Compare commits
	
		
			11 Commits
		
	
	
		
			feature.se
			...
			feature.we
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					cdb8dbafe2 | ||
| 
						 | 
					33b22f95ab | ||
| 
						 | 
					39f77886db | ||
| 
						 | 
					f7470e4a7a | ||
| 
						 | 
					c10c002ee3 | ||
| 
						 | 
					a47ec0df0a | ||
| 
						 | 
					be95050a4b | ||
| 
						 | 
					5043c4e845 | ||
| 
						 | 
					dacbf0707b | ||
| 
						 | 
					34c9d04a35 | ||
| 
						 | 
					aa2868eb17 | 
							
								
								
									
										1
									
								
								AUTHORS
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								AUTHORS
									
									
									
									
									
								
							@@ -33,7 +33,6 @@ Much appreciated contributors (in alphabetical order):
 | 
			
		||||
    Samuel Suther <info@suther.de>                  - German translation
 | 
			
		||||
    Sindre R. Myren <sindrero@stud.ntnu.no>
 | 
			
		||||
    Stewart Platt <stew@futurete.ch>
 | 
			
		||||
    Stéphane Baron <sbaron>
 | 
			
		||||
    Thomas Keller <me@thomaskeller.biz>             - Monotone support
 | 
			
		||||
    Vladimir Solomatin <slash>
 | 
			
		||||
    William Martin <william.martin@lcpc.fr>
 | 
			
		||||
 
 | 
			
		||||
@@ -13,6 +13,7 @@ or newer to properly run this version of Indefero!
 | 
			
		||||
- Display monotone file and directory attributes in the tree and file view
 | 
			
		||||
  (needs a monotone with an interface version of 13.1 or newer)
 | 
			
		||||
- The context area is now kept in view when a page scrolls down several pages
 | 
			
		||||
- git repositories are now available under /r/projectname/
 | 
			
		||||
 | 
			
		||||
## Bugfixes
 | 
			
		||||
 | 
			
		||||
@@ -31,7 +32,6 @@ or newer to properly run this version of Indefero!
 | 
			
		||||
  a new project or monotone key, in case an error popped up in the middle (issue 697)
 | 
			
		||||
- Indefero now sends the MD5 checksum as HTTP header when downloading a file from the
 | 
			
		||||
  download area. Additionally, a unneeded redirect has been removed. (issue 716)
 | 
			
		||||
- Source links without a specific revision did not work due to a wrong regex (issue 730)
 | 
			
		||||
- Better error detection and reporting in the SyncMonotone plugin
 | 
			
		||||
  ATTENTION: This needs Pluf 46b7f251 or newer!
 | 
			
		||||
- Fix the branch links users of the Subversion frontend get when they enter a wrong revision
 | 
			
		||||
@@ -40,7 +40,6 @@ or newer to properly run this version of Indefero!
 | 
			
		||||
  as we have no information what the author string is actually encoded in
 | 
			
		||||
- Indefero no longer displays an empty parents paragraph in the commit view for root revisions of
 | 
			
		||||
  a git repository
 | 
			
		||||
- Indefero now only shows the tags of the closed and not the open issues in the closed issues list
 | 
			
		||||
 | 
			
		||||
## Documentation
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										57
									
								
								doc/httprepos-git.mdtext
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								doc/httprepos-git.mdtext
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,57 @@
 | 
			
		||||
# Accessing git repositories over HTTP
 | 
			
		||||
 | 
			
		||||
Starting with indefero 1.2, git repositories are provided via http,
 | 
			
		||||
featuring read-only and read-write access with full integration with
 | 
			
		||||
indefero's access control mechanisms.
 | 
			
		||||
 | 
			
		||||
## Access git repositories
 | 
			
		||||
 | 
			
		||||
The repositories are available under http://YOURHOST/BASEPATH/r/PROJECT.
 | 
			
		||||
 | 
			
		||||
For authentication, use the "extra password" which you can find on your
 | 
			
		||||
profile page.
 | 
			
		||||
 | 
			
		||||
## Setup
 | 
			
		||||
 | 
			
		||||
The main thing to setup is git_repositories and git_remote_url in
 | 
			
		||||
src/IDF/conf/idf.php
 | 
			
		||||
 | 
			
		||||
git_remote_url should match http://YOURHOST/BASEPATH/r/%s, while
 | 
			
		||||
git_repositories points to the local directory supposed to contain the
 | 
			
		||||
repositories like /PATH/TO/REPOSITORIES/%s.git.
 | 
			
		||||
 | 
			
		||||
## Setup requirements when using PHP over FastCGI
 | 
			
		||||
 | 
			
		||||
There are a couple of things to setup when using PHP over FastCGI, as compared
 | 
			
		||||
to mod_php or similar integrated mechanisms:
 | 
			
		||||
 | 
			
		||||
- You will need to setup a RewriteRule for mod_rewrite (in case of Apache,
 | 
			
		||||
  analogous mechanisms might need to be setup for other http daemons), which
 | 
			
		||||
  passes through the Authorization HTTP Header of a request.
 | 
			
		||||
 | 
			
		||||
  In case of mod_rewrite, the necessary line is
 | 
			
		||||
  one of (depending on server configuration):
 | 
			
		||||
      RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},L]
 | 
			
		||||
      RewriteRule .* - [E=REMOTE_USER:%{HTTP:Authorization},L]
 | 
			
		||||
 | 
			
		||||
- The FastCGI adaptor must allow large requests to be handled by PHP,
 | 
			
		||||
  otherwise push might fail.
 | 
			
		||||
 | 
			
		||||
  For mod_fcgid, this is the FcgidMaxRequestLen option, or MaxRequestLen in
 | 
			
		||||
  older versions. Set this option to some large enough value - there is no
 | 
			
		||||
  issue with RAM use, as another option defines the limit after which the
 | 
			
		||||
  request is backed on disk, which can remain small.
 | 
			
		||||
 | 
			
		||||
## When migrating from syncgit
 | 
			
		||||
 | 
			
		||||
HTTP access can be used in parallel to syncgit.
 | 
			
		||||
 | 
			
		||||
If you want to disable syncgit, just undo the changes detailled
 | 
			
		||||
in doc/syncgit.mdtext:
 | 
			
		||||
- In src/IDF/conf/idf.php keep git_repositories
 | 
			
		||||
- In src/IDF/conf/idf.php adapt git_remote_url to http://host/basepath/r/%s 
 | 
			
		||||
- In src/IDF/conf/idf.php remove idf_plugin_syncgit*
 | 
			
		||||
- Remove the cronjob that called gitcron.php
 | 
			
		||||
- Disable the git daemon (eg. /etc/event.d/local-git-daemon)
 | 
			
		||||
- You can remove the git user and group, if you also adapt the git repositories
 | 
			
		||||
  to be owned by the www user.
 | 
			
		||||
@@ -44,7 +44,7 @@ class IDF_Middleware
 | 
			
		||||
    function process_request(&$request)
 | 
			
		||||
    {
 | 
			
		||||
        $match = array();
 | 
			
		||||
        if (preg_match('#^/(?:api/p|p)/([\-\w]+)/?#', $request->query, $match)) {
 | 
			
		||||
        if (preg_match('#^/(?:api/p|p|r)/([\-\w]+)/?#', $request->query, $match)) {
 | 
			
		||||
            try {
 | 
			
		||||
                $request->project = IDF_Project::getOr404($match[1]);
 | 
			
		||||
            } catch (Pluf_HTTP_Error404 $e) {
 | 
			
		||||
@@ -88,7 +88,6 @@ class IDF_Middleware
 | 
			
		||||
                              'showuser' => 'IDF_Template_ShowUser',
 | 
			
		||||
                              'ashowuser' => 'IDF_Template_AssignShowUser',
 | 
			
		||||
                              'appversion' => 'IDF_Template_AppVersion',
 | 
			
		||||
                              'upload' => 'IDF_Template_Tag_UploadUrl',
 | 
			
		||||
                                            ));
 | 
			
		||||
        $params['modifiers'] = array_merge($params['modifiers'],
 | 
			
		||||
                                           array(
 | 
			
		||||
 
 | 
			
		||||
@@ -132,7 +132,7 @@ class IDF_Project extends Pluf_Model
 | 
			
		||||
        }
 | 
			
		||||
        return $projects[0];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the number of open/closed issues.
 | 
			
		||||
     *
 | 
			
		||||
@@ -167,7 +167,7 @@ GROUP BY uid";
 | 
			
		||||
            $key = ($v['id'] === '-1') ? null : $v['id'];
 | 
			
		||||
            $ownerStatistics[$key] = (int)$v['nb'];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
        arsort($ownerStatistics);
 | 
			
		||||
 | 
			
		||||
        return $ownerStatistics;
 | 
			
		||||
@@ -178,10 +178,9 @@ GROUP BY uid";
 | 
			
		||||
     *
 | 
			
		||||
     * @param string Status ('open'), 'closed'
 | 
			
		||||
     * @param IDF_Tag Subfilter with a label (null)
 | 
			
		||||
     * @param array Restrict further to a list of ids
 | 
			
		||||
     * @return int Count
 | 
			
		||||
     */
 | 
			
		||||
    public function getIssueCountByStatus($status='open', $label=null, $ids=array())
 | 
			
		||||
    public function getIssueCountByStatus($status='open', $label=null)
 | 
			
		||||
    {
 | 
			
		||||
        switch ($status) {
 | 
			
		||||
        case 'open':
 | 
			
		||||
@@ -204,48 +203,12 @@ GROUP BY uid";
 | 
			
		||||
            $sql2 = new Pluf_SQL('idf_tag_id=%s', array($label->id));
 | 
			
		||||
            $sql->SAnd($sql2);
 | 
			
		||||
        }
 | 
			
		||||
        if (count($ids) > 0) {
 | 
			
		||||
            $sql2 = new Pluf_SQL(sprintf('id IN (%s)', implode(', ', $ids)));
 | 
			
		||||
            $sql->SAnd($sql2);
 | 
			
		||||
        }
 | 
			
		||||
        $params = array('filter' => $sql->gen());
 | 
			
		||||
        if (!is_null($label)) { $params['view'] = 'join_tags'; }
 | 
			
		||||
        $gissue = new IDF_Issue();
 | 
			
		||||
        return $gissue->getCount($params);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the tags for a specific list of issues.
 | 
			
		||||
     *
 | 
			
		||||
     * @param string Status ('open') or 'closed'
 | 
			
		||||
     * @param array A list of issue ids
 | 
			
		||||
     * @return array An array of tag objects
 | 
			
		||||
     */
 | 
			
		||||
    public function getTagsByIssues($issue_ids=array())
 | 
			
		||||
    {
 | 
			
		||||
        // make the below query always a valid one
 | 
			
		||||
        if (count($issue_ids) == 0) $issue_ids[] = 0;
 | 
			
		||||
 | 
			
		||||
        $assocTable = $this->_con->pfx.'idf_issue_idf_tag_assoc';
 | 
			
		||||
        $query = sprintf(
 | 
			
		||||
            'SELECT DISTINCT idf_tag_id FROM %s '.
 | 
			
		||||
            'WHERE idf_issue_id IN (%s) '.
 | 
			
		||||
            'GROUP BY idf_tag_id',
 | 
			
		||||
            $assocTable, implode(',', $issue_ids)
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        $db = Pluf::db();
 | 
			
		||||
        $dbData = $db->select($query);
 | 
			
		||||
        $ids = array(0);
 | 
			
		||||
        foreach ($dbData as $data) {
 | 
			
		||||
            $ids[] = $data['idf_tag_id'];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $sql = new Pluf_SQL(sprintf('id IN (%s)', implode(', ', $ids)));
 | 
			
		||||
        $model = new IDF_Tag();
 | 
			
		||||
        return $model->getList(array('filter' => $sql->gen()));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the open/closed tag ids as they are often used when doing
 | 
			
		||||
     * listings.
 | 
			
		||||
@@ -452,11 +415,7 @@ GROUP BY uid";
 | 
			
		||||
        foreach ($this->_con->select($sql) as $idc) {
 | 
			
		||||
            $tag = new IDF_Tag($idc['id']);
 | 
			
		||||
            $tag->nb_use = $idc['nb_use'];
 | 
			
		||||
            // group by class
 | 
			
		||||
            if (!array_key_exists($tag->class, $tags)) {
 | 
			
		||||
                $tags[$tag->class] = array();
 | 
			
		||||
            }
 | 
			
		||||
            $tags[$tag->class][] = $tag;
 | 
			
		||||
            $tags[] = $tag;
 | 
			
		||||
        }
 | 
			
		||||
        return new Pluf_Template_ContextVars($tags);
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -497,5 +497,10 @@ class IDF_Scm
 | 
			
		||||
    {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function repository($request, $match)
 | 
			
		||||
    {
 | 
			
		||||
        throw new Exception('This repository does not support web based repository access');
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -924,4 +924,113 @@ class IDF_Scm_Git extends IDF_Scm
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function repository($request, $match)
 | 
			
		||||
    {
 | 
			
		||||
        // handle a couple of workarounds for authenticating with FastCGI/PHP
 | 
			
		||||
        if (!empty($_SERVER['HTTP_AUTHORIZATION']))
 | 
			
		||||
            list($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']) = explode(':' , base64_decode(substr($_SERVER['HTTP_AUTHORIZATION'], 6)));
 | 
			
		||||
        elseif (!empty($_SERVER['REDIRECT_HTTP_AUTHORIZATION']))
 | 
			
		||||
            list($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']) = explode(':' , base64_decode(substr($_SERVER['REDIRECT_HTTP_AUTHORIZATION'], 6)));
 | 
			
		||||
        elseif (!empty($_SERVER['REDIRECT_REMOTE_USER']))
 | 
			
		||||
            list($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']) = explode(':' , base64_decode(substr($_SERVER['REDIRECT_REMOTE_USER'], 6)));
 | 
			
		||||
 | 
			
		||||
        // authenticate: authenticate connection through "extra" password
 | 
			
		||||
        if (!empty($_SERVER['PHP_AUTH_USER'])) {
 | 
			
		||||
            $sql = new Pluf_SQL('login=%s', array($_SERVER['PHP_AUTH_USER']));
 | 
			
		||||
            $users = Pluf::factory('Pluf_User')->getList(array('filter'=>$sql->gen()));
 | 
			
		||||
            if (count($users) == 1 && $users[0]->active) {
 | 
			
		||||
                $user = $users[0];
 | 
			
		||||
                $realkey = substr(sha1($user->password.Pluf::f('secret_key')), 0, 8);
 | 
			
		||||
                if ($_SERVER['PHP_AUTH_PW'] == $realkey) {
 | 
			
		||||
                    $request->user = $user;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (IDF_Precondition::accessSource($request) !== true) {
 | 
			
		||||
            $response = new Pluf_HTTP_Response("");
 | 
			
		||||
            $response->status_code = 401;
 | 
			
		||||
            $response->headers['WWW-Authenticate']='Basic realm="git for '.$this->project.'"';
 | 
			
		||||
            return $response;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $path = $match[2];
 | 
			
		||||
 
 | 
			
		||||
        if (!file_exists($this->repo)) {
 | 
			
		||||
            mkdir($this->repo, 0750, true);
 | 
			
		||||
            $out = array();
 | 
			
		||||
            $res = 0;
 | 
			
		||||
            exec(sprintf(Pluf::f('idf_exec_cmd_prefix', '').
 | 
			
		||||
                         Pluf::f('git_path', 'git').' --git-dir=%s init', escapeshellarg($this->repo)),
 | 
			
		||||
                 $out, $res);
 | 
			
		||||
            if ($res != 0) {
 | 
			
		||||
                Pluf_Log::error(array('IDF_Scm_Git::repository', $res, $this->repo));
 | 
			
		||||
                throw new Exception(sprintf('Init repository error, exit status %d.', $res));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // update files before delivering them
 | 
			
		||||
        if (($path == 'objects/info/pack') || ($path == 'info/refs')) {
 | 
			
		||||
            $cmd = sprintf(Pluf::f('idf_exec_cmd_prefix', '').
 | 
			
		||||
                       'GIT_DIR=%s '.Pluf::f('git_path', 'git').' update-server-info -f',
 | 
			
		||||
                       escapeshellarg($this->repo));
 | 
			
		||||
            self::shell_exec('IDF_Scm_Git::repository', $cmd);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // smart HTTP discovery
 | 
			
		||||
        if ($path == 'info/refs' && !empty($request->GET['service'])){
 | 
			
		||||
            $service = $request->GET['service'];
 | 
			
		||||
            switch ($service) {
 | 
			
		||||
            case 'git-receive-pack':
 | 
			
		||||
                if (IDF_Precondition::projectMemberOrOwner($request) !== true) {
 | 
			
		||||
                    $response = new Pluf_HTTP_Response("");
 | 
			
		||||
                    $response->status_code = 401;
 | 
			
		||||
                    $response->headers['WWW-Authenticate']='Basic realm="git for '.$this->project.'"';
 | 
			
		||||
                    return $response;
 | 
			
		||||
                }
 | 
			
		||||
            case 'git-upload-pack':
 | 
			
		||||
                $content = sprintf('%04x',strlen($service)+15).
 | 
			
		||||
                         '# service='.$service."\n0000";
 | 
			
		||||
                $content .= self::shell_exec('IDF_Scm_Git::repository',
 | 
			
		||||
                         Pluf::f('idf_exec_cmd_prefix', '').
 | 
			
		||||
                         $service.' --stateless-rpc --advertise-refs '.
 | 
			
		||||
                         $this->repo);
 | 
			
		||||
                $response = new Pluf_HTTP_Response($content,
 | 
			
		||||
                         'application/x-'.$service.'-advertisement');
 | 
			
		||||
                return $response;
 | 
			
		||||
            default:
 | 
			
		||||
                throw new Exception('unknown service: '.$service);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        switch($path) {
 | 
			
		||||
        // smart HTTP RPC
 | 
			
		||||
        case 'git-receive-pack':
 | 
			
		||||
                if (IDF_Precondition::projectMemberOrOwner($request) !== true) {
 | 
			
		||||
                    $response = new Pluf_HTTP_Response("");
 | 
			
		||||
                    $response->status_code = 401;
 | 
			
		||||
                    $response->headers['WWW-Authenticate']='Basic realm="git for '.$this->project.'"';
 | 
			
		||||
                    return $response;
 | 
			
		||||
                }
 | 
			
		||||
        case 'git-upload-pack':
 | 
			
		||||
            $response = new Pluf_HTTP_Response_CommandPassThru(
 | 
			
		||||
                   Pluf::f('idf_exec_cmd_prefix', '').$path.
 | 
			
		||||
                   ' --stateless-rpc '.$this->repo,
 | 
			
		||||
                   'application/x-'.$path.'-result');
 | 
			
		||||
            $response->setStdin(fopen('php://input', 'rb'));
 | 
			
		||||
            return $response;
 | 
			
		||||
 | 
			
		||||
        // regular file
 | 
			
		||||
        default:
 | 
			
		||||
            // make sure we're inside the repo hierarchy (ie. no break-out)
 | 
			
		||||
            if (is_file($this->repo.'/'.$path) &&
 | 
			
		||||
              strpos(realpath($this->repo.'/'.$path), $this->repo.'/') == 0) {
 | 
			
		||||
                return new Pluf_HTTP_Response_File($this->repo.'/'.$path,
 | 
			
		||||
                       'application/octet-stream');
 | 
			
		||||
            } else {
 | 
			
		||||
                return new Pluf_HTTP_Response_NotFound($request);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -58,7 +58,7 @@ class IDF_Template_IssueComment extends Pluf_Template_Tag
 | 
			
		||||
                      implode('|', $nouns);
 | 
			
		||||
            $text = IDF_Template_safePregReplace('#((?:'.$prefix.')(?:\s+r?))([0-9a-f]{1,40}((?:\s+and|\s+or|,)\s+r?[0-9a-f]{1,40})*)\b#i',
 | 
			
		||||
                                                 array($this, 'callbackCommits'), $text);
 | 
			
		||||
            $text = IDF_Template_safePregReplace('=(src:)([^\s@#,\(\)\\\\]+(?:(\\\\)[\s@#][^\s@#,\(\)\\\\]+){0,})+(?:\@([^\s#,]+))?(?:#(\d+))?=im',
 | 
			
		||||
            $text = IDF_Template_safePregReplace('=(src:)([^\s@#,\(\)\\\\]+(?:(\\\\)[\s@#][^\s@#,\(\)\\\\]+){0,})+(?:\@([^\s#,]+))(?:#(\d+))?=im',
 | 
			
		||||
                                                 array($this, 'callbackSource'), $text);
 | 
			
		||||
        }
 | 
			
		||||
        if ($wordwrap) $text = Pluf_Text::wrapHtml($text, 69, "\n");
 | 
			
		||||
 
 | 
			
		||||
@@ -1,35 +0,0 @@
 | 
			
		||||
<?php
 | 
			
		||||
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 | 
			
		||||
/*
 | 
			
		||||
# ***** BEGIN LICENSE BLOCK *****
 | 
			
		||||
# This file is part of InDefero, an open source project management application.
 | 
			
		||||
# Copyright (C) 2011 Céondo Ltd and contributors.
 | 
			
		||||
#
 | 
			
		||||
# InDefero is free software; you can redistribute it and/or modify
 | 
			
		||||
# it under the terms of the GNU General Public License as published by
 | 
			
		||||
# the Free Software Foundation; either version 2 of the License, or
 | 
			
		||||
# (at your option) any later version.
 | 
			
		||||
#
 | 
			
		||||
# InDefero is distributed in the hope that it will be useful,
 | 
			
		||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
# GNU General Public License for more details.
 | 
			
		||||
#
 | 
			
		||||
# You should have received a copy of the GNU General Public License
 | 
			
		||||
# along with this program; if not, write to the Free Software
 | 
			
		||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 | 
			
		||||
#
 | 
			
		||||
# ***** END LICENSE BLOCK ***** */
 | 
			
		||||
 | 
			
		||||
class IDF_Template_Tag_UploadUrl extends Pluf_Template_Tag
 | 
			
		||||
{
 | 
			
		||||
    function start($file='')
 | 
			
		||||
    {
 | 
			
		||||
        echo IDF_Template_Tag_UploadUrl::url($file);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static function url($file='')
 | 
			
		||||
    {
 | 
			
		||||
        return Pluf::f('url_upload', Pluf_Template_Tag_MediaUrl::url() . '/upload') . $file;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -319,11 +319,13 @@ class IDF_Views_Download
 | 
			
		||||
        $pag->no_results_text = __('No downloads were found.');
 | 
			
		||||
        $pag->sort_order = array('creation_dtime', 'DESC');
 | 
			
		||||
        $pag->setFromRequest($request);
 | 
			
		||||
        $tags = $prj->getTagCloud('downloads');
 | 
			
		||||
        return Pluf_Shortcuts_RenderToResponse('idf/downloads/index.html',
 | 
			
		||||
                                               array(
 | 
			
		||||
                                                     'page_title' => $title,
 | 
			
		||||
                                                     'label' => $tag,
 | 
			
		||||
                                                     'downloads' => $pag,
 | 
			
		||||
                                                     'tags' => $tags,
 | 
			
		||||
                                                     'dlabel' => $dtag,
 | 
			
		||||
                                                     ),
 | 
			
		||||
                                               $request);
 | 
			
		||||
 
 | 
			
		||||
@@ -71,9 +71,7 @@ class IDF_Views_Issue
 | 
			
		||||
                        'page_title' => $title,
 | 
			
		||||
                        'open' => $open,
 | 
			
		||||
                        'closed' => $closed,
 | 
			
		||||
                        'issues' => $pag,
 | 
			
		||||
                        'cloud' => 'issues',
 | 
			
		||||
                );
 | 
			
		||||
                        'issues' => $pag);
 | 
			
		||||
        if ($api) return $params;
 | 
			
		||||
        return Pluf_Shortcuts_RenderToResponse('idf/issues/index.html',
 | 
			
		||||
                                               $params, $request);
 | 
			
		||||
@@ -90,7 +88,7 @@ class IDF_Views_Issue
 | 
			
		||||
        $ownerStatistics = array();
 | 
			
		||||
        $status = array();
 | 
			
		||||
        $isTrackerEmpty = false;
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
        $prj = $request->project;
 | 
			
		||||
        $opened = $prj->getIssueCountByStatus('open');
 | 
			
		||||
        $closed = $prj->getIssueCountByStatus('closed');
 | 
			
		||||
@@ -104,7 +102,7 @@ class IDF_Views_Issue
 | 
			
		||||
                $status['Open'] = array($opened, (int)(100 * $opened / ($opened + $closed)));
 | 
			
		||||
                $status['Closed'] = array($closed, (int)(100 * $closed / ($opened + $closed)));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            
 | 
			
		||||
            if ($opened > 0) {
 | 
			
		||||
                // Issue owner statistics
 | 
			
		||||
                $owners = $prj->getIssueCountByOwner('open');
 | 
			
		||||
@@ -119,11 +117,9 @@ class IDF_Views_Issue
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Issue class tag statistics
 | 
			
		||||
                $grouped_tags = $prj->getTagCloud();
 | 
			
		||||
                foreach ($grouped_tags as $class => $tags) {
 | 
			
		||||
                    foreach ($tags as $tag) {
 | 
			
		||||
                        $tagStatistics[$class][$tag->name] = array($tag->nb_use, $tag->id);
 | 
			
		||||
                    }
 | 
			
		||||
                $tags = $prj->getTagCloud();
 | 
			
		||||
                foreach ($tags as $t) {
 | 
			
		||||
                    $tagStatistics[$t->class][$t->name] = array($t->nb_use, $t->id);
 | 
			
		||||
                }
 | 
			
		||||
                foreach($tagStatistics as $k => $v) {
 | 
			
		||||
                    $nbIssueInClass = 0;
 | 
			
		||||
@@ -134,15 +130,15 @@ class IDF_Views_Issue
 | 
			
		||||
                        $tagStatistics[$k][$kk] = array($vv[0], (int)(100 * $vv[0] / $nbIssueInClass), $vv[1]);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                
 | 
			
		||||
                // Sort
 | 
			
		||||
                krsort($tagStatistics);
 | 
			
		||||
                arsort($ownerStatistics);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
        $title = sprintf(__('Summary of tracked issues in %s.'), (string) $prj);
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
        return Pluf_Shortcuts_RenderToResponse('idf/issues/summary.html',
 | 
			
		||||
                                               array('page_title' => $title,
 | 
			
		||||
                                                     'trackerEmpty' => $isTrackerEmpty,
 | 
			
		||||
@@ -153,7 +149,7 @@ class IDF_Views_Issue
 | 
			
		||||
                                                     ),
 | 
			
		||||
                                               $request);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * View the issues watch list of a given user.
 | 
			
		||||
     * Limited to a specified project
 | 
			
		||||
@@ -433,142 +429,45 @@ class IDF_Views_Issue
 | 
			
		||||
 | 
			
		||||
    public $search_precond = array('IDF_Precondition::accessIssues');
 | 
			
		||||
    public function search($request, $match)
 | 
			
		||||
    {
 | 
			
		||||
        $query = !isset($request->REQUEST['q']) ? '' : $request->REQUEST['q'];
 | 
			
		||||
        return $this->doSearch($request, $query, 'open');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public $searchStatus_precond = array('IDF_Precondition::accessIssues');
 | 
			
		||||
    public function searchStatus($request, $match)
 | 
			
		||||
    {
 | 
			
		||||
        $query  = !isset($request->REQUEST['q']) ? '' : $request->REQUEST['q'];
 | 
			
		||||
        $status = in_array($match[2], array('open', 'closed')) ? $match[2] : 'open';
 | 
			
		||||
        return $this->doSearch($request, $query, $status);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public $searchLabel_precond = array('IDF_Precondition::accessIssues');
 | 
			
		||||
    public function searchLabel($request, $match)
 | 
			
		||||
    {
 | 
			
		||||
        $query  = !isset($request->REQUEST['q']) ? '' : $request->REQUEST['q'];
 | 
			
		||||
        $tag_id = intval($match[2]);
 | 
			
		||||
        $status = in_array($match[3], array('open', 'closed')) ? $match[3] : 'open';
 | 
			
		||||
        return $this->doSearch($request, $query, $status, $tag_id);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function doSearch($request, $query, $status, $tag_id=null)
 | 
			
		||||
    {
 | 
			
		||||
        $prj = $request->project;
 | 
			
		||||
        if (trim($query) == '') {
 | 
			
		||||
            $url =  Pluf_HTTP_URL_urlForView('IDF_Views_Issue::index', array($prj->shortname));
 | 
			
		||||
        if (!isset($request->REQUEST['q']) or trim($request->REQUEST['q']) == '') {
 | 
			
		||||
            $url =  Pluf_HTTP_URL_urlForView('IDF_Views_Issue::index',
 | 
			
		||||
                                             array($prj->shortname));
 | 
			
		||||
            return new Pluf_HTTP_Response_Redirect($url);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $tag = null;
 | 
			
		||||
        if ($tag_id !== null) {
 | 
			
		||||
            $tag = Pluf_Shortcuts_GetObjectOr404('IDF_Tag', $tag_id);
 | 
			
		||||
        $q = $request->REQUEST['q'];
 | 
			
		||||
        $title = sprintf(__('Search Issues - %s'), $q);
 | 
			
		||||
        $issues = new Pluf_Search_ResultSet(IDF_Search::mySearch($q, $prj, 'IDF_Issue'));
 | 
			
		||||
        if (count($issues) > 100) {
 | 
			
		||||
            // no more than 100 results as we do not care
 | 
			
		||||
            $issues->results = array_slice($issues->results, 0, 100);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $title = sprintf(__('Search issues - %s'), $query);
 | 
			
		||||
        if ($status === 'closed') {
 | 
			
		||||
            $title = sprintf(__('Search closed issues - %s'), $query);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // using Plufs ResultSet implementation here is inefficient, because
 | 
			
		||||
        // it makes a SELECT for each item and does not allow for further
 | 
			
		||||
        // filtering neither, so we just return the ids and filter by them
 | 
			
		||||
        // and other things in the next round
 | 
			
		||||
        $results = IDF_Search::mySearch($query, $prj, 'IDF_Issue');
 | 
			
		||||
 | 
			
		||||
        $issue_ids = array(0);
 | 
			
		||||
        foreach ($results as $result) {
 | 
			
		||||
            $issue_ids[] = $result['model_id'];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $otags = $prj->getTagIdsByStatus($status);
 | 
			
		||||
        if (count($otags) == 0) $otags[] = 0;
 | 
			
		||||
        $sql = new Pluf_SQL(
 | 
			
		||||
            'id IN ('.implode(',', $issue_ids).') '.
 | 
			
		||||
            'AND status IN ('.implode(', ', $otags).') '.
 | 
			
		||||
            ($tag_id !== null ? 'AND idf_tag_id='.$tag_id.' ' : '')
 | 
			
		||||
        );
 | 
			
		||||
        $model = new IDF_Issue();
 | 
			
		||||
        $issues = $model->getList(array('filter' => $sql->gen(), 'view' => 'join_tags'));
 | 
			
		||||
 | 
			
		||||
        // we unfortunately loose the original sort order,
 | 
			
		||||
        // so we manually have to apply it here again
 | 
			
		||||
        $sorted_issues = new ArrayObject();
 | 
			
		||||
        $filtered_issue_ids = array(0);
 | 
			
		||||
        foreach ($issue_ids as $issue_id) {
 | 
			
		||||
            foreach ($issues as $issue) {
 | 
			
		||||
                if ($issue->id != $issue_id)
 | 
			
		||||
                    continue;
 | 
			
		||||
                if (array_key_exists($issue_id, $sorted_issues))
 | 
			
		||||
                    continue;
 | 
			
		||||
                $sorted_issues[$issue_id] = $issue;
 | 
			
		||||
                $filtered_issue_ids[] = $issue_id;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $pag = new Pluf_Paginator();
 | 
			
		||||
        $pag->items = $issues;
 | 
			
		||||
        $pag->class = 'recent-issues';
 | 
			
		||||
        $pag->items = $sorted_issues;
 | 
			
		||||
        $pag->item_extra_props = array(
 | 
			
		||||
            'project_m' => $prj,
 | 
			
		||||
            'shortname' => $prj->shortname,
 | 
			
		||||
            'current_user' => $request->user
 | 
			
		||||
        );
 | 
			
		||||
        $pag->item_extra_props = array('project_m' => $prj,
 | 
			
		||||
                                       'shortname' => $prj->shortname,
 | 
			
		||||
                                       'current_user' => $request->user);
 | 
			
		||||
        $pag->summary = __('This table shows the found issues.');
 | 
			
		||||
        $pag->action = array('IDF_Views_Issue::search', array($prj->shortname), array('q'=> $q));
 | 
			
		||||
        $pag->extra_classes = array('a-c', '', 'a-c', '');
 | 
			
		||||
        $pag->configure(array(
 | 
			
		||||
            'id' => __('Id'),
 | 
			
		||||
            array('summary', 'IDF_Views_Issue_SummaryAndLabels', __('Summary')),
 | 
			
		||||
            array('status', 'IDF_Views_Issue_ShowStatus', __('Status')),
 | 
			
		||||
            array('modif_dtime', 'Pluf_Paginator_DateAgo', __('Last Updated')),
 | 
			
		||||
        ));
 | 
			
		||||
        // disable paginating
 | 
			
		||||
        $pag->items_per_page = PHP_INT_MAX;
 | 
			
		||||
        $list_display = array(
 | 
			
		||||
                              'id' => __('Id'),
 | 
			
		||||
                              array('summary', 'IDF_Views_Issue_SummaryAndLabels', __('Summary')),
 | 
			
		||||
                              array('status', 'IDF_Views_Issue_ShowStatus', __('Status')),
 | 
			
		||||
                              array('modif_dtime', 'Pluf_Paginator_DateAgo', __('Last Updated')),
 | 
			
		||||
                              );
 | 
			
		||||
        $pag->configure($list_display);
 | 
			
		||||
        $pag->items_per_page = 100;
 | 
			
		||||
        $pag->no_results_text = __('No issues were found.');
 | 
			
		||||
        $pag->setFromRequest($request);
 | 
			
		||||
 | 
			
		||||
        if ($tag_id === null) {
 | 
			
		||||
            $pag->action = array('IDF_Views_Issue::searchStatus',
 | 
			
		||||
                array($prj->shortname, $status),
 | 
			
		||||
                array('q'=> $query),
 | 
			
		||||
            );
 | 
			
		||||
        } else {
 | 
			
		||||
            $pag->action = array('IDF_Views_Issue::searchLabel',
 | 
			
		||||
                array($prj->shortname, $tag_id, $status),
 | 
			
		||||
                array('q'=> $query),
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // get stats about the issues
 | 
			
		||||
        $open = $prj->getIssueCountByStatus('open', $tag, $issue_ids);
 | 
			
		||||
        $closed = $prj->getIssueCountByStatus('closed', $tag, $issue_ids);
 | 
			
		||||
 | 
			
		||||
        // query the available tags for this search result
 | 
			
		||||
        $all_tags = $prj->getTagsByIssues($filtered_issue_ids);
 | 
			
		||||
        $grouped_tags = array();
 | 
			
		||||
        foreach ($all_tags as $atag) {
 | 
			
		||||
            // group by class
 | 
			
		||||
            if (!array_key_exists($atag->class, $grouped_tags)) {
 | 
			
		||||
                $grouped_tags[$atag->class] = array();
 | 
			
		||||
            }
 | 
			
		||||
            $grouped_tags[$atag->class][] = $atag;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $params = array(
 | 
			
		||||
            'page_title' => $title,
 | 
			
		||||
            'issues' => $pag,
 | 
			
		||||
            'query' => $query,
 | 
			
		||||
            'status' => $status,
 | 
			
		||||
            'open' => $open,
 | 
			
		||||
            'closed' => $closed,
 | 
			
		||||
            'tag' => $tag,
 | 
			
		||||
            'all_tags' => $grouped_tags,
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        $params = array('page_title' => $title,
 | 
			
		||||
                        'issues' => $pag,
 | 
			
		||||
                        'q' => $q,
 | 
			
		||||
                        );
 | 
			
		||||
        return Pluf_Shortcuts_RenderToResponse('idf/issues/search.html', $params, $request);
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public $view_precond = array('IDF_Precondition::accessIssues');
 | 
			
		||||
 
 | 
			
		||||
@@ -132,6 +132,12 @@ class IDF_Views_Source
 | 
			
		||||
                                               $request);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function repository($request, $match)
 | 
			
		||||
    {
 | 
			
		||||
        $scm = IDF_Scm::get($request->project);
 | 
			
		||||
        return $scm->repository($request, $match);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public $treeBase_precond = array('IDF_Precondition::accessSource',
 | 
			
		||||
                                     'IDF_Views_Source_Precondition::scmAvailable',
 | 
			
		||||
                                     'IDF_Views_Source_Precondition::revisionValid');
 | 
			
		||||
 
 | 
			
		||||
@@ -152,11 +152,13 @@ class IDF_Views_Wiki
 | 
			
		||||
        $pag->items_per_page = 25;
 | 
			
		||||
        $pag->no_results_text = __('No documentation pages were found.');
 | 
			
		||||
        $pag->setFromRequest($request);
 | 
			
		||||
        $tags = $prj->getTagCloud('wiki');
 | 
			
		||||
        return Pluf_Shortcuts_RenderToResponse('idf/wiki/index.html',
 | 
			
		||||
                                               array(
 | 
			
		||||
                                                     'page_title' => $title,
 | 
			
		||||
                                                     'label' => $tag,
 | 
			
		||||
                                                     'pages' => $pag,
 | 
			
		||||
                                                     'tags' => $tags,
 | 
			
		||||
                                                     'dlabel' => $dtag,
 | 
			
		||||
                                                     ),
 | 
			
		||||
                                               $request);
 | 
			
		||||
 
 | 
			
		||||
@@ -117,7 +117,7 @@ $ctl[] = array('regex' => '#^/p/([\-\w]+)/issues/$#',
 | 
			
		||||
               'base' => $base,
 | 
			
		||||
               'model' => 'IDF_Views_Issue',
 | 
			
		||||
               'method' => 'index');
 | 
			
		||||
 | 
			
		||||
               
 | 
			
		||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/issues/summary/$#',
 | 
			
		||||
               'base' => $base,
 | 
			
		||||
               'model' => 'IDF_Views_Issue',
 | 
			
		||||
@@ -128,16 +128,6 @@ $ctl[] = array('regex' => '#^/p/([\-\w]+)/issues/search/$#',
 | 
			
		||||
               'model' => 'IDF_Views_Issue',
 | 
			
		||||
               'method' => 'search');
 | 
			
		||||
 | 
			
		||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/issues/search/status/(\w+)/$#',
 | 
			
		||||
               'base' => $base,
 | 
			
		||||
               'model' => 'IDF_Views_Issue',
 | 
			
		||||
               'method' => 'searchStatus');
 | 
			
		||||
 | 
			
		||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/issues/search/label/(\d+)/(\w+)/$#',
 | 
			
		||||
               'base' => $base,
 | 
			
		||||
               'model' => 'IDF_Views_Issue',
 | 
			
		||||
               'method' => 'searchLabel');
 | 
			
		||||
 | 
			
		||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/issues/(\d+)/$#',
 | 
			
		||||
               'base' => $base,
 | 
			
		||||
               'model' => 'IDF_Views_Issue',
 | 
			
		||||
@@ -255,6 +245,11 @@ $ctl[] = array('regex' => '#^/p/([\-\w]+)/source/changesrev/$#',
 | 
			
		||||
               'model' => 'IDF_Views_Source_Svn',
 | 
			
		||||
               'method' => 'changelogRev');
 | 
			
		||||
 | 
			
		||||
$ctl[] = array('regex' => '#^/r/([\-\w]+)/(.*)$#',
 | 
			
		||||
               'base' => $base,
 | 
			
		||||
               'model' => 'IDF_Views_Source',
 | 
			
		||||
               'method' => 'repository');
 | 
			
		||||
 | 
			
		||||
// ---------- WIKI -----------------------------------------
 | 
			
		||||
 | 
			
		||||
$ctl[] = array('regex' => '#^/p/([\-\w]+)/doc/$#',
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,7 @@
 | 
			
		||||
{if !$user.isAnonymous()} | <a {if $inCreate}class="active" {/if}href="{url 'IDF_Views_Issue::create', array($project.shortname)}">{trans 'New Issue'}</a> | <a {if $inMyIssues}class="active" {/if}href="{url 'IDF_Views_Issue::myIssues', array($project.shortname, 'submit')}">{trans 'My Issues'}</a>
 | 
			
		||||
| <a {if $inWatchList}class="active" {/if}href="{url 'IDF_Views_Issue::watchList', array($project.shortname, 'open')}">{trans 'My watch list'}</a>{/if} |
 | 
			
		||||
<form class="star" action="{url 'IDF_Views_Issue::search', array($project.shortname)}" method="get">
 | 
			
		||||
<input accesskey="4" type="text" value="{$query}" name="q" size="20" />
 | 
			
		||||
<input accesskey="4" type="text" value="{$q}" name="q" size="20" />
 | 
			
		||||
<input type="submit" name="s" value="{trans 'Search'}" />
 | 
			
		||||
</form>
 | 
			
		||||
{if $inIssue} |
 | 
			
		||||
 
 | 
			
		||||
@@ -8,15 +8,16 @@
 | 
			
		||||
 | 
			
		||||
{/block}
 | 
			
		||||
{block context}
 | 
			
		||||
<p><strong>{trans 'Label:'}</strong>
 | 
			
		||||
{aurl 'url', 'IDF_Views_Issue::listLabel', array($project.shortname, $label.id, 'open')}
 | 
			
		||||
<a href="{$url}" class="label"><strong>{$label.class}:</strong>{$label.name}</a></p>
 | 
			
		||||
{aurl 'open_url', 'IDF_Views_Issue::listLabel', array($project.shortname, $label.id, 'open')}
 | 
			
		||||
{aurl 'closed_url', 'IDF_Views_Issue::listLabel', array($project.shortname, $label.id, 'closed')}
 | 
			
		||||
{blocktrans}<p><strong>Open issues:</strong> <a href="{$open_url}">{$open}</a></p>
 | 
			
		||||
<p><strong>Closed issues:</strong> <a href="{$closed_url}">{$closed}</a></p>
 | 
			
		||||
{/blocktrans}
 | 
			
		||||
<p><strong>{trans 'Label:'}</strong>
 | 
			
		||||
{aurl 'url', 'IDF_Views_Issue::listLabel', array($project.shortname, $label.id, 'open')}
 | 
			
		||||
<a href="{$url}" class="label"><strong>{$label.class}:</strong>{$label.name}</a></p>
 | 
			
		||||
{if $completion}
 | 
			
		||||
{/blocktrans}{if $completion}
 | 
			
		||||
<p><strong>{trans 'Completion:'}</strong> {$completion}</p>
 | 
			
		||||
{/if}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
{/block}
 | 
			
		||||
 
 | 
			
		||||
@@ -13,5 +13,6 @@
 | 
			
		||||
{blocktrans}<p><strong>Open issues:</strong> <a href="{$open_url}">{$open}</a></p>
 | 
			
		||||
<p><strong>Closed issues:</strong> <a href="{$closed_url}">{$closed}</a></p>{/blocktrans}
 | 
			
		||||
{assign $cloud_url = 'IDF_Views_Issue::listLabel'}
 | 
			
		||||
{assign $cloud = 'issues'}
 | 
			
		||||
{include 'idf/tags-cloud.html'}
 | 
			
		||||
{/block}
 | 
			
		||||
 
 | 
			
		||||
@@ -8,25 +8,5 @@
 | 
			
		||||
 | 
			
		||||
{/block}
 | 
			
		||||
{block context}
 | 
			
		||||
{aurl 'open_url',   'IDF_Views_Issue::searchStatus', array($project.shortname, 'open'),   array('q' => $query)}
 | 
			
		||||
{aurl 'closed_url', 'IDF_Views_Issue::searchStatus', array($project.shortname, 'closed'), array('q' => $query)}
 | 
			
		||||
{if $tag != null}
 | 
			
		||||
{aurl 'open_url',   'IDF_Views_Issue::searchLabel', array($project.shortname, $tag.id, 'open'),   array('q' => $query)}
 | 
			
		||||
{aurl 'closed_url', 'IDF_Views_Issue::searchLabel', array($project.shortname, $tag.id, 'closed'), array('q' => $query)}
 | 
			
		||||
{/if}
 | 
			
		||||
{blocktrans}
 | 
			
		||||
<p><strong>Found open issues:</strong> <a href="{$open_url}">{$open}</a></p>
 | 
			
		||||
<p><strong>Found closed issues:</strong> <a href="{$closed_url}">{$closed}</a></p>{/blocktrans}
 | 
			
		||||
{if $tag !== null}
 | 
			
		||||
{blocktrans}<p><strong>Label:</strong>
 | 
			
		||||
<a href="{$open_url}" class="label"><strong>{$tag.class}:</strong>{$tag.name}</a></p>{/blocktrans}
 | 
			
		||||
{else}
 | 
			
		||||
{* yes, this is duplicated from tags-cloud.html, but the code there cannot be easily overridden *}
 | 
			
		||||
<div id="tagscloud" class="smaller"><dl>{foreach $all_tags as $class => $labels}
 | 
			
		||||
<dt class="label">{$class}</dt>
 | 
			
		||||
{foreach $labels as $idx => $label}
 | 
			
		||||
{aurl 'url', 'IDF_Views_Issue::searchLabel', array($project.shortname, $label.id, $status), array('q'=> $query)}
 | 
			
		||||
<dd><a href="{$url}" class="label">{$label.name}{if $idx != count($labels) - 1},{/if}</a></dd>
 | 
			
		||||
{/foreach}{/foreach}</dl></p>
 | 
			
		||||
{/if}
 | 
			
		||||
<p><strong>{trans 'Found issues:'}</strong> {$issues.nb_items}</p>
 | 
			
		||||
{/block}
 | 
			
		||||
 
 | 
			
		||||
@@ -17,7 +17,7 @@
 | 
			
		||||
{assign $submitter_data = $c.get_submitter_data()}
 | 
			
		||||
<div class="issue-comment{if $i == 0} issue-comment-first{/if}{if $i == ($nc-1)} issue-comment-last{/if}" id="ic{$c.id}">
 | 
			
		||||
{if $submitter_data.avatar != ''}
 | 
			
		||||
<img style="float:right; position: relative; max-height: 60px; max-width: 60px;" src="{upload}/avatars/{$submitter_data.avatar}" alt=" " />
 | 
			
		||||
<img style="float:right; position: relative; max-height: 60px; max-width: 60px;" src="{media}/upload/avatars/{$submitter_data.avatar}" alt=" " />
 | 
			
		||||
{else}
 | 
			
		||||
<img style="float:right; position: relative; max-height: 60px; max-width: 60px;" src="http://www.gravatar.com/avatar/{$submitter.email|md5}.jpg?s=60&d={media}/idf/img/spacer.gif" alt=" " />
 | 
			
		||||
{/if}
 | 
			
		||||
 
 | 
			
		||||
@@ -5,4 +5,17 @@
 | 
			
		||||
{if !$user.isAnonymous()}
 | 
			
		||||
{aurl 'url', 'IDF_Views_Review::create', array($project.shortname)}
 | 
			
		||||
<p><a href="{$url}"><img style="vertical-align: text-bottom;" src="{media '/idf/img/add.png'}" alt="+" align="bottom" /></a> <a href="{$url}">{trans 'Start Code Review'}</a></p>{/if}
 | 
			
		||||
 | 
			
		||||
{/block}
 | 
			
		||||
{block context}
 | 
			
		||||
{*
 | 
			
		||||
{aurl 'open_url', 'IDF_Views_Issue::index', array($project.shortname)}
 | 
			
		||||
{aurl 'closed_url', 'IDF_Views_Issue::listStatus', array($project.shortname, 'closed')}
 | 
			
		||||
{blocktrans}<p><strong>Open issues:</strong> <a href="{$open_url}">{$open}</a></p>
 | 
			
		||||
<p><strong>Closed issues:</strong> <a href="{$closed_url}">{$closed}</a></p>{/blocktrans}
 | 
			
		||||
{assign $class = ''}{assign $i = 0}
 | 
			
		||||
<p class="smaller">{foreach $project.getTagCloud($cloud) as $label}
 | 
			
		||||
{aurl 'url', 'IDF_Views_Issue::listLabel', array($project.shortname, $label.id, 'open')}
 | 
			
		||||
{if $class != $label.class}{if $i != 0}<br />{/if}<strong class="label">{$label.class}:</strong> {/if}
 | 
			
		||||
<a href="{$url}" class="label">{$label.name}</a>,{assign $class = $label.class}{assign $i = $i + 1}{/foreach}</p>
 | 
			
		||||
*}{/block}
 | 
			
		||||
 
 | 
			
		||||
@@ -109,7 +109,7 @@ to propose more contributions</strong>.
 | 
			
		||||
{foreach $comments as $c}{ashowuser 'submitter', $c.get_submitter(), $request}{assign $submitter = $c.get_submitter()}{assign $submitter_data = $c.get_submitter_data()}
 | 
			
		||||
<div class="issue-comment{if $i == 1} issue-comment-first{/if}{if $i == ($nc)} issue-comment-last{/if}" id="ic{$c.id}">
 | 
			
		||||
{if $submitter_data.avatar != ''}
 | 
			
		||||
    <img style="float:right; position: relative; max-height: 60px; max-width: 60px;" src="{upload}/avatars/{$submitter_data.avatar}" alt=" " />
 | 
			
		||||
    <img style="float:right; position: relative; max-height: 60px; max-width: 60px;" src="{media}/upload/avatars/{$submitter_data.avatar}" alt=" " />
 | 
			
		||||
{else}
 | 
			
		||||
    <img style="float:right; position: relative;" src="http://www.gravatar.com/avatar/{$submitter.email|md5}.jpg?s=60&d={media}/idf/img/spacer.gif" alt=" " />
 | 
			
		||||
{/if}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,8 @@
 | 
			
		||||
<div id="tagscloud" class="smaller"><dl>{foreach $project.getTagCloud($cloud) as $class => $labels}
 | 
			
		||||
<dt class="label">{$class}</dt>
 | 
			
		||||
{foreach $labels as $idx => $label}
 | 
			
		||||
{assign $class = ''}{assign $i = 0}
 | 
			
		||||
<div id="tagscloud" class="smaller"><dl>{foreach $project.getTagCloud($cloud) as $label}
 | 
			
		||||
{aurl 'url', $cloud_url, array($project.shortname, $label.id, 'open')}
 | 
			
		||||
<dd><a href="{$url}" class="label">{$label.name}{if $idx != count($labels) - 1},{/if}</a></dd>
 | 
			
		||||
{/foreach}{/foreach}</dl></p>
 | 
			
		||||
{if $class != $label.class}<dt class="label">{$label.class}</dt>{assign $i = 0}{/if}
 | 
			
		||||
<dd><a href="{$url}" class="label">{$label.name},</a></dd>
 | 
			
		||||
{assign $class = $label.class}
 | 
			
		||||
{assign $i = $i + 1}
 | 
			
		||||
{/foreach}</dl></p>
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,7 @@
 | 
			
		||||
<table class="form" summary="">
 | 
			
		||||
<tr>
 | 
			
		||||
<th style="text-align: right">{if $user_data.avatar != ''}
 | 
			
		||||
    <img style="max-height: 60px; max-width: 60px;" src="{upload}/avatars/{$user_data.avatar}" alt=" " />
 | 
			
		||||
    <img style="max-height: 60px; max-width: 60px;" src="{media}/upload/avatars/{$user_data.avatar}" alt=" " />
 | 
			
		||||
{else}
 | 
			
		||||
    <img src="http://www.gravatar.com/avatar/{$member.email|md5}.jpg?s=60&d={media}/idf/img/spacer.gif" alt=" " />
 | 
			
		||||
{/if}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user