* code for task #6708.

This commit is contained in:
wangyidong
2019-12-10 13:55:01 +08:00
parent 0c8fd46f7b
commit 6630dd0bb7
40 changed files with 4988 additions and 12 deletions
+14
View File
@@ -45,6 +45,7 @@ $filter->mail = new stdclass();
$filter->user = new stdclass();
$filter->block = new stdclass();
$filter->file = new stdclass();
$filter->repo = new stdclass();
$filter->block->default = new stdclass();
$filter->block->main = new stdclass();
@@ -212,3 +213,16 @@ $filter->git->cat->get['repoUrl'] = 'reg::base64';
$filter->git->diff->get['repoUrl'] = 'reg::base64';
$filter->svn->cat->get['repoUrl'] = 'reg::base64';
$filter->svn->diff->get['repoUrl'] = 'reg::base64';
$filter->repo->default = new stdclass();
$filter->repo->diff = new stdclass();
$filter->repo->view = new stdclass();
$filter->repo->default->get['path'] = 'reg::base64';
$filter->repo->default->get['entry'] = 'reg::base64';
$filter->repo->default->cookie['repoBranch'] = 'reg::any';
$filter->repo->diff->cookie['arrange'] = 'reg::word';
$filter->repo->diff->cookie['repoPairs'] = 'array';
$filter->repo->view->cookie['repoPairs'] = 'array';
$filter->repo->ajaxsynccomment->cookie['syncBranch'] = 'reg::any';
+11 -6
View File
@@ -163,12 +163,17 @@ define('TABLE_TESTSUITE', '`' . $config->db->prefix . 'testsuite`');
define('TABLE_SUITECASE', '`' . $config->db->prefix . 'suitecase`');
define('TABLE_TESTREPORT', '`' . $config->db->prefix . 'testreport`');
define('TABLE_ENTRY', '`' . $config->db->prefix . 'entry`');
define('TABLE_WEBHOOK', '`' . $config->db->prefix . 'webhook`');
define('TABLE_LOG', '`' . $config->db->prefix . 'log`');
define('TABLE_SCORE', '`' . $config->db->prefix . 'score`');
define('TABLE_NOTIFY', '`' . $config->db->prefix . 'notify`');
define('TABLE_OAUTH', '`' . $config->db->prefix . 'oauth`');
define('TABLE_ENTRY', '`' . $config->db->prefix . 'entry`');
define('TABLE_WEBHOOK', '`' . $config->db->prefix . 'webhook`');
define('TABLE_LOG', '`' . $config->db->prefix . 'log`');
define('TABLE_SCORE', '`' . $config->db->prefix . 'score`');
define('TABLE_NOTIFY', '`' . $config->db->prefix . 'notify`');
define('TABLE_OAUTH', '`' . $config->db->prefix . 'oauth`');
define('TABLE_REPO', '`' . $config->db->prefix . 'repo`');
define('TABLE_REPOHISTORY', '`' . $config->db->prefix . 'repohistory`');
define('TABLE_REPOFILES', '`' . $config->db->prefix . 'repofiles`');
define('TABLE_REPOBRANCH', '`' . $config->db->prefix . 'repobranch`');
if(!defined('TABLE_LANG')) define('TABLE_LANG', '`' . $config->db->prefix . 'lang`');
$config->objectTables['product'] = TABLE_PRODUCT;
+66
View File
@@ -0,0 +1,66 @@
-- DROP TABLE IF EXISTS `zt_repo`;
CREATE TABLE IF NOT EXISTS `zt_repo` (
`id` mediumint(9) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`path` varchar(255) NOT NULL,
`prefix` varchar(100) NOT NULL,
`encoding` varchar(20) NOT NULL,
`SCM` varchar(10) NOT NULL,
`client` varchar(100) NOT NULL,
`commits` mediumint(8) unsigned NOT NULL,
`account` varchar(30) NOT NULL,
`password` varchar(30) NOT NULL,
`encrypt` varchar(30) NOT NULL DEFAULT 'plain',
`acl` text NOT NULL,
`synced` tinyint(1) NOT NULL DEFAULT '0',
`lastSync` datetime NOT NULL,
`deleted` tinyint(1) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- DROP TABLE IF EXISTS `zt_repobranch`;
CREATE TABLE IF NOT EXISTS `zt_repobranch` (
`repo` mediumint(8) unsigned NOT NULL,
`revision` mediumint(8) unsigned NOT NULL,
`branch` varchar(255) NOT NULL,
UNIQUE KEY `repo_revision_branch` (`repo`,`revision`,`branch`),
KEY `branch` (`branch`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- DROP TABLE IF EXISTS `zt_repohistory`;
CREATE TABLE IF NOT EXISTS `zt_repohistory` (
`id` mediumint(9) NOT NULL AUTO_INCREMENT,
`repo` mediumint(9) NOT NULL,
`revision` varchar(40) NOT NULL,
`commit` mediumint(8) unsigned NOT NULL,
`comment` text NOT NULL,
`committer` varchar(100) NOT NULL,
`time` datetime NOT NULL,
PRIMARY KEY (`id`),
KEY `repo` (`repo`),
KEY `revision` (`revision`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- DROP TABLE IF EXISTS `zt_repofiles`;
CREATE TABLE IF NOT EXISTS `zt_repofiles` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`repo` mediumint(8) unsigned NOT NULL,
`revision` mediumint(8) unsigned NOT NULL,
`path` varchar(255) NOT NULL,
`parent` varchar(255) NOT NULL,
`type` varchar(20) NOT NULL,
`action` char(1) NOT NULL,
PRIMARY KEY (`id`),
KEY `path` (`path`),
KEY `parent` (`parent`),
KEY `repo` (`repo`),
KEY `revision` (`revision`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
ALTER TABLE `zt_bug` CHANGE `caseVersion` `caseVersion` smallint(6) NOT NULL AFTER `case`;
ALTER TABLE `zt_bug` ADD `repo` mediumint(8) unsigned NOT NULL AFTER `result`;
ALTER TABLE `zt_bug` ADD `lines` varchar(10) COLLATE 'utf8_general_ci' NOT NULL AFTER `repo`;
ALTER TABLE `zt_bug` ADD `v1` varchar(40) COLLATE 'utf8_general_ci' NOT NULL AFTER `lines`;
ALTER TABLE `zt_bug` ADD `v2` varchar(40) COLLATE 'utf8_general_ci' NOT NULL AFTER `v1`;
ALTER TABLE `zt_bug` ADD `repoType` varchar(30) COLLATE 'utf8_general_ci' NOT NULL DEFAULT '' AFTER `v2`;
ALTER TABLE `zt_bug` ADD `entry` varchar(255) COLLATE 'utf8_general_ci' NOT NULL AFTER `repo`;
+1 -1
View File
@@ -2273,7 +2273,7 @@ class baseRouter
* 为了安全起见,对公网环境隐藏脚本路径。
* If the ip is pulic, hidden the full path of scripts.
*/
$remoteIP = helper::getRemoteIp();
$remoteIP = zget($_SERVER, "REMOTE_ADDR", '');
if(!defined('IN_SHELL') and !($remoteIP == '127.0.0.1' or filter_var($remoteIP, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE) === false))
{
$errorLog = str_replace($this->getBasePath(), '', $errorLog);
+3
View File
@@ -0,0 +1,3 @@
<?php
$config = new stdclass();
$config->debug = false;
+455
View File
@@ -0,0 +1,455 @@
<?php
class Git
{
public $client;
public $root;
public function __construct($client, $root, $username, $password, $encoding = 'UTF-8')
{
putenv('LC_CTYPE=en_US.UTF-8');
$this->client = $client;
$this->root = rtrim($root, DIRECTORY_SEPARATOR);
$this->branch = isset($_COOKIE['repoBranch']) ? $_COOKIE['repoBranch'] : '';
chdir($this->root);
exec("{$this->client} config core.quotepath false");
}
public function ls($path, $revision = 'HEAD')
{
$path = ltrim($path, DIRECTORY_SEPARATOR);
$sub = '';
chdir($this->root);
if(!empty($path)) $sub = ":$path";
if(!empty($this->branch))$revision = $this->branch;
$cmd = escapeCmd("$this->client ls-tree -l $revision$sub");
$list = execCmd($cmd . ' 2>&1', 'array', $result);
if($result) return array();
$infos = array();
foreach($list as $entry)
{
list($mod, $kind, $revision, $size, $name) = preg_split('/[\t ]+/', $entry);
/* Get commit info. */
$pathName = ltrim($path . DIRECTORY_SEPARATOR . $name, DIRECTORY_SEPARATOR);
$cmd = escapeCmd("$this->client log -1 $this->branch -- $pathName");
$commit = execCmd($cmd, 'array');
$logs = $this->parseLog($commit);
if($size > 1024 * 1024)
{
$size = round($size / (1024 * 1024), 2) . 'MB';
}
else if($size > 1024)
{
$size = round($size / 1024, 2) . 'KB';
}
else
{
$size .= 'Bytes';
}
$info = new stdClass();
$info->name = $name;
$info->kind = $kind == 'tree' ? 'dir' : 'file';
$info->revision = $logs ? $logs[0]->revision : $revision;
$info->size = $size;
$info->account = $logs ? $logs[0]->committer : '';
$info->date = $logs ? $logs[0]->time : '';
$info->comment = $logs ? $logs[0]->comment : '';
$infos[] = $info;
unset($info);
}
/* Sort by kind */
foreach($infos as $key => $info) $kinds[$key] = $info->kind;
if($infos) array_multisort($kinds, SORT_ASC, $infos);
return $infos;
}
public function branch()
{
chdir($this->root);
/* Get local branch. */
$cmd = escapeCmd("$this->client branch");
$list = execCmd($cmd . ' 2>&1', 'array', $result);
if($result) return array();
$branches = array();
foreach($list as $localBranch)
{
if($localBranch{0} == '*') $localBranch = substr($localBranch, 1);
$localBranch = trim($localBranch);
$branches[$localBranch] = $localBranch;
}
asort($branches);
return $branches;
}
public function getLastLog($path, $count = 10)
{
$path = ltrim($path, DIRECTORY_SEPARATOR);
$revision = $this->branch ? $this->branch : 'HEAD';
chdir($this->root);
$list = execCmd(escapeCmd("$this->client log -10 $revision -- $path"), 'array');
$logs = $this->parseLog($list);
return $logs;
}
public function log($path, $fromRevision = 0, $toRevision = 'HEAD', $count = 0)
{
$path = ltrim($path, DIRECTORY_SEPARATOR);
$count = $count == 0 ? '' : "-n $count";
/* compatible with svn. */
if($fromRevision == 'HEAD' and $this->branch) $fromRevision = $this->branch;
if($toRevision == 'HEAD' and $this->branch) $toRevision = $this->branch;
if($fromRevision === $toRevision)
{
$logs = array();
chdir($this->root);
$list = execCmd(escapeCmd("$this->client log --stat=1024 --name-status -1 $fromRevision -- $path"), 'array');
$logs = $this->parseLog($list);
return $logs;
}
if(!$fromRevision)
{
$revisions = " $toRevision";
}
else
{
$revisions = "$fromRevision..$toRevision";
}
chdir($this->root);
$list = execCmd(escapeCmd("$this->client log $count $revisions -- $path"), 'array');
$logs = $this->parseLog($list);
return $logs;
}
public function blame($path, $revision)
{
$path = ltrim($path, DIRECTORY_SEPARATOR);
chdir($this->root);
$list = execCmd(escapeCmd("$this->client blame -l $revision -- $path"), 'array');
$blames = array();
$revLine = 0;
$revision = '';
foreach($list as $line)
{
if(empty($line)) continue;
if($line{0} == '^') $line = substr($line, 1);
preg_match('/^([0-9a-f]{39,40})\s.*\((\S+)\s+([\d-]+)\s(.*)\s(\d+)\)(.*)$/U', $line, $matches);
if(isset($matches[1]) and $matches[1] != $revision)
{
$blame = array();
$blame['revision'] = $matches[1];
$blame['committer'] = $matches[2];
$blame['time'] = $matches[3];
$blame['line'] = $matches[5];
$blame['lines'] = 1;
$blame['content'] = strpos($matches[6], ' ') === false ? $matches[6] : substr($matches[6], 1);
$revision = $matches[1];
$revLine = $matches[5];
$blames[$revLine] = $blame;
}
elseif(isset($matches[5]))
{
$blame = array();
$blame['line'] = $matches[5];
$blame['content'] = strpos($matches[6], ' ') === false ? $matches[6] : substr($matches[6], 1);
$blames[$matches[5]] = $blame;
$blames[$revLine]['lines'] ++;
}
}
return $blames;
}
public function diff($path, $fromRevision, $toRevision)
{
$path = ltrim($path, DIRECTORY_SEPARATOR);
chdir($this->root);
if($toRevision == 'HEAD' and $this->branch) $toRevision = $this->branch;
if($fromRevision == '^') $fromRevision = $toRevision . '^';
if(strpos($fromRevision, '^') !== false)
{
$list = execCmd(escapeCmd("$this->client log -2 $toRevision --pretty=format:%H -- $path"), 'array');
if(isset($list[1])) $fromRevision = $list[1];
}
$lines = execCmd(escapeCmd("$this->client diff $fromRevision $toRevision -- $path"), 'array');
return $lines;
}
public function cat($entry, $revision = 'HEAD')
{
chdir($this->root);
if($revision == 'HEAD' and $this->branch) $revision = $this->branch;
$cmd = escapeCmd("$this->client show $revision:$entry");
$content = execCmd($cmd);
if(is_array($content)) $content = implode("\n", $content);
return $content;
}
public function info($entry, $revision = 'HEAD')
{
chdir($this->root);
if($revision == 'HEAD' and $this->branch) $revision = $this->branch;
$path = ltrim($entry, DIRECTORY_SEPARATOR);
$cmd = escapeCmd("$this->client ls-tree $revision -- $path");
$result = execCmd($cmd);
$kind = '';
if($result)
{
$results = explode("\n", trim($result));
if(count($results) >= 2)
{
$kind = 'dir';
}
else
{
list($mode, $type) = explode(' ', $results[0]);
$kind = $type == 'tree' ? 'dir' : 'file';
}
}
$list = execCmd(escapeCmd("$this->client log -1 $revision --pretty=format:%H -- $path"), 'array');
$revision = $list[0];
$info = new stdclass();
$info->kind = $kind;
$info->path = $entry;
$info->revision = $revision;
$info->root = $this->root;
return $info;
}
public function parseDiff($lines)
{
if(empty($lines)) return array();
$diffs = array();
$num = count($lines);
$endLine = end($lines);
if(strpos($endLine, '\ No newline at end of file') === 0) $num -= 1;
$newFile = false;
for($i = 0; $i < $num; $i ++)
{
$diffFile = new stdclass();
if(strpos($lines[$i], "diff --git ") === 0)
{
$fileInfo = explode(' ',$lines[$i]);
$fileName = substr($fileInfo[2], strpos($fileInfo[2], '/') + 1);
$diffFile->fileName = $fileName;
for($i++; $i < $num; $i ++)
{
$diff = new stdclass();
/* Fix bug #1757. */
if($lines[$i] == '+++ /dev/null') $newFile = true;
if(strpos($lines[$i], '+++', 0) !== false) continue;
if(strpos($lines[$i], '---', 0) !== false) continue;
if(strpos($lines[$i], '======', 0) !== false) continue;
if(preg_match('/^@@ -(\\d+)(,(\\d+))?\\s+\\+(\\d+)(,(\\d+))?\\s+@@/A', $lines[$i]))
{
$startLines = trim(str_replace(array('@', '+', '-'), '', $lines[$i]));
list($oldStartLine, $newStartLine) = explode(' ', $startLines);
list($diff->oldStartLine) = explode(',', $oldStartLine);
list($diff->newStartLine) = explode(',', $newStartLine);
$oldCurrentLine = $diff->oldStartLine;
$newCurrentLine = $diff->newStartLine;
if($newFile)
{
$oldCurrentLine = $diff->newStartLine;
$newCurrentLine = $diff->oldStartLine;
}
$newLines = array();
for($i++; $i < $num; $i ++)
{
if(preg_match('/^@@ -(\\d+)(,(\\d+))?\\s+\\+(\\d+)(,(\\d+))?\\s+@@/A', $lines[$i]))
{
$i --;
break;
}
if(strpos($lines[$i], "diff --git ") === 0) break;
$line = $lines[$i];
if(strpos($line, '\ No newline at end of file') === 0)continue;
$sign = empty($line) ? '' : $line{0};
if($sign == '-' and $newFile) $sign = '+';
$type = $sign != '-' ? $sign == '+' ? 'new' : 'all' : 'old';
if($sign == '-' || $sign == '+')
{
$line = substr_replace($line, ' ', 1, 0);
if($newFile) $line = preg_replace('/^\-/', '+', $line);
}
$newLine = new stdclass();
$newLine->type = $type;
$newLine->oldlc = $type != 'new' ? $oldCurrentLine : '';
$newLine->newlc = $type != 'old' ? $newCurrentLine : '';
$newLine->line = htmlspecialchars($line);
if($type != 'new') $oldCurrentLine++;
if($type != 'old') $newCurrentLine++;
$newLines[] = $newLine;
}
$diff->lines = $newLines;
$diffFile->contents[] = $diff;
}
if(isset($lines[$i]) and strpos($lines[$i], "diff --git ") === 0)
{
$i --;
$newFile = false;
break;
}
}
$diffs[] = $diffFile;
}
}
return $diffs;
}
public function getCommitCount($commits = 0, $lastVersion = '')
{
chdir($this->root);
$revision = $this->branch ? $this->branch : 'HEAD';
return execCmd(escapeCmd("$this->client rev-list --count $revision -- ./"), 'string');
}
public function getFirstRevision()
{
chdir($this->root);
$list = execCmd(escapeCmd("$this->client rev-list --reverse HEAD -- ./"), 'array');
return $list[0];
}
public function getLatestRevision()
{
chdir($this->root);
$revision = $this->branch ? $this->branch : 'HEAD';
$list = execCmd(escapeCmd("$this->client rev-list -1 $revision -- ./"), 'array');
return $list[0];
}
public function getCommits($version = '', $count = 0, $branch = '')
{
if($version == 'HEAD' and $branch) $version = $branch;
$revision = empty($version) ? $revision : $version;
$revision = is_numeric($revision) ? "--skip=$revision $branch" : $revision;
$count = $count == 0 ? '' : "-n $count";
chdir($this->root);
$list = execCmd(escapeCmd("$this->client log $count $revision -- ./"), 'array');
$commits = $this->parseLog($list);
$logs = array();
foreach($commits as $commit)
{
$hash = $commit->revision;
$log = new stdClass();
$log->committer = $commit->committer;
$log->revision = $commit->revision;
$log->comment = $commit->comment;
$log->time = $commit->time;
$logs['commits'][$hash] = $log;
$logs['files'][$hash] = array();
}
if(empty($logs)) return $logs;
$hash = '';
$files = execCmd(escapeCmd("$this->client whatchanged $count $revision --pretty=format:%an@_@%cd@_@%H@_@%s -- ./"), 'array');
foreach($files as $commit)
{
$commit = trim($commit);
if(empty($commit)) continue;
$parsedCommit = explode('@_@', $commit);
if(count($parsedCommit) == 4)
{
list($account, $date, $hash, $comment) = $parsedCommit;
}
else
{
$file = explode(' ', $commit);
$file = end($file);
list($action, $path) = explode("\t", $file);
$parsedFile = new stdclass();
$parsedFile->revision = $hash;
$parsedFile->path = '/' . trim($path);
$parsedFile->type = 'file';
$parsedFile->action = $action;
$logs['files'][$hash][] = $parsedFile;
}
}
return $logs;
}
public function parseLog($logs)
{
$parsedLogs = array();
$i = 0;
foreach($logs as $line)
{
if(strpos($line, 'commit ') === 0)
{
if(isset($log))
{
$log->comment = trim($comment);
$log->change = $changes;
$parsedLogs[$i] = $log;
$i++;
}
$log = new stdclass();
$comment = '';
$changes = array();
$log->revision = trim(preg_replace('/^commit/', '', $line));
}
elseif(strpos($line, 'Author:') === 0)
{
$account = preg_replace('/^Author:/', '', $line);
$log->committer = trim(preg_replace('/<[a-zA-Z0-9_\-\.]+@[a-zA-Z0-9_\-\.]+>/', '', $account));
}
elseif(strpos($line, 'Date:') === 0)
{
$date = trim(preg_replace('/^Date:/', '', $line));
$log->time = date('Y-m-d H:i:s', strtotime($date));
}
elseif(preg_match('/^\s{2,}/', $line))
{
$comment .= $line;
}
elseif(strpos($line, "\t") !== false)
{
list($action, $entry) = explode("\t", $line);
$entry = '/' . trim($entry);
$pathInfo = array();
$pathInfo['action'] = $action;
$pathInfo['kind'] = 'file';
$changes[$entry] = $pathInfo;
}
}
if(isset($log))
{
$log->comment = trim($comment);
$log->change = $changes;
$parsedLogs[$i] = $log;
}
return $parsedLogs;
}
}
+107
View File
@@ -0,0 +1,107 @@
<?php
class scm
{
public $engine;
public function setEngine($repo)
{
$className = $repo->SCM;
if(!class_exists($className)) require(strtolower($className) . '.class.php');
$this->engine = new $className($repo->client, $repo->path, $repo->account, $repo->password, $repo->encoding);
}
public function ls($path, $revision = 'HEAD')
{
return $this->engine->ls($path, $revision);
}
public function branch()
{
return $this->engine->branch();
}
public function log($path, $fromRevision = 0, $toRevision = 'HEAD', $count = 0)
{
return $this->engine->log($path, $fromRevision, $toRevision);
}
public function blame($path, $revision)
{
return $this->engine->blame($path, $revision);
}
public function getLastLog($path, $count = 10)
{
return $this->engine->getLastLog($path, $count);
}
public function diff($path, $fromRevision = 0, $toRevision = 'HEAD', $parse = 'yes')
{
$diffs = $this->engine->diff($path, $fromRevision, $toRevision);
if($parse != 'yes') return implode("\n", $diffs);
return $this->engine->parseDiff($diffs);
}
public function cat($entry, $revision = 'HEAD')
{
return $this->engine->cat($entry, $revision);
}
public function info($entry, $revision = 'HEAD')
{
return $this->engine->info($entry, $revision);
}
public function getCommitCount($commits = 0, $lastVersion = 0)
{
return $this->engine->getCommitCount($commits, $lastVersion);
}
public function getLatestRevision()
{
return $this->engine->getLatestRevision();
}
public function getFirstRevision()
{
return $this->engine->getFirstRevision();
}
public function getCommits($version = '', $count = 0, $branch = '')
{
return $this->engine->getCommits($version, $count, $branch);
}
}
function escapeCmd($cmd)
{
$codes = array('#', '&', ';', '`', '|', '*', '?', '~', '<', '>', '^', '[', ']', '{', '}', '$', ',', '\x0A', '\xFF');
if(DIRECTORY_SEPARATOR == '/') $codes[] = '\\';
foreach($codes as $code) $cmd = str_replace($code, '\\' . $code, $cmd);
return $cmd;
}
function execCmd($cmd, $return = 'string', &$result = 0, $type = 'utf-8')
{
if(file_exists(dirname(__FILE__) . '/config.php')) include dirname(__FILE__) . '/config.php';
if($type != 'utf-8') $cmd = iconv('utf-8', $type . '//TRANSLIT', $cmd);
$debug = (isset($config->debug) and $config->debug);
if($debug and strpos($cmd, '2>&1') === false) $cmd = $cmd . ' 2>&1';
ob_start();
passthru($cmd, $result);
$output = ob_get_clean();
if($debug and $result)
{
a('The command is ' . $cmd);
a('The result is ' . $result);
a($output);
}
/* When output is empty and with chinese then try execute again in windows. */
if(strtolower(substr(PHP_OS, 0, 3)) == 'win' and empty($output) and $type == 'utf-8' and preg_match("/[\x7f-\xff]/", $cmd)) $output = execCmd($cmd, 'string', $result, 'gbk');
if($return == 'array') return explode("\n", trim($output));
return $output;
}
+15
View File
@@ -0,0 +1,15 @@
<?php
include 'scm.class.php';
function subversionTest()
{
$repo->SCM = 'Subversion';
$repo->client = '/usr/bin/svn';
$repo->account = 'aaa';
$repo->password = 'aaaaaa';
$scm = new scm($repo);
print_r($scm->cat("http://svn.aaa.5upm.cn/bb/aaa"));
}
subversionTest();
+464
View File
@@ -0,0 +1,464 @@
<?php
class Subversion
{
public $client;
public $root;
public $account;
public $password;
public $ssh;
public $remote;
public $encoding;
public function __construct($client, $root, $account, $password, $encoding = 'UTF-8')
{
putenv('LC_CTYPE=en_US.UTF-8');
$this->root = rtrim($root, DIRECTORY_SEPARATOR);
$this->account = $account;
$this->password = $password;
$this->encoding = $encoding;
$this->ssh = (stripos($this->root, 'svn') === 0 or stripos($this->root, 'https') === 0) ? true : false;
$this->remote = !(stripos($this->root, 'file') === 0);
$this->client = $this->remote ? $client . " --username @account@ --password @password@" : $client;
if($this->encoding == 'utf-8') $this->encoding = 'gbk';
}
public function ls($path, $revision = 'HEAD')
{
$resourcePath = $path;
$path = '"' . $this->root . '/' . str_replace('%2F', '/', urlencode($path)) . '"';
$cmd = $this->replaceAuth(escapeCmd($this->buildCMD($path, 'ls', "-r $revision --xml")));
$list = execCmd($cmd, 'string', $result);
if($result)
{
$path = '"' . $this->root . '/' . $resourcePath . '"';
$cmd = $this->replaceAuth(escapeCmd($this->buildCMD($path, 'ls', "-r $revision --xml")));
$list = execCmd($cmd, 'string', $result);
if($result) $list = '';
}
$listObject = simplexml_load_string($list);
if(!empty($list) and empty($listObject))
{
$list = helper::convertEncoding($list, $this->encoding, 'utf-8');
$listObject = simplexml_load_string($list);
}
if(!empty($listObject->list->entry)) $listObject = $listObject->list->entry;
$infos = array();
if(empty($listObject)) return $infos;
foreach($listObject as $list)
{
$info = new stdclass();
$info->name = (string)$list->name;
$info->kind = (string)$list['kind'];
$info->revision = (int)$list->commit['revision'];
$info->account = (string)$list->commit->author;
$info->date = date('Y-m-d H:i:s', strtotime($list->commit->date));
$info->size = $info->kind == 'file' ? (int)$list->size > 1024 ? round((int)$list->size / 1024, 2) . "KB" : (int)$list->size . 'Bytes' : 0;
$info->comment = '';
$infos[] = $info;
}
/* Sort by kind */
foreach($infos as $key => $info) $kind[$key] = $info->kind;
if($infos) array_multisort($kind, SORT_ASC, $infos);
return $infos;
}
public function branch()
{
return array();
}
public function getLastLog($path, $count = 10)
{
$resourcePath = $path;
$path = '"' . $this->root . '/' . str_replace('%2F', '/', urlencode($path)) . '"';
$cmd = $this->replaceAuth(escapeCmd($this->buildCMD($path, 'log', "--limit $count --xml")));
$comments = execCmd($cmd, 'string', $result);
if($result)
{
$path = '"' . $this->root . '/' . $resourcePath . '"';
$cmd = $this->replaceAuth(escapeCmd($this->buildCMD($path, 'log', "--limit $count --xml")));
$comments = execCmd($cmd, 'string', $result);
if($result) $comments = '';
}
$parsedComments = simplexml_load_string($comments);
if(!empty($comments) and empty($parsedComments))
{
$comments = helper::convertEncoding($comments, $this->encoding, 'utf-8');
$parsedComments = simplexml_load_string($comments);
}
$logs = array();
foreach($parsedComments->logentry as $entry)
{
$log = new stdclass();
$log->committer = (string)$entry->author;
$log->revision = (int)$entry['revision'];
$log->comment = trim((string)$entry->msg);
$log->time = date('Y-m-d H:i:s', strtotime($entry->date));
$log->change = array();
$logs[] = $log;
unset($log);
}
/* Sort by kind */
foreach($logs as $key => $log) $revision[$key] = $log->revision;
if($logs) array_multisort($revision, SORT_DESC, $logs);
return $logs;
}
public function log($path, $fromRevision = 0, $toRevision = 'HEAD', $count = 0, $quiet = false)
{
$resourcePath = $path;
$count = $count == 0 ? '' : "--limit $count";
$param = $quiet ? '-q' : '-v';
$path = '"' . $this->root . '/' . str_replace('%2F', '/', urlencode($path)) . '"';
$cmd = $this->replaceAuth(escapeCmd($this->buildCMD($path, 'log', "$count $param -r $fromRevision:$toRevision --xml")));
$comments = execCmd($cmd, 'string', $result);
if($result)
{
$path = '"' . $this->root . '/' . $resourcePath . '"';
$cmd = $this->replaceAuth(escapeCmd($this->buildCMD($path, 'log', "$count $param -r $fromRevision:$toRevision --xml")));
$comments = execCmd($cmd, 'string', $result);
if($result) $comments = '';
}
$parsedComments = simplexml_load_string($comments);
if(!empty($comments) and empty($parsedComments))
{
$comments = helper::convertEncoding($comments, $this->encoding, 'utf-8');
$parsedComments = simplexml_load_string($comments);
}
$logs = array();
$revision = array();
if(empty($parsedComments->logentry)) return $logs;
foreach($parsedComments->logentry as $entry)
{
$log = new stdclass();
$log->committer = (string)$entry->author;
$log->revision = (int)$entry['revision'];
$log->comment = trim((string)$entry->msg);
$log->time = date('Y-m-d H:i:s', strtotime($entry->date));
$log->change = array();
if(!empty($entry->paths))
{
foreach($entry->paths->path as $path)
{
$pathInfo = array();
foreach($path->attributes() as $attr => $value) $pathInfo[$attr] = (string)$value;
$log->change[(string)$path] = $pathInfo;
}
}
if(in_array($log->revision, $revision)) continue;
$logs[] = $log;
$revision[] = $log->revision;
unset($log);
}
/* Sort by kind */
if($logs) array_multisort($revision, SORT_DESC, $logs);
return $logs;
}
public function blame($path, $revision)
{
$resourcePath = $path;
$path = '"' . $this->root . '/' . str_replace('%2F', '/', urlencode($path)) . '"';
$file = $this->replaceAuth(escapeCmd($this->buildCMD($path, 'cat', "-r $revision")));
$blame = $this->replaceAuth(escapeCmd($this->buildCMD($path, 'blame', "-r $revision --xml")));
$output = execCmd($blame, 'string', $result);
if($result)
{
$path = '"' . $this->root . '/' . $resourcePath . '"';
$file = $this->replaceAuth(escapeCmd($this->buildCMD($path, 'cat', "-r $revision")));
$blame = $this->replaceAuth(escapeCmd($this->buildCMD($path, 'blame', "-r $revision --xml")));
$output = execCmd($blame, 'string', $result);
if($result) return array();
}
$content = execCmd($file, 'array');
$parsedResult = simplexml_load_string($output);
if(!empty($output) and empty($parsedResult))
{
$output = helper::convertEncoding($output, $this->encoding, 'utf-8');
$parsedResult = simplexml_load_string($output);
}
$blames = array();
$revLine = 0;
$revision = '';
if($parsedResult->target->entry)
{
foreach($parsedResult->target->entry as $line)
{
if($line->commit['revision'] != $revision)
{
$blame = array();
$blame['revision'] = (int)$line->commit['revision'];
$blame['committer'] = (string)$line->commit->author;
$blame['time'] = substr($line->commit->date, 0, 10);
$blame['line'] = (int)$line['line-number'];
$blame['lines'] = 1;
$blame['content'] = $content[$blame['line'] - 1];
$revision = $blame['revision'];
$revLine = $blame['line'];
$blames[$revLine] = $blame;
}
else
{
$blame = array();
$blame['line'] = (int)$line['line-number'];
$blame['content'] = $content[$blame['line'] - 1];
$blames[$blame['line']] = $blame;
$blames[$revLine]['lines'] ++;
}
}
}
return $blames;
}
public function diff($path, $fromRevision, $toRevision)
{
$resourcePath = $path;
if($fromRevision == '^') $fromRevision = $toRevision - 1;
$path = '"' . $this->root . '/' . str_replace('%2F', '/', urlencode($path)) . '"';
$cmd = $this->replaceAuth(escapeCmd($this->buildCMD($path, 'diff', "-r $fromRevision:$toRevision")));
$lines = execCmd($cmd, 'array', $result);
if($result)
{
$path = '"' . $this->root . '/' . $resourcePath . '"';
$cmd = $this->replaceAuth(escapeCmd($this->buildCMD($path, 'diff', "-r $fromRevision:$toRevision")));
$lines = execCmd($cmd, 'array', $result);
}
return $lines;
}
public function cat($entry, $revision = 'HEAD')
{
$resourcePath = $entry;
$entry = '"' . $this->root . '/' . str_replace('%2F', '/', urlencode($entry)) . '"';
$cmd = $this->replaceAuth(escapeCmd($this->buildCMD($entry, 'cat', "-r $revision")));
$content = execCmd($cmd, 'string', $result);
if($result)
{
$entry = '"' . $this->root . '/' . $resourcePath . '"';
$cmd = $this->replaceAuth(escapeCmd($this->buildCMD($entry, 'cat', "-r $revision")));
$content = execCmd($cmd, 'string', $result);
}
return $content;
}
public function info($entry, $revision = 'HEAD')
{
$resourcePath = $entry;
$entry = '"' . $this->root . '/' . str_replace('%2F', '/', urlencode($entry)) . '"';
$svnInfo = $this->replaceAuth(escapeCmd($this->buildCMD($entry, 'info', "-r $revision --xml")));
$svninfo = execCmd($svnInfo, 'string', $result);
if($result)
{
$entry = '"' . $this->root . '/' . $resourcePath . '"';
$svnInfo = $this->replaceAuth(escapeCmd($this->buildCMD($entry, 'info', "-r $revision --xml")));
$svninfo = execCmd($svnInfo, 'string', $result);
if($result) $svninfo = '';
}
$parsedSvnInfo = simplexml_load_string($svninfo);
if(!empty($svninfo) and empty($parsedSvnInfo))
{
$svninfo = helper::convertEncoding($svninfo, $this->encoding, 'utf-8');
$parsedSvnInfo = simplexml_load_string($svninfo);
}
$info = new stdclass();
$info->kind = empty($parsedSvnInfo->entry['kind']) ? '' : (string)$parsedSvnInfo->entry['kind'];
$info->path = empty($parsedSvnInfo->entry['path']) ? '' : (string)$parsedSvnInfo->entry['path'];
$info->revision = empty($parsedSvnInfo->entry['revision']) ? '' : (int)$parsedSvnInfo->entry['revision'];
$info->cRevision = empty($parsedSvnInfo->entry->commit['revision']) ? '' : (int)$parsedSvnInfo->entry->commit['revision'];
$info->root = empty($parsedSvnInfo->entry->repository->root) ? '' : (string)$parsedSvnInfo->entry->repository->root;
return $info;
}
public function parseDiff($lines)
{
if(empty($lines)) return array();
$diffs = array();
$num = count($lines);
$endLine = end($lines);
if(strpos($endLine, '\ No newline at end of file') === 0) $num -= 1;
for($i = 0; $i < $num; $i ++)
{
$diffFile = new stdclass();
if(strpos($lines[$i], "Index: ") === 0)
{
$fileName = str_replace('Index: ', '', $lines[$i]);
$diffFile->fileName = $fileName;
for($i++; $i < $num; $i ++)
{
$diff = new stdclass();
if(strpos($lines[$i], '+++', 0) !== false) continue;
if(strpos($lines[$i], '---', 0) !== false) continue;
if(strpos($lines[$i], '======', 0) !== false) continue;
if(preg_match('/^@@ -(\\d+)(,(\\d+))?\\s+\\+(\\d+)(,(\\d+))?\\s+@@\\s*($)/A', $lines[$i]))
{
$startLines = trim(str_replace(array('@', '+', '-'), '', $lines[$i]));
list($oldStartLine, $newStartLine) = explode(' ', $startLines);
list($diff->oldStartLine) = explode(',', $oldStartLine);
list($diff->newStartLine) = explode(',', $newStartLine);
$oldCurrentLine = $diff->oldStartLine;
$newCurrentLine = $diff->newStartLine;
$newLines = array();
for($i++; $i < $num; $i ++)
{
if(preg_match('/^@@ -(\\d+)(,(\\d+))?\\s+\\+(\\d+)(,(\\d+))?\\s+@@\\s*($)/A', $lines[$i]))
{
$i --;
break;
}
if(strpos($lines[$i], "Index: ") === 0) break;
$line = $lines[$i];
if(strpos($line, '\ No newline at end of file') === 0)continue;
$sign = empty($line) ? '' : $line{0};
$type = $sign != '-' ? $sign == '+' ? 'new' : 'all' : 'old';
if($sign == '-' || $sign == '+') $line = substr_replace($line, ' ', 1, 0);
$newLine = new stdclass();
$newLine->type = $type;
$newLine->oldlc = $type != 'new' ? $oldCurrentLine : '';
$newLine->newlc = $type != 'old' ? $newCurrentLine : '';
$newLine->line = $line;
if($type != 'new') $oldCurrentLine++;
if($type != 'old') $newCurrentLine++;
$newLines[] = $newLine;
}
$diff->lines = $newLines;
$diffFile->contents[] = $diff;
}
if(isset($lines[$i]) and strpos($lines[$i], "Index: ") === 0)
{
$i --;
break;
}
}
$diffs[] = $diffFile;
}
}
return $diffs;
}
public function getCommitCount($commits = 0, $lastVersion = 0)
{
if(empty($commits)) $commits = 0;
if(empty($lastVersion)) $lastVersion = 0;
$lastRevision = $this->getLatestRevision();
$count = 10000;
$from = $lastVersion;
while(true)
{
$logs = $this->log('', $from, $lastRevision, empty($from) ? $count : $count + 1, $quiet = true);
if(empty($logs)) break;
$num = empty($from) ? count($logs) : count($logs) - 1;
$commits += $num;
$from = reset($logs);
$from = $from->revision;
if($from == $lastRevision) break;
}
return $commits;
}
public function getFirstRevision()
{
$logs = $this->log('', 0, 'HEAD', 1, $quiet = true);
if(empty($logs)) return 0;
$firstLog = end($logs);
return $firstLog->revision;
}
public function getLatestRevision()
{
$info = $this->info('');
return $info->cRevision;
}
public function getCommits($version = '', $count = 0)
{
$count = $count == 0 ? '' : "--limit $count";
$path = '"' . $this->root . '"';
if(stripos($this->root, 'https') === 0 or stripos($this->root, 'svn') === 0)
{
$comments = str_replace("\\", "/", "$this->client log $count -v -r $version:0 --non-interactive --trust-server-cert-failures=cn-mismatch --trust-server-cert --no-auth-cache --xml $path");
}
else
{
$comments = str_replace("\\", "/", "$this->client log $count -v -r $version:0 --no-auth-cache --xml $path");
}
$comments = $this->replaceAuth(escapeCmd($comments));
$comments = execCmd($comments, 'string', $result);
if($result) $comments = '';
$parsedComments = simplexml_load_string($comments);
if(!empty($comments) and empty($parsedComments))
{
$comments = helper::convertEncoding($comments, $this->encoding, 'utf-8');
$parsedComments = simplexml_load_string($comments);
}
$logs = array();
foreach($parsedComments->logentry as $entry)
{
$parsedLog = new stdClass();
$parsedLog->committer = (string)$entry->author;
$parsedLog->revision = (int)$entry['revision'];
$parsedLog->comment = trim((string)$entry->msg);
$parsedLog->time = date('Y-m-d H:i:s', strtotime($entry->date));
$logs['commits'][$parsedLog->revision] = $parsedLog;
$logs['files'][$parsedLog->revision] = array();
if(!empty($entry->paths))
{
foreach($entry->paths->path as $file)
{
$parsedFile = new stdclass();
$parsedFile->revision = $parsedLog->revision;
$parsedFile->path = (string)$file;
$parsedFile->type = (string)$file['kind'];
$parsedFile->action = (string)$file['action'];
$logs['files'][$parsedLog->revision][] = $parsedFile;
}
}
}
return $logs;
}
public function replaceAuth($cmd)
{
return str_replace(array('@account@', '@password@'), array($this->account, $this->password), $cmd);
}
public function buildCMD($path, $action, $param)
{
if($this->ssh)
{
$cmd = str_replace("\\", "/", "$this->client $action $param --non-interactive --trust-server-cert-failures=cn-mismatch --trust-server-cert --no-auth-cache $path");
}
else
{
$cmd = str_replace("\\", "/", "$this->client $action $param --no-auth-cache $path");
}
return $cmd;
}
}
+1 -1
View File
@@ -239,7 +239,7 @@ class adminModel extends model
/* Check weak password when login. */
if($this->app->moduleName == 'user' and $this->app->methodName == 'login')
{
if(!isset($_POST['passwordStrength']) return true;
if(!isset($_POST['passwordStrength'])) return true;
if(isset($this->config->safe->mode) and $this->post->passwordStrength < $this->config->safe->mode) return true;
}
+9 -4
View File
@@ -4,10 +4,11 @@ $lang->menuOrder[5] = 'my';
$lang->menuOrder[10] = 'product';
$lang->menuOrder[15] = 'project';
$lang->menuOrder[20] = 'qa';
$lang->menuOrder[25] = 'doc';
$lang->menuOrder[30] = 'report';
$lang->menuOrder[35] = 'company';
$lang->menuOrder[40] = 'admin';
$lang->menuOrder[25] = 'repo';
$lang->menuOrder[30] = 'doc';
$lang->menuOrder[35] = 'report';
$lang->menuOrder[40] = 'company';
$lang->menuOrder[45] = 'admin';
/* index menu order. */
$lang->index->menuOrder[5] = 'product';
@@ -76,6 +77,10 @@ $lang->testsuite->menuOrder = $lang->testcase->menuOrder;
$lang->caselib->menuOrder = $lang->testcase->menuOrder;
$lang->testreport->menuOrder = $lang->testcase->menuOrder;
$lang->repo->menuOrder[5] = 'log';
$lang->repo->menuOrder[15] = 'settings';
$lang->repo->menuOrder[20] = 'delete';
/* doc menu order. */
$lang->doc->menuOrder[5] = 'list';
$lang->doc->menuOrder[10] = 'product';
+7
View File
@@ -123,6 +123,7 @@ $lang->menu->my = '<span> 我的地盘</span>|my|index';
$lang->menu->product = $lang->productCommon . '|product|index|locate=no';
$lang->menu->project = $lang->projectCommon . '|project|index|locate=no';
$lang->menu->qa = '测试|qa|index';
$lang->menu->repo = '代码|repo|log';
$lang->menu->doc = '文档|doc|index';
$lang->menu->report = '统计|report|index';
$lang->menu->company = '组织|company|index';
@@ -331,6 +332,12 @@ $lang->caselib->menu->testsuite = array('link' => '套件|testsuite|browse|');
$lang->caselib->menu->report = array('link' => '报告|testreport|browse|');
$lang->caselib->menu->caselib = array('link' => '用例库|caselib|browse', 'alias' => 'create,createcase,view,edit,batchcreatecase,showimport', 'subModule' => 'tree,testcase');
$lang->repo = new stdclass();
$lang->repo->menu = new stdclass();
$lang->repo->menu->log = array('link' =>'浏览|repo|log|repoID=%s&entry=', 'alias' => 'diff,view,revision,showsynccomment');
$lang->repo->menu->settings = '设置|repo|settings|repoID=%s';
$lang->repo->menu->delete = array('link' => '删除|repo|delete|repoID=%s', 'target' => 'hiddenwin');
/* 文档视图菜单设置。*/
$lang->doc = new stdclass();
$lang->doc->menu = new stdclass();
+32
View File
@@ -0,0 +1,32 @@
<?php
$config->program = new stdclass();
$config->program->suffix['c'] = "cpp";
$config->program->suffix['cpp'] = "cpp";
$config->program->suffix['asp'] = "asp";
$config->program->suffix['php'] = "php";
$config->program->suffix['cs'] = "cs";
$config->program->suffix['sh'] = "bash";
$config->program->suffix['jsp'] = "java";
$config->program->suffix['lua'] = "lua";
$config->program->suffix['sql'] = "sql";
$config->program->suffix['js'] = "javascript";
$config->program->suffix['ini'] = "ini";
$config->program->suffix['conf'] = "apache";
$config->program->suffix['bat'] = "dos";
$config->program->suffix['py'] = "python";
$config->program->suffix['rb'] = "ruby";
$config->program->suffix['as'] = "actionscript";
$config->program->suffix['html'] = "xml";
$config->program->suffix['xml'] = "xml";
$config->program->suffix['htm'] = "xml";
$config->program->suffix['pl'] = "perl";
$config->repo->cacheTime = 10;
$config->repo->syncTime = 10;
$config->repo->batchNum = 100;
$config->repo->images = '|png|gif|jpg|ico|jpeg|bmp|';
$config->repo->binary = '|pdf|';
$config->repo->editor = new stdclass();
$config->repo->editor->view = array('id' => 'commentText', 'tools' => 'simpleTools');
$config->repo->editor->diff = array('id' => 'commentText', 'tools' => 'simpleTools');
+642
View File
@@ -0,0 +1,642 @@
<?php
/**
* The control file of repo module of ZenTaoPMS.
*
* @copyright Copyright 2009-2012 青岛易软天创网络科技有限公司 (QingDao Nature Easy Soft Network Technology Co,LTD www.cnezsoft.com)
* @author Yidong Wang, Jinyong Zhu
* @package repo
* @version $Id$
* @link http://www.zentao.net
*/
class repo extends control
{
/**
* Construct.
*
* @access public
* @return void
*/
public function __construct()
{
parent::__construct();
$disFuncs = str_replace(' ', '', ini_get('disable_functions'));
if(stripos(",$disFuncs,", ',exec,') !== false or stripos(",$disFuncs,", ',shell_exec,') !== false)
{
echo js::alert($this->lang->repo->error->useless);
die(js::locate('back'));
}
$this->scm = $this->app->loadClass('scm');
$this->repos = $this->repo->getRepoPairs();
if(common::hasPriv('repo', 'create')) $this->lang->modulePageActions = html::a(helper::createLink('repo', 'create'), "<i class='icon icon-plus text-muted'></i> " . $this->lang->repo->create, '', "class='btn'");
if(empty($this->repos) and $this->methodName != 'create') die(js::locate($this->repo->createLink('create')));
/* Unlock session for wait to get data of repo. */
session_write_close();
}
/**
* Create repo.
*
* @access public
* @return void
*/
public function create()
{
$this->repo->setMenu($this->repos);
if(!empty($_POST))
{
$repoID = $this->repo->create();
if(dao::isError()) die(js::error(dao::getError()));
die(js::locate($this->repo->createLink('showSyncComment', "repoID=$repoID"), 'parent'));
}
$this->view->title = $this->lang->repo->create;
$this->view->groups = $this->loadModel('group')->getPairs();
$this->view->users = $this->loadModel('user')->getPairs('noletter|noempty|nodeleted');
$this->display();
}
/**
* Set repo.
*
* @param int $repoID
* @access public
* @return void
*/
public function settings($repoID = 0)
{
$this->repo->setMenu($this->repos, $repoID);
if($repoID == 0) $repoID = $this->session->repoID;
if(!empty($_POST))
{
$needSync = $this->repo->saveSettings($repoID);
if(dao::isError()) die(js::error(dao::getError()));
if(!$needSync)
{
die(js::locate($this->repo->createLink('showSyncComment', "repoID=$repoID"), 'parent'));
}
die(js::locate($this->repo->createLink('log', "repoID=$repoID"), 'parent'));
}
$this->view->title = $this->lang->repo->settings;
$this->view->repo = $this->repo->getRepoByID($repoID);
$this->view->groups = $this->loadModel('group')->getPairs();
$this->view->users = $this->loadModel('user')->getPairs('noletter|noempty|nodeleted', !empty($repo->acl->users) ? $repo->acl->users : '');
$this->display();
}
/**
* Delete repo.
*
* @param int $repoID
* @param string $confirm
* @access public
* @return void
*/
public function delete($repoID, $confirm = 'no')
{
if($confirm == 'no')
{
die(js::confirm($this->lang->repo->notice->delete, $this->repo->createLink('delete', "repoID=$repoID&confirm=yes")));
}
$this->dao->delete()->from(TABLE_REPO)->where('id')->eq($repoID)->exec();
$this->dao->delete()->from(TABLE_REPOHISTORY)->where('repo')->eq($repoID)->exec();
$this->dao->delete()->from(TABLE_REPOFILES)->where('repo')->eq($repoID)->exec();
$this->dao->delete()->from(TABLE_REPOBRANCH)->where('repo')->eq($repoID)->exec();
echo js::alert($this->lang->repo->notice->successDelete);
die(js::locate($this->repo->createLink('log'), 'parent'));
}
/**
* View repo file.
*
* @param int $repoID
* @param string $entry
* @param string $revision
* @param string $showBug
* @param string $encoding
* @access public
* @return void
*/
public function view($repoID, $entry, $revision = 'HEAD', $showBug = 'false', $encoding = '')
{
if($this->get->entry) $entry = $this->get->entry;
$this->repo->setMenu($this->repos, $repoID);
$this->repo->setBackSession('view', $withOtherModule = true);
if($repoID == 0) $repoID = $this->session->repoID;
$file = $entry;
$repo = $this->repo->getRepoByID($repoID);
$entry = $this->repo->decodePath($entry);
$this->scm->setEngine($repo);
$info = $this->scm->info($entry, $revision);
if($info->kind == 'dir') $this->locate($this->repo->createLink('log', "repoID=$repoID&entry=&revision=$revision", "entry=" . $this->repo->encodePath($info->path)));
$content = $this->scm->cat($entry, $revision);
$entry = urldecode($entry);
$pathInfo = pathinfo($entry);
$encoding = empty($encoding) ? $repo->encoding : $encoding;
$encoding = strtolower(str_replace('_', '-', $encoding));
$suffix = '';
if(isset($pathInfo["extension"])) $suffix = strtolower($pathInfo["extension"]);
if(!$suffix or (!array_key_exists($suffix, $this->config->program->suffix) and strpos($this->config->repo->images, "|$suffix|") === false)) $suffix = $this->repo->isBinary($content, $suffix) ? 'binary' : 'c';
if(strpos($this->config->repo->images, "|$suffix|") !== false)
{
$content = base64_encode($content);
}
elseif($encoding != 'utf-8')
{
$content = helper::convertEncoding($content, $encoding);
}
$this->app->loadClass('pager', $static = true);
$pager = new pager(0, 8, 1);
$commiters = $this->loadModel('user')->getCommiters();
$logType = 'file';
$revisions = $this->repo->getLogs($repo, '/' . $entry, 'HEAD', $logType, $pager);
$i = 0;
foreach($revisions as $log)
{
if($revision == 'HEAD' and $i == 0) $revision = $log->revision;
if($revision == $log->revision) $revisionName = $repo->SCM == 'Git' ? $this->repo->getGitRevisionName($log->revision, $log->commit) : $log->revision;
$log->committer = zget($commiters, $log->committer, $log->committer);
$i++;
}
if(!isset($revisionName))
{
if($repo->SCM == 'Git') $gitCommit = $this->dao->select('*')->from(TABLE_REPOHISTORY)->where('revision')->eq($revision)->andWhere('repo')->eq($repo->id)->fetch('commit');
$revisionName = ($repo->SCM == 'Git' and isset($gitCommit)) ? $this->repo->getGitRevisionName($revision, $gitCommit) : $revision;
}
$this->view->revisions = $revisions;
$this->view->title = $this->lang->repo->common;
$this->view->type = 'view';
$this->view->showBug = $showBug;
$this->view->encoding = str_replace('-', '_', $encoding);
$this->view->repoID = $repoID;
$this->view->repo = $repo;
$this->view->revision = $revision;
$this->view->revisionName = $revisionName;
$this->view->preAndNext = $this->repo->getPreAndNext($repo, '/' . $entry, $revision);
$this->view->file = $file;
$this->view->entry = $entry;
$this->view->path = $entry;
$this->view->suffix = $suffix;
$this->view->content = $content;
$this->view->pager = $pager;
$this->view->logType = $logType;
$this->view->info = $info;
$this->display();
}
/**
* Browse repo.
*
* @param int $repoID
* @param string $path
* @param string $revision
* @param int $refresh
* @access public
* @return void
*/
public function browse($repoID = 0, $path = '', $revision = 'HEAD', $refresh = 0)
{
if($this->get->path) $path = $this->get->path;
$this->locate($this->repo->createLink('log', "repoID=$repoID&entry=&revision=$revision", "entry=$path"));
}
/**
* show repo log.
*
* @param int $repoID
* @param string $entry
* @param string $revision
* @param string $type
* @param int $recTotal
* @param int $recPerPage
* @param int $pageID
* @access public
* @return void
*/
public function log($repoID = 0, $entry = '', $revision = 'HEAD', $type = 'dir', $recTotal = 0, $recPerPage = 50, $pageID = 1)
{
if($this->get->entry) $entry = $this->get->entry;
$this->repo->setMenu($this->repos, $repoID);
$this->repo->setBackSession('list', $withOtherModule = true);
if($repoID == 0) $repoID = $this->session->repoID;
$repo = $this->repo->getRepoByID($repoID);
$file = $entry;
$entry = $this->repo->decodePath($entry);
$this->app->loadClass('pager', $static = true);
$pager = new pager($recTotal, $recPerPage, $pageID);
$this->scm->setEngine($repo);
$info = $this->scm->info($entry, $revision);
$logs = $this->repo->getLogs($repo, $entry, $revision, $type, $pager);
$commiters = $this->loadModel('user')->getCommiters();
foreach($logs as $log) $log->committer = zget($commiters, $log->committer, $log->committer);
$this->view->repo = $repo;
$this->view->title = $this->lang->repo->common;
$this->view->logs = $logs;
$this->view->revision = $revision;
$this->view->repoID = $repoID;
$this->view->entry = urldecode($entry);
$this->view->path = urldecode($entry);
$this->view->file = urldecode($file);
$this->view->pager = $pager;
$this->view->info = $info;
$this->display();
}
/**
* Show repo revision.
*
* @param int $repoID
* @param int $revision
* @param string $path
* @param string $type
*
* @access public
* @return void
*/
public function revision($repoID, $revision, $root = '', $type = 'dir')
{
$this->repo->setMenu($this->repos, $repoID);
$this->repo->setBackSession();
if($repoID == 0) $repoID = $this->session->repoID;
$repo = $this->repo->getRepoByID($repoID);
$this->scm->setEngine($repo);
$log = $this->scm->log('', $revision, $revision);
$history = $this->dao->select('*')->from(TABLE_REPOHISTORY)->where('revision')->eq($log[0]->revision)->andWhere('repo')->eq($repoID)->fetch();
if($history)
{
$oldRevision = $this->dao->select('revision')->from(TABLE_REPOHISTORY)->where('commit')->eq($history->commit - 1)->andWhere('repo')->eq($repoID)->fetch('revision');
$log[0]->commit = $history->commit;
}
if(empty($oldRevision)) $oldRevision = '^';
$changes = array();
$viewPriv = common::hasPriv('repo', 'view');
$diffPriv = common::hasPriv('repo', 'diff');
foreach($log[0]->change as $path => $change)
{
if($repo->prefix) $path = str_replace($repo->prefix, '', $path);
$encodePath = $this->repo->encodePath($path);
if($change['kind'] == '' or $change['kind'] == 'file')
{
$change['view'] = $viewPriv ? html::a($this->repo->createLink('view', "repoID=$repoID&entry=&revision=$revision", "entry=$encodePath"), $this->lang->repo->viewA) : '';
if($change['action'] == 'M') $change['diff'] = $diffPriv ? html::a($this->repo->createLink('diff', "repoID=$repoID&entry=&oldRevision=$oldRevision&newRevision=$revision", "entry=$encodePath"), $this->lang->repo->diffAB) : '';
}
else
{
$change['view'] = $viewPriv ? html::a($this->repo->createLink('log', "repoID=$repoID&entry=&revision=$revision", "entry=$encodePath"), $this->lang->repo->log) : '';
if($change['action'] == 'M') $change['diff'] = $diffPriv ? html::a($this->repo->createLink('diff', "repoID=$repoID&entry=&oldRevision=$oldRevision&newRevision=$revision", "entry=$encodePath"), $this->lang->repo->diffAB) : '';
}
$changes[$path] = $change;
}
$root = $this->repo->decodePath($root);
$parent = '';
if($type == 'file')
{
$parent = $this->dao->select('parent')->from(TABLE_REPOFILES)
->where('revision')->eq($history->id)
->andWhere('path')->eq('/' . $root)
->fetch('parent');
}
$this->view->title = $this->lang->repo->common;
$this->view->log = $log[0];
$this->view->repo = $repo;
$this->view->path = $root;
$this->view->type = $type;
$this->view->changes = $changes;
$this->view->repoID = $repoID;
$this->view->revision = $log[0]->revision;
$this->view->parentDir = $parent;
$this->view->oldRevision = $oldRevision;
$this->view->preAndNext = $this->repo->getPreAndNext($repo, $root, $revision, $type, 'revision');
$this->display();
}
/**
* Show diff.
*
* @param int $repoID
* @param string $entry
* @param string $oldRevision
* @param string $newRevision
* @param string $showBug
* @param string $encoding
* @access public
* @return void
*/
public function diff($repoID, $entry = '', $oldRevision = '0', $newRevision = 'HEAD', $showBug = 'false', $encoding = '')
{
if($this->get->entry) $entry = $this->get->entry;
$this->repo->setMenu($this->repos, $repoID);
if($repoID == 0) $repoID = $this->session->repoID;
$file = $entry;
$repo = $this->repo->getRepoByID($repoID);
$entry = $this->repo->decodePath($entry);
$pathInfo = pathinfo($entry);
$suffix = '';
if(isset($pathInfo["extension"])) $suffix = strtolower($pathInfo["extension"]);
$arrange = $this->cookie->arrange ? $this->cookie->arrange : 'inline';
if(!empty($_POST))
{
$oldRevision = isset($this->post->revision[1]) ?$this->post->revision[1] : '';
$newRevision = isset($this->post->revision[0]) ?$this->post->revision[0] : '';
if($this->post->arrange)
{
$arrange = $this->post->arrange;
setcookie('arrange', $arrange);
}
if($this->post->encoding) $encoding = $this->post->encoding;
if(!$oldRevision)
{
echo js::alert($this->lang->repo->error->diff);
die(js::locate('back'));
}
}
$this->scm->setEngine($repo);
$encoding = empty($encoding) ? $repo->encoding : $encoding;
$encoding = strtolower(str_replace('_', '-', $encoding));
$info = $this->scm->info($entry, $newRevision);
$diffs = $this->scm->diff($entry, $oldRevision, $newRevision);
foreach($diffs as $diff)
{
if($encoding != 'utf-8')
{
$diff->fileName = helper::convertEncoding($diff->fileName, $encoding);
if(empty($diff->contents)) continue;
foreach($diff->contents as $content)
{
if(empty($content->lines)) continue;
foreach($content->lines as $lines)
{
if(empty($lines->line)) continue;
$lines->line = helper::convertEncoding($lines->line, $encoding);
}
}
}
}
/* When arrange is appose then adjust data for show them easy.*/
if($arrange == 'appose')
{
foreach($diffs as $diffFile)
{
if(empty($diffFile->contents)) continue;
foreach($diffFile->contents as $content)
{
$old = array();
$new = array();
foreach($content->lines as $line)
{
if($line->type != 'new') $old[$line->oldlc] = $line->line;
if($line->type != 'old') $new[$line->newlc] = $line->line;
}
$content->old = $old;
$content->new = $new;
}
}
}
$this->view->title = $this->lang->repo->common . $this->lang->colon . $this->lang->repo->diff;
$this->view->position[] = $this->lang->repo->diff;
$this->view->type = 'diff';
$this->view->showBug = $showBug;
$this->view->entry = urldecode($entry);
$this->view->suffix = $suffix;
$this->view->file = $file;
$this->view->repoID = $repoID;
$this->view->repo = $repo;
$this->view->encoding = str_replace('-', '_', $encoding);
$this->view->arrange = $arrange;
$this->view->diffs = $diffs;
$this->view->newRevision = $newRevision;
$this->view->oldRevision = $oldRevision;
$this->view->revision = $newRevision;
$this->view->historys = $repo->SCM == 'Git' ? $this->dao->select('revision,commit')->from(TABLE_REPOHISTORY)->where('revision')->in("$oldRevision,$newRevision")->andWhere('repo')->eq($repo->id)->fetchPairs() : '';
$this->view->info = $info;
$this->display();
}
/**
* Download repo file.
*
* @param int $repoID
* @param string $path
* @param string $fromRevision
* @param string $toRevision
* @param string $type
* @access public
* @return void
*/
public function download($repoID, $path, $fromRevision = 'HEAD', $toRevision = '', $type = 'file')
{
if($this->get->path) $path = $this->get->path;
$entry = $this->repo->decodePath($path);
$repo = $this->repo->getRepoByID($repoID);
$this->scm->setEngine($repo);
$content = $type == 'file' ? $this->scm->cat($entry, $fromRevision) : $this->scm->diff($entry, $fromRevision, $toRevision, 'patch');
$fileName = basename(urldecode($entry));
if($type != 'file') $fileName .= "r$fromRevision--r$toRevision.patch";
$extension = ltrim(strrchr($fileName, '.'), '.');
$this->fetch('file', 'sendDownHeader', array("fileName" => $fileName, "fileType" => $extension, "content" => $content));
}
/**
* Show sync comment.
*
* @param int $repoID
* @access public
* @return void
*/
public function showSyncComment($repoID = 0)
{
$this->repo->setMenu($this->repos, $repoID);
if($repoID == 0) $repoID = $this->session->repoID;
$this->view->title = $this->lang->repo->common . $this->lang->colon . $this->lang->repo->showSyncComment;
$this->view->position[] = $this->lang->repo->showSyncComment;
$latestInDB = $this->repo->getLatestComment($repoID);
$this->view->version = $latestInDB ? (int)$latestInDB->commit : 1;
$this->view->repoID = $repoID;
$this->display();
}
/**
* Ajax sync comment.
*
* @param int $repoID
* @param string $type
* @access public
* @return void
*/
public function ajaxSyncComment($repoID = 0, $type = 'batch')
{
set_time_limit(0);
$repo = $this->repo->getRepoByID($repoID);
if(empty($repo)) die();
if($repo->synced) die('finish');
$this->scm->setEngine($repo);
$branchID = '';
if($repo->SCM == 'Git' and empty($branchID))
{
$branches = $this->scm->branch();
if($branches)
{
/* Init branchID. */
if($this->cookie->syncBranch) $branchID = $this->cookie->syncBranch;
if(!isset($branches[$branchID])) $branchID = '';
if(empty($branchID)) $branchID = reset($branches);
/* Get unsynced branches. */
foreach($branches as $branch)
{
unset($branches[$branch]);
if($branch == $branchID)
{
$this->repo->setRepoBranch($branchID);
setcookie("syncBranch", $branchID, 0, $this->config->webRoot);
break;
}
}
}
}
$latestInDB = $this->dao->select('DISTINCT t1.*')->from(TABLE_REPOHISTORY)->alias('t1')
->leftJoin(TABLE_REPOBRANCH)->alias('t2')->on('t1.id=t2.revision')
->where('t1.repo')->eq($repoID)
->beginIF($repo->SCM == 'Git' and $this->cookie->repoBranch)->andWhere('t2.branch')->eq($this->cookie->repoBranch)->fi()
->orderBy('t1.time')
->limit(1)
->fetch();
$version = empty($latestInDB) ? 1 : $latestInDB->commit + 1;
$logs = array();
$revision = $version == 1 ? 'HEAD' : ($repo->SCM == 'Git' ? $latestInDB->commit : $latestInDB->revision);
if($type == 'batch')
{
$logs = $this->scm->getCommits($revision, $this->config->repo->batchNum, $branchID);
}
else
{
$logs = $this->scm->getCommits($revision, 0, $branchID);
}
$commitCount = $this->repo->saveCommit($repoID, $logs, $version, $branchID);
if(empty($commitCount))
{
if(!$repo->synced)
{
if($repo->SCM == 'Git')
{
if($branchID) $this->repo->saveExistsLogBranch($repo->id, $branchID);
$branchID = reset($branches);
setcookie("syncBranch", $branchID, 0, $this->config->webRoot);
if($branchID) $this->repo->fixCommit($repoID);
}
if(empty($branchID))
{
$this->repo->markSynced($repoID);
die('finish');
}
}
}
$this->dao->update(TABLE_REPO)->set('commits=commits + ' . $commitCount)->where('id')->eq($repoID)->exec();
echo $type == 'batch' ? $commitCount : 'finish';
}
/**
* Ajax show side logs.
*
* @param int $repoID
* @param string $path
* @param string $type
* @param int $recTotal
* @param int $recPerPage
* @param int $pageID
* @access public
* @return void
*/
public function ajaxSideLogs($repoID, $path, $type = 'dir', $recTotal = 0, $recPerPage = 8, $pageID = 1)
{
if($this->get->path) $path = $this->get->path;
$this->app->loadClass('pager', $static = true);
$pager = new pager($recTotal, $recPerPage, $pageID);
$repo = $this->repo->getRepoByID($repoID);
$path = $this->repo->decodePath($path);
$commiters = $this->loadModel('user')->getCommiters();
$revisions = $this->repo->getLogs($repo, $path, 'HEAD', $type, $pager);
foreach($revisions as $revision) $revision->committer = zget($commiters, $revision->committer, $revision->committer);
$this->view->repo = $this->repo->getRepoByID($repoID);
$this->view->revisions = $revisions;
$this->view->pager = $pager;
$this->view->repoID = $repoID;
$this->view->logType = $type;
$this->view->path = urldecode($path);
$this->display();
}
/**
* Ajax get committer.
*
* @param int $repoID
* @param string $entry
* @param int $revision
* @param int $line
* @access public
* @return void
*/
public function ajaxGetCommitter($repoID, $entry, $revision, $line)
{
if($this->get->entry) $entry = $this->get->entry;
$repo = $this->repo->getRepoByID($repoID);
$entry = $this->repo->decodePath($entry);
$this->scm->setEngine($repo);
$blames = $this->scm->blame($entry, $revision);
$committer = '';
while($line > 0)
{
if(isset($blames[$line]['committer']))
{
$committer = $blames[$line]['committer'];
break;
}
$line--;
}
die($committer);
}
}
+179
View File
@@ -0,0 +1,179 @@
a{color:#169;}
a:hover, a:active{ text-decoration:underline; color:#C61A1A;}
h2,h3 {font-size:20px; padding:0 0 10px; margin: 0; clear: both;}
h3 {font-size:16px;}
.revision{font-size:12px; line-height:20px; text-align:right; padding-right:8px;}
.directory{ background-image:url('theme/default/images/repo/dir.png')}
.file{ background-image:url('theme/default/images/repo/txt.png')}
//.icon{ width:17px; padding-left:10px; padding-right:2px;}
.mini-icon{ display: inline-block; height: 16px; width: 16px; background-color: transparent; background-position: 0 0; background-repeat: no-repeat; vertical-align: text-bottom;}
.action {float:left;}
.input-group select#encrypt{border-left:0px;}
.arrange {float:right;}
.versions {position:relative}
#diffRepo {position:absolute; left:20px;z-index:1000;}
#repoID {display: inline-block; width: auto;}
.repoCode a:hover{text-decoration:none;}
.commentButton
{
background-repeat: no-repeat;
position: absolute;
left: -28px;
width: 40px;
z-index: 10;
cursor:pointer;
font-size:18px;
color:#4183C4;
display: none;
}
.repoCode tr.over .commentButton {display: block;}
.bug
{
background-repeat: no-repeat;
position: absolute;
left: -7px;
width: 20px;
z-index: 0;
cursor:pointer;
font-size:18px;
color: #4183C4;
line-height: 18px;
}
.repoCode .icon{opacity:1;}
.icon-comment-add:before {content: '\e74c'; transform: scale(-1, 1); display: inline-block; font-weight: normal;}
.icon-comment-add:after {content: '+'; display: block; font-weight: normal; position: absolute; left: 16px; top: 1px; font-family: Arial; font-weight: bold; font-size: 12px;}
.icon-comments:before {content: '\e750'; transform: scale(-1, 1); display: inline-block; font-weight: normal; font-size: 18px; line-height: 18px;}
.commentButton:hover,.bug:hover{color: #d20b0b;}
.commentBoard{border-top: 1px solid #E4E4E4; border-bottom: 1px solid #E4E4E4; padding:0; white-space:normal; background-color:#eee; padding: 10px;}
.commentBoard .table-form th {background: none}
.lines input{width:40px;}
.commentSubmit, .commentCancel{margin-right:10px;}
.commentFoot .optional{float:left;}
.commentBoard.using .bugContainer {border: 1px solid #ddd; background: #fff}
.commentBoard.using .bugContainer > .commentHeader {background: #f1f1f1; padding: 0 10px; border-bottom: 1px solid #ddd}
.commentHeaderAuthor{max-width: 600px; line-height: 33px; font-weight: bold; color: #222; overflow: hidden; white-space: nowrap; text-overflow: ellipsis;}
.comment{width:100%; word-break:keep-all; white-space:nowrap; overflow:hidden; text-overflow:ellipsis;}
.commentContent{margin:10px;}
.commentHeaderRight{float:right;}
/* Sider */
#mainContent > #sidebar > .side-body.affix {top:0px; z-index:10000;}
/* Pre row */
.repoCode table > tbody > tr.over td {background: #f8eec7;}
.repoCode table > tbody > tr.over th {background: #cdcdcd; color: #333}
/* Comment-btn */
.comment-btn {position: relative; margin: 0; padding: 0; display: none}
.repoCode tr.over .comment-btn {display: block;}
.comment-btn .icon-wrapper {display: block; position: absolute; background: #4183C4; border-radius: 2px; width: 24px; height: 20px; left: -6px; top: 0; line-height: 20px; text-align: center; color: #fff; cursor: pointer; transition: transform 0.2s;}
.comment-btn .icon-wrapper:before {display: block; content: ' '; right: -4px; top: 6px; position: absolute; border-left: 4px solid #4183C4; border-right: 0 solid transparent; border-bottom: 4px solid transparent; border-top: 4px solid transparent; width: 0; height: 0}
.comment-btn .icon-wrapper:hover {background: #169; transform: scale(1.1)}
.comment-btn .icon-wrapper:hover:before {border-left-color: #169}
.repoCode tr.commented {cursor: pointer;}
.repoCode tr.commented .comment-btn {display: block;}
.repoCode tr.commented .comment-btn .icon-wrapper {background: none; border: none; width: 24px; line-height: 18px; height: 18px; left: -6px; color: #4183c4}
.repoCode tr.commented .comment-btn .icon-wrapper:hover {border-color: #169; color: #169}
.repoCode tr.commented .comment-btn .icon-wrapper > i:before {content: '\e750'; font-size: 18px; transform: scale(-1, 1); display: inline-block;}
.repoCode tr.commented .comment-btn .icon-wrapper:before {display: none}
.repoCode tr.over.commented .comment-btn .icon-wrapper, .repoCode tr.selected.commented .comment-btn .icon-wrapper {line-height: 20px; height: 20px; background: #4183C4; color: #fff; left: -6px}
.repoCode tr.over.commented .comment-btn .icon-wrapper > i:before {content: "\e661"; font-size: 14px;}
.repoCode tr.selected.commented .comment-btn .icon-wrapper > i:before {font-size: 14px;}
.repoCode tr.over.commented .comment-btn .icon-wrapper:before, .repoCode tr.selected.commented .comment-btn .icon-wrapper:before {display: block;}
/* repo action form */
.repoCode .comment-list, .repoCode .comment-actions {max-width: 900px}
.repoCode .bugFormContainer {border: 1px solid #bbb; margin: 0 0 0 15px; padding: 10px 20px 10px 10px; max-width: 880px; background: #fff}
.repoCode .bugFormContainer th {width: 70px}
.repoCode .action-row {display: none}
.repoCode .with-action-row .action-row {display: table-row}
.repoCode .action-cell {background: #EEE; white-space: normal; padding: 10px 15px 10px 0;}
.repoCode .with-action-row table tr.selected .comment-btn:last-child {display: block;}
.repoCode .with-action-row table tr.selected td {background: #f8eec7}
.repoCode .with-action-row table tr.selected th {background: #cdcdcd}
.repoCode .with-action-row table tr.selected .comment-btn .icon-wrapper > i:before, .repoCode #diff.with-action-row tr.selected .comment-btn .icon-wrapper > i:before {content: '\d7'}
.repoCode .comment-row {display: none}
.repoCode .comment-row.show {display: table-row !important;}
.repoCode .comment-cell {background: #eee; white-space: normal;}
.repoCode .comment-cell .panel {margin: 10px; border-color: #bbb}
.repoCode .comment-cell .panel-body {padding: 6px 10px}
.repoCode .comment-cell .panel-actions.pull-right {margin-right: 0; margin-top: 0;}
.repoCode .comment-cell .editing .panel-body, .repoCode .comment-cell .commentContainer.show-form .panel-body {display: none}
.repoCode .comment-cell .bug-edit-form, {padding: 10px; display: none}
.repoCode .comment-cell .editing .bug-edit-form, .repoCode .comment-cell .commentContainer.show-form .comment-edit-form {display: block;}
.repoCode .comment {border: 1px solid #e5e5e5; background: #fafafa; padding: 5px 10px; margin-bottom: 10px;}
.repoCode .comment .comment-edit-form {margin-top: 10px;}
.repoCode .panel-bug .steps {background: #f1f1f1; padding: 5px 10px}
.repoCode .panel-bug .bug-edit-form {margin-bottom: 10px;}
.repoCode .panel-bug .panel-body {display: none}
.repoCode .panel-bug .panel-heading {cursor: pointer;}
.repoCode .panel-bug.show .panel-body {display: block;}
.repoCode .panel-bug.show .icon-chevron-sign-down:before {content: '\e711'}
.repoCode .panel-bug.show-edit-form .bug-edit-form,
.repoCode .panel-bug.show-form .commentForm,
.repoCode .comment.show-form .comment-edit-form {display: block;}
.repoCode .panel-bug .bug-edit-form,
.repoCode .panel-bug.show-form .addComment,
.repoCode .panel-bug .commentForm,
.repoCode .comment .comment-edit-form,
.repoCode .panel-bug.show-edit-form .panel-body .title,
.repoCode .panel-bug.show-edit-form .bug-date,
.repoCode .comment.show-form .comment-content, .repoCode .comment.show-form .comment-date {display: none}
.repoCode .text-content {white-space: normal; white-space: pre-line}
.repoCode .text-muted {color: #aaa}
.repoCode tr {transition: all 1s;}
.repoCode tr.highlight {background: #fff4e5;}
.repoCode tr.highlight td, .repoCode tr.highlight th {background: none; border-top: 1px solid #e48600; border-bottom: 1px solid #e48600}
.repoCode tr.highlight.commented th {color: #e48600;}
.repoCode tr.highlight.commented td, .repoCode tr.highlight.commented th {border-bottom: none}
.repoCode tr.highlight + tr.highlight td, .repoCode tr.highlight + tr.highlight th {border-top: none}
.repoCode .row-tip {display: none;}
.repoCode tr.commented .row-tip {display: block; position: relative; right: -3px; bottom: -1px;}
.repoCode tr.commented .tip, .repoCode tr.commented.open .tip.on-collapse {display: block; position: absolute; right: 0; bottom: 0; color: #4183c4; opacity: 0; padding:0 5px; background: #edf3ff; height: 20px; line-height: 20px; transition: opacity 0.2s;}
.repoCode tr.commented:hover .tip.on-expand {opacity: 1}
.repoCode tr.commented.open .tip.on-collapse {opacity: 1}
.repoCode tr.commented.open .tip.on-expand {display: none}
.repoCode tr.commented.open .tip.on-collapse span {display: none}
.repoCode tr.commented.open:hover .tip.on-collapse span {display: inline;}
.repoCode tr.commented.open {background: #f8fafe}
.repoCode tr.commented .preview-icon {position: absolute; left: -6px; bottom: 0; width: 20px; height: 20px; line-height: 20px; text-align: center; color: #4183c4; background: #edf3ff; display: none}
.repoCode tr.commented:hover .preview-icon {display: block; transform: scale(-1, 1);}
.repoCode tr.commented .preview-icon:before {font-size: 18px;}
.repoCode #diff tr.commented .row-tip {right: 0}
.repoCode #diff tr.commented .icon-chat-dot {left: 0}
.repoCode .panel, .bugFormContainer {transition: border 0.4s;}
.repoCode .panel.highlight, #bugForm.highlight .bugFormContainer {border-color: #e48600;}
#bugsPreview {white-space: normal;}
#bugsPreview .dropdown-menu {top: -100%; left: 30%; padding-top: 0; min-width: 300px; max-width: 500px;}
#bugsPreview .dropdown-menu > li.dropdown-header {background: #f1f1f1; padding-top: 8px;}
#bugsPreview .dropdown-menu > li > a {border-top: 1px solid #e5e5e5; text-overflow : ellipsis; overflow: hidden;}
#bugsPreview .dropdown-menu.show {display: block;}
.icon-comments {position: relative; left: -50px}
/* bug form */
#bugForm, #bugForm table {margin: 0; padding: 0;}
.panel .table + .panel-footer {border-top: 0; background: #fff}
.transparent{ border-color:transparent;background: none repeat scroll 0 0 transparent;}
.transparent:hover{ border-color:transparent;background: none repeat scroll 0 0 transparent;}
.side-col{width: 600px;}
#sidebar > .side-body{width: 580px;}
.hide-sidebar #sidebar > .side-body{display: none;}
#sidebar>.sidebar-toggle{left:5px; right:auto;}
#sidebar>.sidebar-toggle>.icon{right:-4px; left:auto;}
+22
View File
@@ -0,0 +1,22 @@
body{padding-bottom:0px;}
.w-code{ width:48%; word-break: break-all;}
td.code { color:#484848; padding:0px 3px; white-space: pre-wrap}
.none {background:#EAF2F5;}
table.diff {margin-bottom:0px;}
.diff caption{ border: 1px solid #e4e4e4; background: #edf3fe; margin: 0; padding: 6px 2px 6px 10px; text-align: left; font-weight: bold; font-size: 13px;}
.diff th, .diff td{ border:none;}
.diff th{ padding-top:2px; padding-bottom:2px;}
.diff .line-new, .diff .line-new { background:#CFC;}
.diff .line-old, .diff .line-old { background:#FCC;}
.diff .line-all, .diff .line-all { background:#FFF;}
.diff .w-num { width:25px; border-right:1px solid #E4E4E4; color:#999; border-left:1px solid #E4E4E4; color:#999; font-weight:normal;}
.repoCode .diff tr .comment-btn .icon-wrapper {left: -23px;}
.repoCode .diff tr.over td.line-all, .repoCode .diff tr.over td.line-all {background: #f8eec7}
.repoCode .diff tr.over td.line-new, .repoCode .diff tr.over td.line-new {background: #8eff8e}
.repoCode .diff tr.over td.line-old, .repoCode .diff tr.over td.line-old {background: #f6b2b2}
.repoCode form > .btn {margin-right: 10px;}
.label-exchange {background-color: #566F7C;cursor: pointer}
.label-exchange i{padding:0;}
.btn-download{border-right: none;}
+3
View File
@@ -0,0 +1,3 @@
.change ul{margin:8px;margin-left:1.5em;}
.change li{ list-style:none;}
.panel-heading {border-bottom: 1px solid #ddd;}
+14
View File
@@ -0,0 +1,14 @@
.code {position:relative; padding:3px; border-radius:3px;}
.code .content {border:1px solid #CCC; padding:0;}
.repoCode pre {margin:0;padding:0;background:white; border:none;}
tr,th,td {border-bottom:none;}
.repoCode pre > table > tbody > tr > th {border: none; background-color:#ECECEC; width: 40px; text-align:right; vertical-align: top;}
.repoCode pre > table > tbody > tr > th, .repoCode pre > table > tbody > tr > td {padding:1px 3px;}
.repoCode pre .commentContent{line-height:1.4;}
.repoCode pre > table{border:0px; width:100%;}
.repoCode .binary {text-align:center;}
.repoCode .binary a {display:block; margin:100px 0px;}
.repoCode .binary a .icon-download {font-size:50px;}
.repoCode .image {text-align:center; padding-top:10px;}
.panel .panel-heading .action .input-group {margin-top:-6px; margin-right:-10px;}
.body-modal .panel-actions {right:30px;}
+86
View File
@@ -0,0 +1,86 @@
/**
* Swtich repo.
*
* @param int $repoID
* @param string $module
* @param string $method
* @access public
* @return void
*/
function switchRepo(repoID, module, method)
{
if(typeof(eventKeyCode) == 'undefined') eventKeyCode = 0;
if(eventKeyCode > 0 && eventKeyCode != 13) return false;
/* The projec id is a string, use it as the project model. */
if(isNaN(repoID))
{
$.cookie('projectMode', repoID, {expires:config.cookieLife, path:config.webRoot});
repoID = 0;
}
if(method != 'settings') method ="browse";
link = createLink(module, method, 'repoID=' + repoID);
location.href=link;
}
/**
* Switch branch for git.
*
* @param string $branchID
* @access public
* @return void
*/
function switchBranch(branchID)
{
$.cookie('repoBranch', branchID, {expires:config.cookieLife, path:config.webRoot});
$.cookie('repoRefresh', 1, {expires:config.cookieLife, path:config.webRoot});
location.href=location.href;
}
/**
* Limit select two.
* @return void
*/
if($("input:checkbox[name='revision[]']:checked").length < 2)
{
$("input:checkbox[name='revision[]']:lt(2)").attr('checked', 'checked');
}
$("input:checkbox[name='revision[]']").each(function(){ if(!$(this).is(':checked')) $(this).attr("disabled","disabled")});
$("input:checkbox[name='revision[]']").click(function(){
var checkNum = $("input:checkbox[name='revision[]']:checked").length;
if (checkNum >= 2)
{
$("input:checkbox[name='revision[]']").each(function(){ if(!$(this).is(':checked')) $(this).attr("disabled","disabled")});
}
else
{
$("input:checkbox[name='revision[]']").each(function(){$(this).attr("disabled", false)});
}
});
$(function()
{
$(document).on('click', '.ajaxPager', function()
{
$('#sidebar .side-body').load($(this).attr('href'));
return false;
})
if($('#sidebar').size() > 0)
{
var fixH = $("#sidebar").offset().top;
$(window).scroll(function()
{
var scroH = $(this).scrollTop();
if(scroH>=fixH)
{
$("#sidebar > .side-body").addClass('affix');
}
else if(scroH<fixH)
{
$("#sidebar > .side-body").removeClass('affix');
}
});
}
})
+5
View File
@@ -0,0 +1,5 @@
function changeEncoding(encoding)
{
$('#encoding').val(encoding);
$('#encoding').parents('form').submit();
}
+18
View File
@@ -0,0 +1,18 @@
$(document).ready(function()
{
$("input:checkbox[name='revision[]']").each(function()
{
$(this).click(function()
{
var checkNum = $("input:checkbox[name='revision[]']:checked").length;
if (checkNum >= 2)
{
$("input:checkbox[name='revision[]']").each(function(){if($(this).attr('checked') == false) $(this).attr("disabled","disabled")});
}
else
{
$("input:checkbox[name='revision[]']").each(function(){if($(this).attr('checked') == false) $(this).attr("enabled","enabled")});
}
});
});
});
+19
View File
@@ -0,0 +1,19 @@
$(document).ready(function()
{
var $pre = $('.repoCode .content pre');
var rowTip = $('#rowTip').html();
if($pre.length)
{
hljs.initHighlightingOnLoad();
var content = hljs.highlight($pre.attr('class'), $pre.text());
var code = '', line;
var arr = content.value.split(/\r\n|[\n\v\f\r\x85\u2028\u2029]/);
for(var i = 0 ; i < arr.length ; i++)
{
line = i + 1;
code += "<tr data-line='" + line +"'><th id='L" + line + "'><div class='comment-btn view'><span class='icon-wrapper'><i class='icon-plus'></i></span></div>" + line + "</th><td>" + (arr[i] || '&nbsp;') + rowTip + "</td></tr>";
}
$pre.html("<table><tbody>" + code + "</tbody></table>");
}
});
+150
View File
@@ -0,0 +1,150 @@
<?php
$lang->repo->common = 'Repo';
$lang->repo->create = 'Create Repo';
$lang->repo->settings = 'Settings';
$lang->repo->browse = 'View Repo';
$lang->repo->delete = 'Delete Repo';
$lang->repo->showSyncComment = 'Display Synchronization';
$lang->repo->ajaxSyncComment = 'Interface: Ajax Sync Note';
$lang->repo->download = 'Download File';
$lang->repo->downloadDiff = 'Download Diff';
$lang->repo->diffAction = 'Revision Diff';
$lang->repo->revisionAction = 'Revision Detail';
$lang->repo->blameAction = 'Repo Blame';
$lang->repo->addBug = 'Add Review';
$lang->repo->editBug = 'Edit Bug';
$lang->repo->deleteBug = 'Delete Bug';
$lang->repo->addComment = 'Add Comment';
$lang->repo->editComment = 'Edit Comment';
$lang->repo->deleteComment = 'Delete Comment';
$lang->repo->submit = 'Submit';
$lang->repo->cancel = 'Cancel';
$lang->repo->addComment = 'Add Comment';
$lang->repo->product = $lang->productCommon;
$lang->repo->module = 'Module';
$lang->repo->project = $lang->projectCommon;
$lang->repo->type = 'Type';
$lang->repo->assign = 'AssignTo';
$lang->repo->title = 'Title';
$lang->repo->detile = 'Detail';
$lang->repo->lines = 'Lines';
$lang->repo->line = 'Line';
$lang->repo->expand = 'Unfold';
$lang->repo->collapse = 'Fold';
$lang->repo->id = 'ID';
$lang->repo->SCM = 'Type';
$lang->repo->name = 'Name';
$lang->repo->path = 'Path';
$lang->repo->prefix = 'Prefix';
$lang->repo->config = 'Config';
$lang->repo->account = 'Username';
$lang->repo->password = 'Password';
$lang->repo->encoding = 'Encoding';
$lang->repo->client = 'Client Path';
$lang->repo->size = 'Size';
$lang->repo->revision = 'Revision';
$lang->repo->revisionA = 'Revision';
$lang->repo->revisions = 'Revision';
$lang->repo->time = 'Date';
$lang->repo->committer = 'Committer';
$lang->repo->commits = 'Commits';
$lang->repo->synced = 'Initialize Sync';
$lang->repo->lastSync = 'Last Sync';
$lang->repo->deleted = 'Deleted';
$lang->repo->commit = 'Commit';
$lang->repo->comment = 'Comment';
$lang->repo->view = 'View File';
$lang->repo->viewA = 'View';
$lang->repo->log = 'Revision Log';
$lang->repo->blame = 'Blame';
$lang->repo->date = 'Date';
$lang->repo->diff = 'Diff';
$lang->repo->diffAB = 'Diff';
$lang->repo->diffAll = 'Diff All';
$lang->repo->viewDiff = 'View diff';
$lang->repo->allLog = 'All Revisions';
$lang->repo->location = 'Location';
$lang->repo->file = 'File';
$lang->repo->action = 'Action';
$lang->repo->code = 'Code';
$lang->repo->review = 'Repo Review';
$lang->repo->acl = 'Privilege';
$lang->repo->group = 'Group';
$lang->repo->user = 'User';
$lang->repo->info = 'Version Info';
$lang->repo->title = 'Title';
$lang->repo->status = 'Status';
$lang->repo->openedBy = 'CreatedBy';
$lang->repo->assignedTo = 'AssignedTo';
$lang->repo->openedDate = 'CreatedDate';
$lang->repo->latestRevision = 'Latest Revision';
$lang->repo->actionInfo = "Add by %s in %s";
$lang->repo->changes = "Change Log";
$lang->repo->reviewLocation = "File: %s@%s, line:%s - %s";
$lang->repo->commentEdit = '<i class="icon-pencil"></i>';
$lang->repo->commentDelete = '<i class="icon-remove"></i>';
$lang->repo->allChanges = "Other Changes";
$lang->repo->commitTitle = "The %sth Commit";
$lang->repo->viewDiffList['inline'] = 'Inline';
$lang->repo->viewDiffList['appose'] = 'Parallel';
$lang->repo->encryptList['plain'] = 'No encryption';
$lang->repo->encryptList['base64'] = 'BASE64';
$lang->repo->logStyles['A'] = 'Add';
$lang->repo->logStyles['M'] = 'Modification';
$lang->repo->logStyles['D'] = 'Delete';
$lang->repo->encodingList['utf_8'] = 'UTF-8';
$lang->repo->encodingList['gbk'] = 'GBK';
$lang->repo->scmList['Subversion'] = 'Subversion';
$lang->repo->scmList['Git'] = 'Git';
$lang->repo->notice = new stdclass();
$lang->repo->notice->syncing = 'Synchronizing. Please wait ...';
$lang->repo->notice->syncComplete = 'Synchronized. Now redirecting ...';
$lang->repo->notice->syncedCount = 'The number of records synchronized is ';
$lang->repo->notice->delete = 'Are you sure delete this repo?';
$lang->repo->notice->successDelete = 'Repository is removed.';
$lang->repo->notice->commentContent = 'Comment';
$lang->repo->notice->deleteBug = 'Are you sure to delete this bug?';
$lang->repo->notice->deleteComment = 'Are you sure to delete this comment?';
$lang->repo->notice->lastSyncTime = 'Last Sync:';
$lang->repo->error = new stdclass();
$lang->repo->error->useless = 'Your server disabled exec and shell_exec, so it cannot be applied.';
$lang->repo->error->connect = 'Connection to the repo failed. Please enter username, password and repo address correctly!';
$lang->repo->error->version = 'Version 1.8+ of https and svn protocol is required. Please update to latest version! Go to http://subversion.apache.org/';
$lang->repo->error->path = 'Repo address is the file path, e.g. /home/test.';
$lang->repo->error->cmd = 'Client Error!';
$lang->repo->error->diff = 'Two versions must be selected.';
$lang->repo->error->product = "Please select {$lang->productCommon}!";
$lang->repo->error->commentText = 'Please enter content for review!';
$lang->repo->error->comment = 'Please enter content!';
$lang->repo->error->title = 'Please enter title!';
$lang->repo->error->accessDenied = 'You do not have the privilege to access the repository.';
$lang->repo->error->noFound = 'The repo is not found.';
$lang->repo->error->noFile = '%s does not exist.';
$lang->repo->error->noPriv = 'The program does not have the privilege to switch to %s';
$lang->repo->error->output = "The command is: %s\nThe error is(%s): %s\n";
$lang->repo->error->clientVersion = "Client version is too low, please upgrade or change SVN client";
$lang->repo->error->encoding = "The encoding maybe wrong. Please change the encoding and try again.";
$lang->repo->example = new stdclass();
$lang->repo->example->client = "For example, /usr/bin/svn, C:\subversion\svn.exe, /usr/bin/git";
$lang->repo->example->path = "For example, SVN: http://example.googlecode.com/svn/, GIT: /home/test";
$lang->repo->example->config = "Config directory is required in https. Use '--config-dir' to generate config dir.";
$lang->repo->example->encoding = "input encoding of files";
$lang->repo->typeList['standard'] = 'Standard';
$lang->repo->typeList['performance'] = 'Performance';
$lang->repo->typeList['security'] = 'Security';
$lang->repo->typeList['redundancy'] = 'Redundancy';
$lang->repo->typeList['logicError'] = 'Logic Error';
+150
View File
@@ -0,0 +1,150 @@
<?php
$lang->repo->common = 'Repo';
$lang->repo->create = 'Create Repo';
$lang->repo->settings = 'Settings';
$lang->repo->browse = 'View Repo';
$lang->repo->delete = 'Delete Repo';
$lang->repo->showSyncComment = 'Display Synchronization';
$lang->repo->ajaxSyncComment = 'Interface: Ajax Sync Note';
$lang->repo->download = 'Download File';
$lang->repo->downloadDiff = 'Download Diff';
$lang->repo->diffAction = 'Revision Diff';
$lang->repo->revisionAction = 'Revision Detail';
$lang->repo->blameAction = 'Repo Blame';
$lang->repo->addBug = 'Add Review';
$lang->repo->editBug = 'Edit Bug';
$lang->repo->deleteBug = 'Delete Bug';
$lang->repo->addComment = 'Add Comment';
$lang->repo->editComment = 'Edit Comment';
$lang->repo->deleteComment = 'Delete Comment';
$lang->repo->submit = 'Submit';
$lang->repo->cancel = 'Cancel';
$lang->repo->addComment = 'Add Comment';
$lang->repo->product = $lang->productCommon;
$lang->repo->module = 'Module';
$lang->repo->project = $lang->projectCommon;
$lang->repo->type = 'Type';
$lang->repo->assign = 'AssignTo';
$lang->repo->title = 'Title';
$lang->repo->detile = 'Detail';
$lang->repo->lines = 'Lines';
$lang->repo->line = 'Line';
$lang->repo->expand = 'Unfold';
$lang->repo->collapse = 'Fold';
$lang->repo->id = 'ID';
$lang->repo->SCM = 'Type';
$lang->repo->name = 'Name';
$lang->repo->path = 'Path';
$lang->repo->prefix = 'Prefix';
$lang->repo->config = 'Config';
$lang->repo->account = 'Username';
$lang->repo->password = 'Password';
$lang->repo->encoding = 'Encoding';
$lang->repo->client = 'Client Path';
$lang->repo->size = 'Size';
$lang->repo->revision = 'Revision';
$lang->repo->revisionA = 'Revision';
$lang->repo->revisions = 'Revision';
$lang->repo->time = 'Date';
$lang->repo->committer = 'Committer';
$lang->repo->commits = 'Commits';
$lang->repo->synced = 'Initialize Sync';
$lang->repo->lastSync = 'Last Sync';
$lang->repo->deleted = 'Deleted';
$lang->repo->commit = 'Commit';
$lang->repo->comment = 'Comment';
$lang->repo->view = 'View File';
$lang->repo->viewA = 'View';
$lang->repo->log = 'Revision Log';
$lang->repo->blame = 'Blame';
$lang->repo->date = 'Date';
$lang->repo->diff = 'Diff';
$lang->repo->diffAB = 'Diff';
$lang->repo->diffAll = 'Diff All';
$lang->repo->viewDiff = 'View diff';
$lang->repo->allLog = 'All Revisions';
$lang->repo->location = 'Location';
$lang->repo->file = 'File';
$lang->repo->action = 'Action';
$lang->repo->code = 'Code';
$lang->repo->review = 'Repo Review';
$lang->repo->acl = 'Privilege';
$lang->repo->group = 'Group';
$lang->repo->user = 'User';
$lang->repo->info = 'Version Info';
$lang->repo->title = 'Title';
$lang->repo->status = 'Status';
$lang->repo->openedBy = 'CreatedBy';
$lang->repo->assignedTo = 'AssignedTo';
$lang->repo->openedDate = 'CreatedDate';
$lang->repo->latestRevision = 'Latest Revision';
$lang->repo->actionInfo = "Add by %s in %s";
$lang->repo->changes = "Change Log";
$lang->repo->reviewLocation = "File: %s@%s, line:%s - %s";
$lang->repo->commentEdit = '<i class="icon-pencil"></i>';
$lang->repo->commentDelete = '<i class="icon-remove"></i>';
$lang->repo->allChanges = "Other Changes";
$lang->repo->commitTitle = "The %sth Commit";
$lang->repo->viewDiffList['inline'] = 'Inline';
$lang->repo->viewDiffList['appose'] = 'Parallel';
$lang->repo->encryptList['plain'] = 'No encryption';
$lang->repo->encryptList['base64'] = 'BASE64';
$lang->repo->logStyles['A'] = 'Add';
$lang->repo->logStyles['M'] = 'Modification';
$lang->repo->logStyles['D'] = 'Delete';
$lang->repo->encodingList['utf_8'] = 'UTF-8';
$lang->repo->encodingList['gbk'] = 'GBK';
$lang->repo->scmList['Subversion'] = 'Subversion';
$lang->repo->scmList['Git'] = 'Git';
$lang->repo->notice = new stdclass();
$lang->repo->notice->syncing = 'Synchronizing. Please wait ...';
$lang->repo->notice->syncComplete = 'Synchronized. Now redirecting ...';
$lang->repo->notice->syncedCount = 'The number of records synchronized is ';
$lang->repo->notice->delete = 'Are you sure delete this repo?';
$lang->repo->notice->successDelete = 'Repository is removed.';
$lang->repo->notice->commentContent = 'Comment';
$lang->repo->notice->deleteBug = 'Are you sure to delete this bug?';
$lang->repo->notice->deleteComment = 'Are you sure to delete this comment?';
$lang->repo->notice->lastSyncTime = 'Last Sync:';
$lang->repo->error = new stdclass();
$lang->repo->error->useless = 'Your server disabled exec and shell_exec, so it cannot be applied.';
$lang->repo->error->connect = 'Connection to the repo failed. Please enter username, password and repo address correctly!';
$lang->repo->error->version = 'Version 1.8+ of https and svn protocol is required. Please update to latest version! Go to http://subversion.apache.org/';
$lang->repo->error->path = 'Repo address is the file path, e.g. /home/test.';
$lang->repo->error->cmd = 'Client Error!';
$lang->repo->error->diff = 'Two versions must be selected.';
$lang->repo->error->product = "Please select {$lang->productCommon}!";
$lang->repo->error->commentText = 'Please enter content for review!';
$lang->repo->error->comment = 'Please enter content!';
$lang->repo->error->title = 'Please enter title!';
$lang->repo->error->accessDenied = 'You do not have the privilege to access the repository.';
$lang->repo->error->noFound = 'The repo is not found.';
$lang->repo->error->noFile = '%s does not exist.';
$lang->repo->error->noPriv = 'The program does not have the privilege to switch to %s';
$lang->repo->error->output = "The command is: %s\nThe error is(%s): %s\n";
$lang->repo->error->clientVersion = "Client version is too low, please upgrade or change SVN client";
$lang->repo->error->encoding = "The encoding maybe wrong. Please change the encoding and try again.";
$lang->repo->example = new stdclass();
$lang->repo->example->client = "For example, /usr/bin/svn, C:\subversion\svn.exe, /usr/bin/git";
$lang->repo->example->path = "For example, SVN: http://example.googlecode.com/svn/, GIT: /home/test";
$lang->repo->example->config = "Config directory is required in https. Use '--config-dir' to generate config dir.";
$lang->repo->example->encoding = "input encoding of files";
$lang->repo->typeList['standard'] = 'Standard';
$lang->repo->typeList['performance'] = 'Performance';
$lang->repo->typeList['security'] = 'Security';
$lang->repo->typeList['redundancy'] = 'Redundancy';
$lang->repo->typeList['logicError'] = 'Logic Error';
+150
View File
@@ -0,0 +1,150 @@
<?php
$lang->repo->common = 'Repo';
$lang->repo->create = 'Create Repo';
$lang->repo->settings = 'Settings';
$lang->repo->browse = 'View Repo';
$lang->repo->delete = 'Delete Repo';
$lang->repo->showSyncComment = 'Display Synchronization';
$lang->repo->ajaxSyncComment = 'Interface: Ajax Sync Note';
$lang->repo->download = 'Download File';
$lang->repo->downloadDiff = 'Download Diff';
$lang->repo->diffAction = 'Revision Diff';
$lang->repo->revisionAction = 'Revision Detail';
$lang->repo->blameAction = 'Repo Blame';
$lang->repo->addBug = 'Add Review';
$lang->repo->editBug = 'Edit Bug';
$lang->repo->deleteBug = 'Delete Bug';
$lang->repo->addComment = 'Add Comment';
$lang->repo->editComment = 'Edit Comment';
$lang->repo->deleteComment = 'Delete Comment';
$lang->repo->submit = 'Submit';
$lang->repo->cancel = 'Cancel';
$lang->repo->addComment = 'Add Comment';
$lang->repo->product = $lang->productCommon;
$lang->repo->module = 'Module';
$lang->repo->project = $lang->projectCommon;
$lang->repo->type = 'Type';
$lang->repo->assign = 'AssignTo';
$lang->repo->title = 'Title';
$lang->repo->detile = 'Detail';
$lang->repo->lines = 'Lines';
$lang->repo->line = 'Line';
$lang->repo->expand = 'Unfold';
$lang->repo->collapse = 'Fold';
$lang->repo->id = 'ID';
$lang->repo->SCM = 'Type';
$lang->repo->name = 'Name';
$lang->repo->path = 'Path';
$lang->repo->prefix = 'Prefix';
$lang->repo->config = 'Config';
$lang->repo->account = 'Username';
$lang->repo->password = 'Password';
$lang->repo->encoding = 'Encoding';
$lang->repo->client = 'Client Path';
$lang->repo->size = 'Size';
$lang->repo->revision = 'Revision';
$lang->repo->revisionA = 'Revision';
$lang->repo->revisions = 'Revision';
$lang->repo->time = 'Date';
$lang->repo->committer = 'Committer';
$lang->repo->commits = 'Commits';
$lang->repo->synced = 'Initialize Sync';
$lang->repo->lastSync = 'Last Sync';
$lang->repo->deleted = 'Deleted';
$lang->repo->commit = 'Commit';
$lang->repo->comment = 'Comment';
$lang->repo->view = 'View File';
$lang->repo->viewA = 'View';
$lang->repo->log = 'Revision Log';
$lang->repo->blame = 'Blame';
$lang->repo->date = 'Date';
$lang->repo->diff = 'Diff';
$lang->repo->diffAB = 'Diff';
$lang->repo->diffAll = 'Diff All';
$lang->repo->viewDiff = 'View diff';
$lang->repo->allLog = 'All Revisions';
$lang->repo->location = 'Location';
$lang->repo->file = 'File';
$lang->repo->action = 'Action';
$lang->repo->code = 'Code';
$lang->repo->review = 'Repo Review';
$lang->repo->acl = 'Privilege';
$lang->repo->group = 'Group';
$lang->repo->user = 'User';
$lang->repo->info = 'Version Info';
$lang->repo->title = 'Title';
$lang->repo->status = 'Status';
$lang->repo->openedBy = 'CreatedBy';
$lang->repo->assignedTo = 'AssignedTo';
$lang->repo->openedDate = 'CreatedDate';
$lang->repo->latestRevision = 'Latest Revision';
$lang->repo->actionInfo = "Add by %s in %s";
$lang->repo->changes = "Change Log";
$lang->repo->reviewLocation = "File: %s@%s, line:%s - %s";
$lang->repo->commentEdit = '<i class="icon-pencil"></i>';
$lang->repo->commentDelete = '<i class="icon-remove"></i>';
$lang->repo->allChanges = "Other Changes";
$lang->repo->commitTitle = "The %sth Commit";
$lang->repo->viewDiffList['inline'] = 'Inline';
$lang->repo->viewDiffList['appose'] = 'Parallel';
$lang->repo->encryptList['plain'] = 'No encryption';
$lang->repo->encryptList['base64'] = 'BASE64';
$lang->repo->logStyles['A'] = 'Add';
$lang->repo->logStyles['M'] = 'Modification';
$lang->repo->logStyles['D'] = 'Delete';
$lang->repo->encodingList['utf_8'] = 'UTF-8';
$lang->repo->encodingList['gbk'] = 'GBK';
$lang->repo->scmList['Subversion'] = 'Subversion';
$lang->repo->scmList['Git'] = 'Git';
$lang->repo->notice = new stdclass();
$lang->repo->notice->syncing = 'Synchronizing. Please wait ...';
$lang->repo->notice->syncComplete = 'Synchronized. Now redirecting ...';
$lang->repo->notice->syncedCount = 'The number of records synchronized is ';
$lang->repo->notice->delete = 'Are you sure delete this repo?';
$lang->repo->notice->successDelete = 'Repository is removed.';
$lang->repo->notice->commentContent = 'Comment';
$lang->repo->notice->deleteBug = 'Are you sure to delete this bug?';
$lang->repo->notice->deleteComment = 'Are you sure to delete this comment?';
$lang->repo->notice->lastSyncTime = 'Last Sync:';
$lang->repo->error = new stdclass();
$lang->repo->error->useless = 'Your server disabled exec and shell_exec, so it cannot be applied.';
$lang->repo->error->connect = 'Connection to the repo failed. Please enter username, password and repo address correctly!';
$lang->repo->error->version = 'Version 1.8+ of https and svn protocol is required. Please update to latest version! Go to http://subversion.apache.org/';
$lang->repo->error->path = 'Repo address is the file path, e.g. /home/test.';
$lang->repo->error->cmd = 'Client Error!';
$lang->repo->error->diff = 'Two versions must be selected.';
$lang->repo->error->product = "Please select {$lang->productCommon}!";
$lang->repo->error->commentText = 'Please enter content for review!';
$lang->repo->error->comment = 'Please enter content!';
$lang->repo->error->title = 'Please enter title!';
$lang->repo->error->accessDenied = 'You do not have the privilege to access the repository.';
$lang->repo->error->noFound = 'The repo is not found.';
$lang->repo->error->noFile = '%s does not exist.';
$lang->repo->error->noPriv = 'The program does not have the privilege to switch to %s';
$lang->repo->error->output = "The command is: %s\nThe error is(%s): %s\n";
$lang->repo->error->clientVersion = "Client version is too low, please upgrade or change SVN client";
$lang->repo->error->encoding = "The encoding maybe wrong. Please change the encoding and try again.";
$lang->repo->example = new stdclass();
$lang->repo->example->client = "For example, /usr/bin/svn, C:\subversion\svn.exe, /usr/bin/git";
$lang->repo->example->path = "For example, SVN: http://example.googlecode.com/svn/, GIT: /home/test";
$lang->repo->example->config = "Config directory is required in https. Use '--config-dir' to generate config dir.";
$lang->repo->example->encoding = "input encoding of files";
$lang->repo->typeList['standard'] = 'Standard';
$lang->repo->typeList['performance'] = 'Performance';
$lang->repo->typeList['security'] = 'Security';
$lang->repo->typeList['redundancy'] = 'Redundancy';
$lang->repo->typeList['logicError'] = 'Logic Error';
+150
View File
@@ -0,0 +1,150 @@
<?php
$lang->repo->common = '代码';
$lang->repo->create = '创建版本库';
$lang->repo->settings = '版本库设置';
$lang->repo->browse = '浏览';
$lang->repo->delete = '删除版本库';
$lang->repo->showSyncComment = '显示同步进度';
$lang->repo->ajaxSyncComment = '接口:AJAX同步注释';
$lang->repo->download = '下载';
$lang->repo->downloadDiff = '下载Diff';
$lang->repo->diffAction = '版本对比';
$lang->repo->revisionAction = '版本详情';
$lang->repo->blameAction = '版本追溯';
$lang->repo->addBug = '添加评审';
$lang->repo->editBug = '编辑评审';
$lang->repo->deleteBug = '删除评审';
$lang->repo->addComment = '添加备注';
$lang->repo->editComment = '编辑备注';
$lang->repo->deleteComment = '删除备注';
$lang->repo->submit = '提交';
$lang->repo->cancel = '取消';
$lang->repo->addComment = '添加评论';
$lang->repo->product = $lang->productCommon;
$lang->repo->module = '模块';
$lang->repo->project = $lang->projectCommon;
$lang->repo->type = '类型';
$lang->repo->assign = '指派';
$lang->repo->title = '标题';
$lang->repo->detile = '详情';
$lang->repo->lines = '代码行';
$lang->repo->line = '行';
$lang->repo->expand = '点击展开';
$lang->repo->collapse = '点击折叠';
$lang->repo->id = '编号';
$lang->repo->SCM = '类型';
$lang->repo->name = '名称';
$lang->repo->path = '地址';
$lang->repo->prefix = '地址扩展';
$lang->repo->config = '配置目录';
$lang->repo->account = '用户名';
$lang->repo->password = '密码';
$lang->repo->encoding = '编码';
$lang->repo->client = '客户端';
$lang->repo->size = '大小';
$lang->repo->revision = '查看版本';
$lang->repo->revisionA = '版本';
$lang->repo->revisions = '版本';
$lang->repo->time = '提交时间';
$lang->repo->committer = '作者';
$lang->repo->commits = '提交数';
$lang->repo->synced = '初始化同步';
$lang->repo->lastSync = '最后同步时间';
$lang->repo->deleted = '已删除';
$lang->repo->commit = '提交';
$lang->repo->comment = '注释';
$lang->repo->view = '查看文件';
$lang->repo->viewA = '查看';
$lang->repo->log = '版本历史';
$lang->repo->blame = '追溯';
$lang->repo->date = '日期';
$lang->repo->diff = '比较差异';
$lang->repo->diffAB = '比较';
$lang->repo->diffAll = '全部比较';
$lang->repo->viewDiff = '查看差异';
$lang->repo->allLog = '所有版本';
$lang->repo->location = '位置';
$lang->repo->file = '文件';
$lang->repo->action = '操作';
$lang->repo->code = '代码';
$lang->repo->review = '评审';
$lang->repo->acl = '权限';
$lang->repo->group = '分组';
$lang->repo->user = '用户';
$lang->repo->info = '版本信息';
$lang->repo->title = '标题';
$lang->repo->status = '状态';
$lang->repo->openedBy = '创建者';
$lang->repo->assignedTo = '指派给';
$lang->repo->openedDate = '创建日期';
$lang->repo->latestRevision = '最近修订版本';
$lang->repo->actionInfo = "由%s在%s添加";
$lang->repo->changes = "修改记录";
$lang->repo->reviewLocation = "%s@%s,%s行 - %s行";
$lang->repo->commentEdit = '<i class="icon-pencil"></i>';
$lang->repo->commentDelete = '<i class="icon-remove"></i>';
$lang->repo->allChanges = "其他改动";
$lang->repo->commitTitle = "第%s次提交";
$lang->repo->viewDiffList['inline'] = '直列';
$lang->repo->viewDiffList['appose'] = '并排';
$lang->repo->encryptList['plain'] = '不加密';
$lang->repo->encryptList['base64'] = 'BASE64';
$lang->repo->logStyles['A'] = '添加';
$lang->repo->logStyles['M'] = '修改';
$lang->repo->logStyles['D'] = '删除';
$lang->repo->encodingList['utf_8'] = 'UTF-8';
$lang->repo->encodingList['gbk'] = 'GBK';
$lang->repo->scmList['Subversion'] = 'Subversion';
$lang->repo->scmList['Git'] = 'Git';
$lang->repo->notice = new stdclass();
$lang->repo->notice->syncing = '正在同步中, 请稍等...';
$lang->repo->notice->syncComplete = '同步完成,正在跳转...';
$lang->repo->notice->syncedCount = '已经同步记录条数';
$lang->repo->notice->delete = '是否要删除该版本库?';
$lang->repo->notice->successDelete = '已经成功删除版本库。';
$lang->repo->notice->commentContent = '输入回复内容';
$lang->repo->notice->deleteBug = '确认删除该Bug?';
$lang->repo->notice->deleteComment = '确认删除该回复?';
$lang->repo->notice->lastSyncTime = '最后更新于:';
$lang->repo->error = new stdclass();
$lang->repo->error->useless = '你的服务器禁用了exec,shell_exec方法,无法使用该功能';
$lang->repo->error->connect = '连接版本库失败,请填写正确的用户名、密码和版本库地址!';
$lang->repo->error->version = "https和svn协议需要1.8及以上版本的客户端,请升级到最新版本!详情访问:http://subversion.apache.org/";
$lang->repo->error->path = '版本库地址直接填写文件路径,如:/home/test。';
$lang->repo->error->cmd = '客户端错误!';
$lang->repo->error->diff = '必须选择两个版本';
$lang->repo->error->product = "请选择{$lang->productCommon}!";
$lang->repo->error->commentText = '请填写评审内容';
$lang->repo->error->comment = '请填写内容';
$lang->repo->error->title = '请填写标题';
$lang->repo->error->accessDenied = '你没有权限访问该版本库';
$lang->repo->error->noFound = '你访问的版本库不存在';
$lang->repo->error->noFile = '目录 %s 不存在';
$lang->repo->error->noPriv = '程序没有权限切换到目录 %s';
$lang->repo->error->output = "执行命令:%s\n错误结果(%s): %s\n";
$lang->repo->error->clientVersion = "客户端版本过低,请升级或更换SVN客户端";
$lang->repo->error->encoding = "编码可能错误,请更换编码重试。";
$lang->repo->example = new stdclass();
$lang->repo->example->client = "例如:/usr/bin/svn, C:\subversion\svn.exe, /usr/bin/git";
$lang->repo->example->path = "例如:SVN: http://example.googlecode.com/svn/, GIT: /homt/test";
$lang->repo->example->config = "https需要填写配置目录的位置,通过config-dir选项生成配置目录";
$lang->repo->example->encoding = "填写版本库中文件的编码";
$lang->repo->typeList['standard'] = '规范';
$lang->repo->typeList['performance'] = '性能';
$lang->repo->typeList['security'] = '安全';
$lang->repo->typeList['redundancy'] = '冗余';
$lang->repo->typeList['logicError'] = '逻辑错误';
+150
View File
@@ -0,0 +1,150 @@
<?php
$lang->repo->common = '代碼';
$lang->repo->create = '創建版本庫';
$lang->repo->settings = '版本庫設置';
$lang->repo->browse = '瀏覽';
$lang->repo->delete = '刪除版本庫';
$lang->repo->showSyncComment = '顯示同步進度';
$lang->repo->ajaxSyncComment = '介面:AJAX同步註釋';
$lang->repo->download = '下載';
$lang->repo->downloadDiff = '下載Diff';
$lang->repo->diffAction = '版本對比';
$lang->repo->revisionAction = '版本詳情';
$lang->repo->blameAction = '版本追溯';
$lang->repo->addBug = '添加評審';
$lang->repo->editBug = '編輯評審';
$lang->repo->deleteBug = '刪除評審';
$lang->repo->addComment = '添加備註';
$lang->repo->editComment = '編輯備註';
$lang->repo->deleteComment = '刪除備註';
$lang->repo->submit = '提交';
$lang->repo->cancel = '取消';
$lang->repo->addComment = '添加評論';
$lang->repo->product = $lang->productCommon;
$lang->repo->module = '模組';
$lang->repo->project = $lang->projectCommon;
$lang->repo->type = '類型';
$lang->repo->assign = '指派';
$lang->repo->title = '標題';
$lang->repo->detile = '詳情';
$lang->repo->lines = '代碼行';
$lang->repo->line = '行';
$lang->repo->expand = '點擊展開';
$lang->repo->collapse = '點擊摺疊';
$lang->repo->id = '編號';
$lang->repo->SCM = '類型';
$lang->repo->name = '名稱';
$lang->repo->path = '地址';
$lang->repo->prefix = '地址擴展';
$lang->repo->config = '配置目錄';
$lang->repo->account = '用戶名';
$lang->repo->password = '密碼';
$lang->repo->encoding = '編碼';
$lang->repo->client = '客戶端';
$lang->repo->size = '大小';
$lang->repo->revision = '查看版本';
$lang->repo->revisionA = '版本';
$lang->repo->revisions = '版本';
$lang->repo->time = '提交時間';
$lang->repo->committer = '作者';
$lang->repo->commits = '提交數';
$lang->repo->synced = '初始化同步';
$lang->repo->lastSync = '最後同步時間';
$lang->repo->deleted = '已刪除';
$lang->repo->commit = '提交';
$lang->repo->comment = '註釋';
$lang->repo->view = '查看檔案';
$lang->repo->viewA = '查看';
$lang->repo->log = '版本歷史';
$lang->repo->blame = '追溯';
$lang->repo->date = '日期';
$lang->repo->diff = '比較差異';
$lang->repo->diffAB = '比較';
$lang->repo->diffAll = '全部比較';
$lang->repo->viewDiff = '查看差異';
$lang->repo->allLog = '所有版本';
$lang->repo->location = '位置';
$lang->repo->file = '檔案';
$lang->repo->action = '操作';
$lang->repo->code = '代碼';
$lang->repo->review = '評審';
$lang->repo->acl = '權限';
$lang->repo->group = '分組';
$lang->repo->user = '用戶';
$lang->repo->info = '版本信息';
$lang->repo->title = '標題';
$lang->repo->status = '狀態';
$lang->repo->openedBy = '創建者';
$lang->repo->assignedTo = '指派給';
$lang->repo->openedDate = '創建日期';
$lang->repo->latestRevision = '最近修訂版本';
$lang->repo->actionInfo = "由%s在%s添加";
$lang->repo->changes = "修改記錄";
$lang->repo->reviewLocation = "%s@%s,%s行 - %s行";
$lang->repo->commentEdit = '<i class="icon-pencil"></i>';
$lang->repo->commentDelete = '<i class="icon-remove"></i>';
$lang->repo->allChanges = "其他改動";
$lang->repo->commitTitle = "第%s次提交";
$lang->repo->viewDiffList['inline'] = '直列';
$lang->repo->viewDiffList['appose'] = '並排';
$lang->repo->encryptList['plain'] = '不加密';
$lang->repo->encryptList['base64'] = 'BASE64';
$lang->repo->logStyles['A'] = '添加';
$lang->repo->logStyles['M'] = '修改';
$lang->repo->logStyles['D'] = '刪除';
$lang->repo->encodingList['utf_8'] = 'UTF-8';
$lang->repo->encodingList['gbk'] = 'GBK';
$lang->repo->scmList['Subversion'] = 'Subversion';
$lang->repo->scmList['Git'] = 'Git';
$lang->repo->notice = new stdclass();
$lang->repo->notice->syncing = '正在同步中, 請稍等...';
$lang->repo->notice->syncComplete = '同步完成,正在跳轉...';
$lang->repo->notice->syncedCount = '已經同步記錄條數';
$lang->repo->notice->delete = '是否要刪除該版本庫?';
$lang->repo->notice->successDelete = '已經成功刪除版本庫。';
$lang->repo->notice->commentContent = '輸入回覆內容';
$lang->repo->notice->deleteBug = '確認刪除該Bug?';
$lang->repo->notice->deleteComment = '確認刪除該回覆?';
$lang->repo->notice->lastSyncTime = '最後更新于:';
$lang->repo->error = new stdclass();
$lang->repo->error->useless = '你的伺服器禁用了exec,shell_exec方法,無法使用該功能';
$lang->repo->error->connect = '連接版本庫失敗,請填寫正確的用戶名、密碼和版本庫地址!';
$lang->repo->error->version = "https和svn協議需要1.8及以上版本的客戶端,請升級到最新版本!詳情訪問:http://subversion.apache.org/";
$lang->repo->error->path = '版本庫地址直接填寫檔案路徑,如:/home/test。';
$lang->repo->error->cmd = '客戶端錯誤!';
$lang->repo->error->diff = '必須選擇兩個版本';
$lang->repo->error->product = "請選擇{$lang->productCommon}!";
$lang->repo->error->commentText = '請填寫評審內容';
$lang->repo->error->comment = '請填寫內容';
$lang->repo->error->title = '請填寫標題';
$lang->repo->error->accessDenied = '你沒有權限訪問該版本庫';
$lang->repo->error->noFound = '你訪問的版本庫不存在';
$lang->repo->error->noFile = '目錄 %s 不存在';
$lang->repo->error->noPriv = '程序沒有權限切換到目錄 %s';
$lang->repo->error->output = "執行命令:%s\n錯誤結果(%s): %s\n";
$lang->repo->error->clientVersion = "客戶端版本過低,請升級或更換SVN客戶端";
$lang->repo->error->encoding = "編碼可能錯誤,請更換編碼重試。";
$lang->repo->example = new stdclass();
$lang->repo->example->client = "例如:/usr/bin/svn, C:\subversion\svn.exe, /usr/bin/git";
$lang->repo->example->path = "例如:SVN: http://example.googlecode.com/svn/, GIT: /homt/test";
$lang->repo->example->config = "https需要填寫配置目錄的位置,通過config-dir選項生成配置目錄";
$lang->repo->example->encoding = "填寫版本庫中檔案的編碼";
$lang->repo->typeList['standard'] = '規範';
$lang->repo->typeList['performance'] = '性能';
$lang->repo->typeList['security'] = '安全';
$lang->repo->typeList['redundancy'] = '冗餘';
$lang->repo->typeList['logicError'] = '邏輯錯誤';
+964
View File
@@ -0,0 +1,964 @@
<?php
class repoModel extends model
{
/**
* Check repo priv.
*
* @param object $repo
* @access public
* @return bool
*/
public function checkPriv($repo)
{
$account = $this->app->user->account;
if(strpos(",{$this->app->company->admins},", ",$account,") !== false) return true;
if(empty($repo->acl->groups) and empty($repo->acl->users)) return true;
if(!empty($repo->acl->groups))
{
foreach($this->app->user->groups as $group)
{
if(in_array($group, $repo->acl->groups)) return true;
}
}
if(!empty($repo->acl->users) and in_array($account, $repo->acl->users)) return true;
return false;
}
/**
* Set menu.
*
* @param array $repos
* @param int $repoID
* @access public
* @return void
*/
public function setMenu($repos, $repoID = '')
{
if(empty($repoID)) $repoID = $this->session->repoID ? $this->session->repoID : key($repos);
if(!isset($repos[$repoID])) $repoID = key($repos);
/* Check the privilege. */
if($repoID)
{
$repo = $this->getRepoByID($repoID);
if(empty($repo))
{
echo(js::alert($this->lang->repo->error->noFound));
die(js::locate('back'));
}
if(!$this->checkPriv($repo))
{
echo(js::alert($this->lang->repo->error->accessDenied));
die(js::locate('back'));
}
}
if(!empty($repos))
{
$repoIndex = '<div class="btn-group angle-btn"><div class="btn-group"><button data-toggle="dropdown" type="button" class="btn">' . ($repo->SCM == 'Subversion' ? '[SVN] ' : '[GIT] ') . $repo->name . ' <span class="caret"></span></button>';
$repoIndex .= $this->select($repos, $repoID);
$repoIndex .= '</div></div>';
$branches = $this->getBranches($repo);
if(empty($branches))
{
$this->setRepoBranch('');
}
else
{
$branchID = 'master';
if($this->cookie->repoBranch) $branchID = $this->cookie->repoBranch;
if(!isset($branches[$branchID])) $branchID = 'master';
$branch = zget($branches, $branchID);
if(empty($branch)) $branchID = $branch = current($branches);
$this->setRepoBranch($branchID);
$repoIndex .= '<div class="btn-group angle-btn"><div class="btn-group"><button data-toggle="dropdown" type="button" class="btn">' . $branch . ' <span class="caret"></span></button>';
$repoIndex .= "<div class='dropdown-menu search-list' data-ride='searchList'>";
$repoIndex .= "<div class='list-group'>";
foreach($branches as $branch)
{
$class = $branchID == $branch ? "class='active'" : '';
$repoIndex .= html::a("javascript:switchBranch(\"$branch\")", $branch, '', $class);
}
$repoIndex .= "</div></div></div></div>";
}
$this->lang->modulePageNav = $repoIndex;
}
foreach($this->lang->repo->menu as $key => $menu)
{
common::setMenuVars($this->lang->repo->menu, $key, $repoID);
}
session_start();
$this->session->set('repoID', $repoID);
session_write_close();
}
/**
* Create the select code of repos.
*
* @param array $repos
* @param int $repoID
* @param string $currentModule
* @param string $currentMethod
* @access public
* @return string
*/
public function select($repos, $repoID)
{
$selectHtml = "<div class='dropdown-menu search-list' data-ride='searchList'>";
$selectHtml .= "<div class='input-control search-box has-icon-left has-icon-right search-example'>";
$selectHtml .= "<input id='repoSearchBox' type='search' autocomplete='off' class='form-control search-input empty'>";
$selectHtml .= "<label for='repoSearchBox' class='input-control-icon-left search-icon'><i class='icon icon-search'></i></label>";
$selectHtml .= "<a class='input-control-icon-right search-clear-btn'><i class='icon icon-close icon-sm'></i></a></div>";
$selectHtml .= "<div class='list-group'>";
foreach($repos as $id => $name)
{
$class = $repoID == $id ? "class='active'" : '';
$selectHtml .= html::a(helper::createLink('repo', 'log', "repoID={$id}"), $name, '', $class);
}
$selectHtml .= "</div></div>";
return $selectHtml;
}
/**
* Get all repos.
*
* @access public
* @return array
*/
public function getAllRepos()
{
$repos = $this->dao->select('*')->from(TABLE_REPO)->where('deleted')->eq(0)->fetchAll();
foreach($repos as $i => $repo)
{
$repo->acl = json_decode($repo->acl);
if(!$this->checkPriv($repo)) unset($repos[$i]);
}
return $repos;
}
/**
* Get repo pairs.
*
* @access public
* @return array
*/
public function getRepoPairs()
{
$repos = $this->dao->select('*')->from(TABLE_REPO)->where('deleted')->eq(0)->fetchAll();
$repoPairs = array();
foreach($repos as $repo)
{
$repo->acl = json_decode($repo->acl);
$scm = $repo->SCM == 'Subversion' ? 'svn' : 'git';
if($this->checkPriv($repo)) $repoPairs[$repo->id] = "[{$scm}] " . $repo->name;
}
return $repoPairs;
}
/**
* Get repo by id.
*
* @param int $repoID
* @access public
* @return object
*/
public function getRepoByID($repoID)
{
$repo = $this->dao->select('*')->from(TABLE_REPO)->where('id')->eq($repoID)->fetch();
if(!$repo) return false;
if($repo->encrypt == 'base64') $repo->password = base64_decode($repo->password);
$repo->acl = json_decode($repo->acl);
return $repo;
}
/**
* Get git branches.
*
* @param object $repo
* @access public
* @return array
*/
public function getBranches($repo)
{
$this->scm = $this->app->loadClass('scm');
$this->scm->setEngine($repo);
return $this->scm->branch();
}
/**
* Get logs.
*
* @param object $repo
* @param string $entry
* @param string $revision
* @param string $type
* @param object $pager
* @access public
* @return array
*/
public function getLogs($repo, $entry, $revision = 'HEAD', $type = 'dir', $pager = null)
{
$entry = ltrim($entry, '/');
$entry = $repo->prefix . (empty($entry) ? '' : '/' . $entry);
if((time() - strtotime($repo->lastSync)) / 60 >= $this->config->repo->syncTime) $this->updateLatestCommit($repo);
$repoID = $repo->id;
$revisionTime = $this->dao->select('time')->from(TABLE_REPOHISTORY)->alias('t1')
->leftJoin(TABLE_REPOBRANCH)->alias('t2')->on('t1.id=t2.revision')
->where('t1.repo')->eq($repoID)
->beginIF($revision != 'HEAD')->andWhere('t1.revision')->eq($revision)->fi()
->beginIF($this->cookie->repoBranch)->andWhere('t2.branch')->eq($this->cookie->repoBranch)->fi()
->orderBy('time desc')
->limit(1)
->fetch('time');
$historyIdList = array();
if($entry != '/' and !empty($entry))
{
$historyIdList = $this->dao->select('DISTINCT t2.id')->from(TABLE_REPOFILES)->alias('t1')
->leftJoin(TABLE_REPOHISTORY)->alias('t2')->on('t1.revision=t2.id')
->where('1=1')
->andWhere('t1.repo')->eq($repo->id)
->beginIF($type == 'dir')
->andWhere('t1.parent', true)->like(rtrim($entry, '/') . "/%")
->orWhere('t1.parent')->eq(rtrim($entry, '/'))
->markRight(1)
->fi()
->beginIF($type == 'file')->andWhere('t1.path')->eq("$entry")->fi()
->orderBy('t2.`time` desc')
->page($pager)
->fetchPairs('id', 'id');
}
$comments = $this->dao->select('DISTINCT t1.*')->from(TABLE_REPOHISTORY)->alias('t1')
->leftJoin(TABLE_REPOBRANCH)->alias('t2')->on('t1.id=t2.revision')
->where('t1.repo')->eq($repoID)
->andWhere('t1.`time`')->le($revisionTime)
->andWhere('left(t1.comment, 12)')->ne('Merge branch')
->beginIF($this->cookie->repoBranch)->andWhere('t2.branch')->eq($this->cookie->repoBranch)->fi()
->beginIF($entry != '/' and !empty($entry))->andWhere('t1.id')->in($historyIdList)->fi()
->orderBy('time desc');
if($entry == '/' or empty($entry))$comments->page($pager, 't1.id');
$comments = $comments->fetchAll('revision');
foreach($comments as $repoComment) $repoComment->comment = $this->replaceCommentLink($repoComment->comment);
return $comments;
}
/**
* Get latest comment.
*
* @param int $repoID
* @access public
* @return object
*/
public function getLatestComment($repoID)
{
$count = $this->dao->select('count(DISTINCT t1.id) as count')->from(TABLE_REPOHISTORY)->alias('t1')
->leftJoin(TABLE_REPOBRANCH)->alias('t2')->on('t1.id=t2.revision')
->where('t1.repo')->eq($repoID)
->beginIF($this->cookie->repoBranch)->andWhere('t2.branch')->eq($this->cookie->repoBranch)->fi()
->fetch('count');
$lastComment = $this->dao->select('t1.*')->from(TABLE_REPOHISTORY)->alias('t1')
->leftJoin(TABLE_REPOBRANCH)->alias('t2')->on('t1.id=t2.revision')
->where('t1.repo')->eq($repoID)
->beginIF($this->cookie->repoBranch)->andWhere('t2.branch')->eq($this->cookie->repoBranch)->fi()
->orderBy('t1.time desc')
->limit(1)
->fetch();
if(empty($lastComment)) return null;
$repo = $this->getRepoByID($repoID);
if($repo->SCM == 'Git' and $lastComment->commit != $count)
{
$this->fixCommit($repo->id);
$lastComment->commit = $count;
}
return $lastComment;
}
/**
* Get revisions from db.
*
* @param int $repoID
* @param string $limit
* @param string $maxRevision
* @param string $minRevision
* @access public
* @return array
*/
public function getRevisionsFromDB($repoID, $limit = '', $maxRevision = '', $minRevision = '')
{
$revisions = $this->dao->select('DISTINCT t1.*')->from(TABLE_REPOHISTORY)->alias('t1')
->leftJoin(TABLE_REPOBRANCH)->alias('t2')->on('t1.id=t2.revision')
->where('t1.repo')->eq($repoID)
->beginIF(!empty($maxRevision))->andWhere('t1.revision')->le($maxRevision)->fi()
->beginIF(!empty($minRevision))->andWhere('t1.revision')->ge($minRevision)->fi()
->beginIF($this->cookie->repoBranch)->andWhere('t2.branch')->eq($this->cookie->repoBranch)->fi()
->orderBy('t1.revision desc')
->beginIF(!empty($limit))->limit($limit)->fi()
->fetchAll('revision');
$commiters = $this->loadModel('user')->getCommiters();
foreach($revisions as $revision)
{
$revision->comment = $this->replaceCommentLink($revision->comment);
$revision->committer = isset($commiters[$revision->committer]) ? $commiters[$revision->committer] : $revision->committer;
}
return $revisions;
}
/**
* Get history.
*
* @param int $repoID
* @param array $revisions
* @access public
* @return array
*/
public function getHistory($repoID, $revisions)
{
return $this->dao->select('DISTINCT t1.*')->from(TABLE_REPOHISTORY)->alias('t1')
->leftJoin(TABLE_REPOBRANCH)->alias('t2')->on('t1.id=t2.revision')
->where('t1.repo')->eq($repoID)
->andWhere('t1.revision')->in($revisions)
->beginIF($this->cookie->repoBranch)->andWhere('t2.branch')->eq($this->cookie->repoBranch)->fi()
->fetchAll('revision');
}
/**
* Get review.
*
* @param int $repoID
* @param string $entry
* @param string $revision
* @access public
* @return array
*/
public function getReview($repoID, $entry, $revision)
{
$reviews = array();
$bugs = $this->dao->select('t1.*, t2.realname')->from(TABLE_BUG)->alias('t1')
->leftJoin(TABLE_USER)->alias('t2')
->on('t1.openedBy = t2.account')
->where('t1.repo')->eq($repoID)
->andWhere('t1.entry')->eq($entry)
->andWhere('t1.v2')->eq($revision)
->andWhere('t1.deleted')->eq(0)
->fetchAll('id');
$comments = $this->dao->select('t1.*, t2.realname')->from(TABLE_ACTION)->alias('t1')
->leftJoin(TABLE_USER)->alias('t2')
->on('t1.actor = t2.account')
->where('t1.objectType')->eq('bug')
->andWhere('t1.objectID')->in(array_keys($bugs))
->andWhere('t1.action')->eq('commented')
->fetchGroup('objectID', 'id');
foreach($bugs as $bug)
{
if(common::hasPriv('bug', 'edit')) $bug->edit = true;
if(common::hasPriv('bug', 'delete')) $bug->delete = true;
$lines = explode(',', trim($bug->lines, ','));
$line = $lines[0];
$reviews[$line]['bugs'][$bug->id] = $bug;
if(isset($comments[$bug->id]))
{
foreach($comments[$bug->id] as $key => $comment)
{
if($comment->actor == $this->app->user->account) $comment->edit = true;
}
$reviews[$line]['comments'] = $comments;
}
}
return $reviews;
}
/**
* Get git revisionName.
*
* @param string $revision
* @param int $commit
* @access public
* @return string
*/
public function getGitRevisionName($revision, $commit)
{
if(empty($commit)) return substr($revision, 0, 10);
return substr($revision, 0, 10) . '<span title="' . sprintf($this->lang->repo->commitTitle, $commit) . '"> (' . $commit . ') </span>';
}
/**
* create
*
* @access public
* @return int
*/
public function create()
{
$this->checkConnection();
$data = fixer::input('post')->skipSpecial('path,client,account,password')->get();
$data->acl = empty($data->acl) ? '' : json_encode($data->acl);
if(empty($data->client)) $data->client = 'svn';
if($data->SCM == 'Subversion')
{
$scm = $this->app->loadClass('scm');
$scm->setEngine($data);
$info = $scm->info('');
$data->prefix = empty($info->root) ? '' : trim(str_ireplace($info->root, '', str_replace('\\', '/', $data->path)), '/');
if($data->prefix) $data->prefix = '/' . $data->prefix;
}
if($data->encrypt == 'base64') $data->password = base64_encode($data->password);
$this->dao->insert(TABLE_REPO)->data($data)->exec();
return $this->dao->lastInsertID();
}
/**
* Save settings.
*
* @param int $repoID
* @access public
* @return bool
*/
public function saveSettings($repoID)
{
$this->checkConnection();
$data = fixer::input('post')->skipSpecial('path,client,account,password')->get();
$data->acl = empty($data->acl) ? '' : json_encode($data->acl);
if(empty($data->client)) $data->client = 'svn';
$repo = $this->getRepoByID($repoID);
$data->prefix = $repo->prefix;
if($data->SCM == 'Subversion' and $data->path != $repo->path)
{
$scm = $this->app->loadClass('scm');
$scm->setEngine($data);
$info = $scm->info('');
$data->prefix = empty($info->root) ? '' : trim(str_ireplace($info->root, '', str_replace('\\', '/', $data->path)), '/');
if($data->prefix) $data->prefix = '/' . $data->prefix;
}
elseif($data->SCM != $repo->SCM and $data->SCM == 'Git')
{
$data->prefix = '';
}
if($data->path != $repo->path) $data->synced = 0;
if($data->encrypt == 'base64') $data->password = base64_encode($data->password);
$this->dao->update(TABLE_REPO)->data($data)->where('id')->eq($repoID)->exec();
if($repo->path != $data->path)
{
$this->dao->delete()->from(TABLE_REPOHISTORY)->where('repo')->eq($repoID)->exec();
$this->dao->delete()->from(TABLE_REPOFILES)->where('repo')->eq($repoID)->exec();
return false;
}
return true;
}
/**
* Save commit.
*
* @param int $repoID
* @param array $logs
* @param int $version
* @param string $branch
* @access public
* @return int
*/
public function saveCommit($repoID, $logs, $version, $branch = '')
{
$count = 0;
if(empty($logs)) return $count;
foreach($logs['commits'] as $i => $commit)
{
$existsRevision = $this->dao->select('id,revision')->from(TABLE_REPOHISTORY)->where('repo')->eq($repoID)->andWhere('revision')->eq($commit->revision)->fetch();
if($existsRevision)
{
if($branch) $this->dao->replace(TABLE_REPOBRANCH)->set('repo')->eq($repoID)->set('revision')->eq($existsRevision->id)->set('branch')->eq($branch)->exec();
continue;
}
$commit->repo = $repoID;
$commit->commit = $version;
$commit->comment = htmlspecialchars($commit->comment);
$this->dao->insert(TABLE_REPOHISTORY)->data($commit)->exec();
if(!dao::isError())
{
$commitID = $this->dao->lastInsertID();
if($branch) $this->dao->replace(TABLE_REPOBRANCH)->set('repo')->eq($repoID)->set('revision')->eq($commitID)->set('branch')->eq($branch)->exec();
foreach($logs['files'][$i] as $file)
{
$parentPath = dirname($file->path);
$file->parent = $parentPath == '\\' ? '/' : $parentPath;
$file->revision = $commitID;
$file->repo = $repoID;
$this->dao->insert(TABLE_REPOFILES)->data($file)->exec();
}
$revisionPairs[$commit->revision] = $commit->revision;
$version++;
$count++;
}
else
{
dao::getError();
}
}
return $count;
}
/**
* Save exists log branch.
*
* @param int $repoID
* @param string $branch
* @access public
* @return void
*/
public function saveExistsLogBranch($repoID, $branch)
{
$lastBranchLog = $this->dao->select('t1.time')->from(TABLE_REPOHISTORY)->alias('t1')
->leftJoin(TABLE_REPOBRANCH)->alias('t2')->on('t1.id=t2.revision')
->where('t1.repo')->eq($repoID)
->andWhere('t2.branch')->eq($branch)
->orderBy('time')
->limit(1)
->fetch();
$stmt = $this->dao->select('*')->from(TABLE_REPOHISTORY)->where('repo')->eq($repoID)->andWhere('time')->lt($lastBranchLog->time)->query();
while($log = $stmt->fetch())
{
$this->dao->REPLACE(TABLE_REPOBRANCH)->set('repo')->eq($repoID)->set('revision')->eq($log->id)->set('branch')->eq($branch)->exec();
}
}
/**
* Update commit count.
*
* @param int $repoID
* @param int $count
* @access public
* @return void
*/
public function updateCommitCount($repoID, $count)
{
return $this->dao->update(TABLE_REPO)->set('commits')->eq($count)->where('id')->eq($repoID)->exec();
}
/**
* Update latest commit.
*
* @param object $repo
* @access public
* @return void
*/
public function updateLatestCommit($repo)
{
$repoID = $repo->id;
$latestInDB = $this->getLatestComment($repoID);
$version = empty($latestInDB) ? 1 : $latestInDB->commit + 1;
$scm = $this->app->loadClass('scm');
$scm->setEngine($repo);
$commitCount = $scm->getCommitCount(empty($latestInDB) ? 0 : $latestInDB->commit, empty($latestInDB) ? 0 : $latestInDB->revision);
if($commitCount >= $version)
{
$revision = 'HEAD';
$logs = $scm->getCommits($revision, $commitCount - $version + 1, $this->cookie->repoBranch);
$logs['commits'] = array_reverse($logs['commits'], true);
$commitCount = $this->saveCommit($repoID, $logs, $version, $this->cookie->repoBranch);
if($repo->SCM == 'Git' and empty($latestInDB)) $this->fixCommit($repo->id);
$this->updateCommitCount($repoID, $commitCount);
}
$this->dao->update(TABLE_REPO)->set('lastSync')->eq(helper::now())->where('id')->eq($repoID)->exec();
}
/**
* Update comment.
*
* @param int $commentID
* @param string $comment
* @access public
* @return string
*/
public function updateComment($commentID, $comment)
{
$this->dao->update(TABLE_ACTION)->set('comment')->eq($comment)->where('id')->eq($commentID)->exec();
return $comment;
}
/**
* Delete comment.
*
* @param int $commentID
* @access public
* @return void
*/
public function deleteComment($commentID)
{
return $this->dao->delete()->from(TABLE_ACTION)->where('id')->eq($commentID)->exec();
}
/**
* Get pre and next revision.
*
* @param object $repo
* @param string $entry
* @param string $revision
* @param string $fileType
* @param string $method
*
* @access public
* @return object
*/
public function getPreAndNext($repo, $entry, $revision = 'HEAD', $fileType = 'dir', $method = 'view')
{
$entry = ltrim($entry, '/');
$entry = $repo->prefix . '/' . $entry;
$repoID = $repo->id;
if($method == 'view')
{
$revisions = $this->dao->select('DISTINCT t1.revision,t1.commit')->from(TABLE_REPOHISTORY)->alias('t1')
->leftJoin(TABLE_REPOFILES)->alias('t2')->on('t1.id=t2.revision')
->leftJoin(TABLE_REPOBRANCH)->alias('t3')->on('t1.id=t3.revision')
->where('t1.repo')->eq($repoID)
->beginIF($this->cookie->repoBranch)->andWhere('t3.branch')->eq($this->cookie->repoBranch)->fi()
->andWhere('t2.path')->eq("$entry")
->orderBy('commit desc')
->fetchPairs();
}
else
{
$revisions = $this->dao->select('DISTINCT t1.revision,t1.commit')->from(TABLE_REPOHISTORY)->alias('t1')
->leftJoin(TABLE_REPOFILES)->alias('t2')->on('t1.id=t2.revision')
->leftJoin(TABLE_REPOBRANCH)->alias('t3')->on('t1.id=t3.revision')
->where('t1.repo')->eq($repoID)
->beginIF($this->cookie->repoBranch)->andWhere('t3.branch')->eq($this->cookie->repoBranch)->fi()
->beginIF($entry == '/')->andWhere('t2.revision = t1.id')->fi()
->beginIF($fileType == 'dir' && $entry != '/')
->andWhere('t2.parent', true)->like(rtrim($entry, '/') . "/%")
->orWhere('t2.parent')->eq(rtrim($entry, '/'))
->markRight(1)
->fi()
->beginIF($fileType == 'file' && $entry != '/')->andWhere('t2.path')->eq($entry)->fi()
->orderBy('commit desc')
->fetchPairs();
}
$preRevision = false;
$preAndNext = new stdclass();
$preAndNext->pre = '';
$preAndNext->next = '';
foreach($revisions as $version => $commit)
{
/* Get next object. */
if($preRevision === true)
{
$preAndNext->next = $version;
break;
}
/* Get pre object. */
if($revision == $version)
{
if($preRevision) $preAndNext->pre = $preRevision;
$preRevision = true;
}
if($preRevision !== true) $preRevision = $version;
}
return $preAndNext;
}
/**
* Create link for repo
*
* @param string $method
* @param string $params
* @param string $pathParams
* @param string $viewType
* @param bool $onlybody
* @access public
* @return string
*/
public function createLink($method, $params = '', $pathParams = '', $viewType = '', $onlybody = false)
{
$link = helper::createLink('repo', $method, $params, $viewType, $onlybody);
if(empty($pathParams)) return $link;
$link .= strpos($link, '?') === false ? '?' : '&';
$link .= $pathParams;
return $link;
}
/**
* Set back session/
*
* @param string $type
* @param bool $withOtherModule
* @access public
* @return void
*/
public function setBackSession($type = 'list', $withOtherModule = false)
{
$backKey = 'repo' . ucfirst(strtolower($type));
session_start();
$uri = $this->app->getURI(true);
if(!empty($_GET) and $this->config->requestType == 'PATH_INFO') $uri .= "?" . http_build_query($_GET);
$_SESSION[$backKey] = $uri;
if($type == 'list') unset($_SESSION['repoView']);
if($withOtherModule)
{
$this->session->set('bugList', $uri);
$this->session->set('taskList', $uri);
}
session_write_close();
}
/**
* Set repo branch.
*
* @param string $branch
* @access public
* @return void
*/
public function setRepoBranch($branch)
{
setcookie("repoBranch", $branch, 0, $this->config->webRoot);
$_COOKIE['repoBranch'] = $branch;
}
/**
* Mark synced status.
*
* @param int $repoID
* @access public
* @return void
*/
public function markSynced($repoID)
{
$this->fixCommit($repoID);
$this->dao->update(TABLE_REPO)->set('synced')->eq(1)->where('id')->eq($repoID)->exec();
}
/**
* Fix commit.
*
* @param int $repoID
* @access public
* @return void
*/
public function fixCommit($repoID)
{
$stmt = $this->dao->select('DISTINCT t1.id')->from(TABLE_REPOHISTORY)->alias('t1')
->leftJoin(TABLE_REPOBRANCH)->alias('t2')->on('t1.id=t2.revision')
->where('t1.repo')->eq($repoID)
->beginIF($this->cookie->repoBranch)->andWhere('t2.branch')->eq($this->cookie->repoBranch)->fi()
->orderBy('time')
->query();
$i = 1;
while($repoHistory = $stmt->fetch())
{
$this->dao->update(TABLE_REPOHISTORY)->set('`commit`')->eq($i)->where('id')->eq($repoHistory->id)->exec();
$i++;
}
}
/**
* Encode repo path.
*
* @param string $path
* @access public
* @return string
*/
public function encodePath($path = '')
{
return helper::safe64Encode(urlencode($path));
}
/**
* Decode repo path.
*
* @param string $path
* @access public
* @return string
*/
public function decodePath($path = '')
{
return trim(urldecode(helper::safe64Decode($path)), '/');
}
/**
* Check content is binary.
*
* @param string $content
* @param string $suffix
* @access public
* @return bool
*/
public function isBinary($content, $suffix = '')
{
if(strpos($this->config->repo->binary, "|$suffix|") !== false) return true;
$blk = substr($content, 0, 512);
return (
false ||
substr_count($blk, "^\r\n")/512 > 0.3 ||
substr_count($blk, "^ -~")/512 > 0.3 ||
substr_count($blk, "\x00") > 0
);
}
/**
* Check connection
*
* @access public
* @return void
*/
public function checkConnection()
{
if(empty($_POST)) return false;
$scm = $this->post->SCM;
$client = $this->post->client;
$account = $this->post->account;
$password = $this->post->password;
$encoding = strtoupper($this->post->encoding);
$path = $this->post->path;
if($encoding != 'UTF8' and $encoding != 'UTF-8') $path = helper::convertEncoding($path, 'utf-8', $encoding);
if($scm == 'Subversion')
{
$path = '"' . $path . '"';
if(stripos($path, 'https://') === 1 or stripos($path, 'svn://') === 1)
{
$ssh = true;
$remote = true;
$command = "$client info --username $account --password $password --non-interactive --trust-server-cert-failures=cn-mismatch --trust-server-cert --no-auth-cache $path 2>&1";
}
else if(stripos($path, 'file://') === 1)
{
$ssh = false;
$remote = false;
$command = "$client info --non-interactive --no-auth-cache $path 2>&1";
}
else
{
$ssh = false;
$remote = true;
$command = "$client info --username $account --password $password --non-interactive --no-auth-cache $path 2>&1";
}
exec($command, $output, $result);
if($result)
{
$versionCommand = "$client --version --quiet 2>&1";
exec($versionCommand, $versionOutput, $versionResult);
if($versionResult)
{
$message = sprintf($this->lang->repo->error->output, $versionCommand, $versionResult, join("\n", $versionOutput));
echo $message;
die(js::alert($this->lang->repo->error->cmd . '\n' . str_replace(array("\n", "'"), array('\n', '"'), $message)));
}
if($ssh and version_compare(end($versionOutput), '1.6', '<')) die(js::alert($this->lang->repo->error->version));
$message = sprintf($this->lang->repo->error->output, $command, $result, join("\n", $output));
echo $message;
if(stripos($message, 'Expected FS format between') !== false and strpos($message, 'found format') !== false) die(js::alert($this->lang->repo->error->clientVersion));
if(preg_match('/[^\:\/\\A-Za-z0-9_\-\'\"]/', $path)) die(js::alert($this->lang->repo->error->encoding . '\n' . str_replace(array("\n", "'"), array('\n', '"'), $message)));
die(js::alert($this->lang->repo->error->connect . '\n' . str_replace(array("\n", "'"), array('\n', '"'), $message)));
}
}
elseif($scm == 'Git')
{
if(!chdir($path))
{
if(!is_dir($path)) die(js::alert(sprintf($this->lang->repo->error->noFile, $path)));
if(!is_executable($path)) die(js::alert(sprintf($this->lang->repo->error->noPriv, $path)));
die(js::alert($this->lang->repo->error->path));
}
$command = "$client tag 2>&1";
exec($command, $output, $result);
if($result)
{
echo sprintf($this->lang->repo->error->output, $command, $result, join("\n", $output));
die(js::alert($this->lang->repo->error->connect));
}
}
return true;
}
/**
* Replace comment link.
*
* @param string $comment
* @access public
* @return string
*/
public function replaceCommentLink($comment)
{
$stories = array();
$tasks = array();
$bugs = array();
$commonReg = "(?:\s){0,}((?:#|:|:){0,})([0-9, ]{1,})";
$taskReg = '/task' . $commonReg . '/i';
$storyReg = '/story' . $commonReg . '/i';
$bugReg = '/bug' . $commonReg . '/i';
if(preg_match_all($storyReg, $comment, $result))
{
$storyLinks = $this->addLink($result, 'story');
foreach($storyLinks as $search => $replace) $comment = str_replace($search, $replace, $comment);
}
if(preg_match_all($taskReg, $comment, $result))
{
$taskLinks = $this->addLink($result, 'task');
foreach($taskLinks as $search => $replace) $comment = str_replace($search, $replace, $comment);
}
if(preg_match_all($bugReg, $comment, $result))
{
$bugLinks = $this->addLink($result, 'bug');
foreach($bugLinks as $search => $replace) $comment = str_replace($search, $replace, $comment);
}
return $comment;
}
/**
* Add link.
*
* @param string $matches
* @param string $method
* @access public
* @return string
*/
public function addLink($matches, $method)
{
if(empty($matches)) return null;
$replaceLines = array();
foreach($matches[2] as $key => $ids)
{
$spit = strpos($ids, ',') !== false ? ',' : ' ';
$ids = explode(' ', str_replace(',', ' ', $ids));
$links = $method . " " . $matches[1][$key];
foreach($ids as $id)
{
if($id) $links .= html::a(helper::createLink($method, 'view', "id=$id"), $id) . $spit;
}
$replaceLines[$matches[0][$key]] = rtrim($links, $spit);
}
return $replaceLines;
}
}
+88
View File
@@ -0,0 +1,88 @@
<?php
/**
* The side logs view file of repo module of ZenTaoPMS.
*
* @copyright Copyright 2009-2014 QingDao Nature Easy Soft Network Technology Co,LTD (www.cnezsoft.com)
* @license LGPL (http://www.gnu.org/licenses/lgpl.html)
* @author Yidong Wang <yidong@cnezsoft.com>
* @package repo
* @version $Id$
* @link http://www.zentao.net
*/
?>
<?php
$pathInfo = '&root=' . $this->repo->encodePath(empty($path) ? '/' : $path);
if(isset($entry)) $pathInfo .= '&type=file';
?>
<form id='logForm' class='main-table' data-ride='table' action='<?php echo $this->repo->createLink('diff', "repoID=$repoID", "entry=" . $this->repo->encodePath($path))?>' method='post'>
<table class='table table-fixed'>
<thead>
<tr>
<th class='w-40px'></th>
<th class='w-80px'><?php echo $lang->repo->revisionA?></th>
<?php if($repo->SCM == 'Git'):?>
<th class='w-70px'><?php echo $lang->repo->commit?></th>
<?php endif;?>
<th class='w-80px'><?php echo $lang->repo->time?></th>
<th class='w-100px'><?php echo $lang->repo->committer?></th>
<th><?php echo $lang->repo->comment?></th>
</tr>
</thead>
<tbody>
<?php foreach($revisions as $log):?>
<tr>
<td>
<div class='checkbox-primary'>
<input type='checkbox' name='revision[]' value="<?php echo $log->revision?>" />
<label></label>
</div>
</td>
<td class='versions'><span class="revision"><?php echo html::a($this->repo->createLink('revision', "repoID=$repoID&revision={$log->revision}" . $pathInfo), $repo->SCM == 'Git' ? substr($log->revision, 0, 10) : $log->revision);?></span></td>
<?php if($repo->SCM == 'Git'):?>
<td><?php echo $log->commit?></td>
<?php endif;?>
<td><?php echo substr($log->time, 0, 10);?></td>
<td><?php echo $log->committer;?></td>
<?php $comment = htmlspecialchars($log->comment, ENT_QUOTES);?>
<td title='<?php echo $comment?>' class='comment'><?php echo $log->comment?></td>
</tr>
<?php endforeach;?>
</tbody>
</table>
<div class='table-footer'>
<?php if(common::hasPriv('repo', 'diff')) echo html::submitButton($lang->repo->diff, '', count($revisions) < 2 ? 'disabled btn btn-primary' : 'btn btn-primary')?>
<?php echo html::a($this->repo->createLink('log', "repoID=$repoID&entry=&revision=HEAD&type=$logType", "entry=" . $this->repo->encodePath($path)), $lang->repo->allLog);?>
<div class='pull-right'>
<div class='btn-group'>
<?php
$prePage = $pager->pageID == 1 ? 1 : $pager->pageID - 1;
$nextPage = $pager->pageID == $pager->pageTotal ? $pager->pageID : $pager->pageID + 1;
$params = "repoID=$repoID&path=&type=$logType&recTotal={$pager->recTotal}&recPerPage={$pager->recPerPage}";
$preLink = $this->repo->createLink('ajaxSideLogs', "$params&pageID=$prePage", "path=" . $this->repo->encodePath($path));
$nextLink = $this->repo->createLink('ajaxSideLogs', "$params&pageID=$nextPage", "path=" . $this->repo->encodePath($path));
echo html::a($preLink, "<i class='icon icon-angle-left'></i>", '', "class='ajaxPager btn" . ($prePage == $pager->pageID ? ' disabled' : '') . "'");
echo html::a($nextLink, "<i class='icon icon-angle-right'></i>", '', "class='ajaxPager btn" . ($nextPage == $pager->pageID ? ' disabled' : '') . "'");
?>
</div>
</div>
</div>
</form>
<script>
if($("input:checkbox[name='revision[]']:checked").length < 2)
{
$("input:checkbox[name='revision[]']:lt(2)").attr('checked', 'checked');
}
$("input:checkbox[name='revision[]']").each(function(){ if(!$(this).is(':checked')) $(this).attr("disabled","disabled")});
$("input:checkbox[name='revision[]']").click(function(){
var checkNum = $("input:checkbox[name='revision[]']:checked").length;
if (checkNum >= 2)
{
$("input:checkbox[name='revision[]']").each(function(){ if(!$(this).is(':checked')) $(this).attr("disabled","disabled")});
}
else
{
$('#diffRepo').remove();
$("input:checkbox[name='revision[]']").each(function(){$(this).attr("disabled", false)});
}
});
</script>
+83
View File
@@ -0,0 +1,83 @@
<?php
/**
* The create view file of repo module of ZenTaoPMS.
*
* @copyright Copyright 2009-2012 青岛易软天创网络科技有限公司 (QingDao Nature Easy Soft Network Technology Co,LTD www.cnezsoft.com)
* @author Wang Yidong, Zhu Jinyong
* @package repo
* @version $Id: create.html.php $
*/
?>
<?php include '../../common/view/header.html.php';?>
<?php if(common::checkNotCN()):?>
<style>
.user-addon{padding-right: 16px; padding-left: 16px;}
</style>
<?php endif;?>
<div id='mainContent' class='main-content'>
<div class='center-block'>
<div class='main-header'>
<h2><?php echo $lang->repo->create;?></h2>
</div>
<form class='form-indicator main-form' method='post' target='hiddenwin' id='dataform'>
<table class='table table-form'>
<tr>
<th><?php echo $lang->repo->SCM;?></th>
<td><?php echo html::select('SCM', $lang->repo->scmList, 'Subversion', "class='form-control'");?></td>
</tr>
<tr>
<th><?php echo $lang->repo->name;?></th>
<td><?php echo html::input('name', '', "class='form-control'");?></td>
</tr>
<tr>
<th><?php echo $lang->repo->path;?></th>
<td><?php echo html::input('path', '', "class='form-control'")?></td>
<td class='muted'><?php echo $lang->repo->example->path;?></td>
</tr>
<tr>
<th><?php echo $lang->repo->encoding;?></th>
<td><?php echo html::input('encoding', 'utf-8', "class='form-control'");?></td>
</tr>
<tr>
<th><?php echo $lang->repo->client;?></th>
<td><?php echo html::input('client', '', "class='form-control'")?></td>
<td class='muted'><?php echo $lang->repo->example->client;?></td>
</tr>
<tr>
<th><?php echo $lang->repo->account;?></th>
<td><?php echo html::input('account', '', "class='form-control'");?></td>
</tr>
<tr>
<th><?php echo $lang->repo->password;?></th>
<td>
<div class='input-group'>
<?php echo html::password('password', '', "class='form-control'");?>
<span class='input-group-addon fix-border fix-padding'></span>
<?php echo html::select('encrypt', $lang->repo->encryptList, 'base64', "class='form-control'");?>
</div>
</td>
</tr>
<tr>
<th><?php echo $lang->repo->acl;?></th>
<td class='acl'>
<div class='input-group mgb-10'>
<span class='input-group-addon'><?php echo $lang->repo->group?></span>
<?php echo html::select('acl[groups][]', $groups, '', "class='form-control chosen' multiple")?>
</div>
<div class='input-group'>
<span class='input-group-addon user-addon'><?php echo $lang->repo->user?></span>
<?php echo html::select('acl[users][]', $users, '', "class='form-control chosen' multiple")?>
</div>
</td>
</tr>
<tr>
<td colspan='3' class='text-center form-actions'>
<?php echo html::submitButton();?>
<?php echo html::backButton();?>
</td>
</tr>
</table>
</form>
</div>
</div>
<?php include '../../common/view/footer.html.php';?>
+174
View File
@@ -0,0 +1,174 @@
<?php
/**
* The diff view file of repo module of ZenTaoPMS.
*
* @copyright Copyright 2009-2012 青岛易软天创网络科技有限公司 (QingDao Nature Easy Soft Network Technology Co,LTD www.cnezsoft.com)
* @author Wang Yidong, Zhu Jinyong
* @package repo
* @version $Id: browse.html.php $
*/
?>
<?php include '../../common/view/header.html.php';?>
<?php include '../../common/view/form.html.php';?>
<?php include '../../common/view/kindeditor.html.php';?>
<?php if(!isonlybody()):?>
<div id='mainMenu' class='clearfix'>
<div class='btn-toolbar pull-left'>
<?php
$backURI = $this->session->repoView ? $this->session->repoView : $this->session->repoList;
if($backURI)
{
echo html::a($backURI, "<i class='icon icon-back icon-sm'></i>" . $lang->goback, '', "class='btn btn-link'");
}
else
{
echo html::backButton("<i class='icon icon-back icon-sm'></i>" . $lang->goback, '', "btn btn-link");
}
?>
<div class="divider"></div>
<div class="page-title">
<?php
echo html::a($this->repo->createLink('browse', "repoID=$repoID"), $repo->name);
$paths= explode('/', $entry);
$fileName = array_pop($paths);
$postPath = '';
foreach($paths as $pathName)
{
$postPath .= $pathName . '/';
echo '/' . ' ' . html::a($this->repo->createLink('browse', "repoID=$repoID", "path=" . $this->repo->encodePath($postPath)), trim($pathName, '/'));
}
echo '/' . ' ' . $fileName;
if($repo->SCM == 'Git')
{
$oldRevision = $oldRevision == '^' ? "$newRevision" : $oldRevision;
echo " <span class='label label-info'>" . substr($oldRevision, 0, 10) . " : " . substr($newRevision, 0, 10) . ' (' . $historys[$oldRevision] . ' : ' . $historys[$newRevision] . ')</span>';
}
else
{
$oldRevision = $oldRevision == '^' ? $newRevision - 1 : $oldRevision;
echo " <span class='label label-info'>$oldRevision : $newRevision</span>";
}
?>
<span class='label label-exchange'><i class="icon icon-exchange"></i></span>
</div>
</div>
</div>
<?php endif;?>
<div class="repo panel">
<div class='panel-heading'>
<form method='post'>
<div class='btn-group pull-right'>
<?php echo html::commonButton($lang->repo->viewDiffList['inline'], "id='inline'", $arrange == 'inline' ? 'active btn btn-sm' : 'btn btn-sm')?>
<?php echo html::commonButton($lang->repo->viewDiffList['appose'], "id='appose'", $arrange == 'appose' ? 'active btn btn-sm' : 'btn btn-sm')?>
</div>
<div class='btn-toolbar'>
<div class='btn-group'>
<?php if(common::hasPriv('repo', 'download')) echo html::a($this->repo->createLink('download', "repoID=$repoID&path=&fromRevison=$oldRevision&toRevision=$newRevision&type=path", "path=" . $this->repo->encodePath($entry)), $lang->repo->downloadDiff, 'hiddenwin', "class='btn btn-sm btn-download'");?>
<div class='btn-group'>
<?php echo html::commonButton(zget($lang->repo->encodingList, $encoding, $lang->repo->encoding) . "<span class='caret'></span>", "data-toggle='dropdown'", 'btn dropdown-toggle btn-sm')?>
<ul class='dropdown-menu' role='menu'>
<?php foreach($lang->repo->encodingList as $key => $val):?>
<li><?php echo html::a('javascript:changeEncoding("'. $key . '")', $val)?></li>
<?php endforeach;?>
</ul>
</div>
</div>
</div>
<?php echo html::hidden('arrange', $arrange) . html::hidden('encoding', $encoding) . html::hidden('revision[]', $newRevision) . html::hidden('revision[]', $oldRevision)?>
</form>
</div>
<?php foreach($diffs as $diffFile):?>
<div class='repoCode'>
<table class='table diff' id='diff'>
<caption><?php echo $diffFile->fileName;?></caption>
<?php if(empty($diffFile->contents)) continue;?>
<?php foreach($diffFile->contents as $content):?>
<?php
$oldCurrentLine = $content->oldStartLine;
$newCurrentLine = $content->newStartLine;
?>
<?php if(!in_array($oldCurrentLine, array('0', '1')) and !in_array($newCurrentLine, array('0', '1'))):?>
<tr data-line='<?php echo $newCurrentLine ?>' class='empty'>
<th class='w-num text-center'>...</th>
<?php if($arrange == 'appose'):?>
<td class='none code'></td>
<?php endif;?>
<th class='w-num text-center'>...</th>
<td class='none code'></td>
</tr>
<?php endif?>
<?php if($arrange == 'inline'):?>
<?php foreach($content->lines as $line):?>
<tr data-line='<?php echo $line->newlc ?>'>
<th class='w-num text-right'><?php if($line->type != 'new') echo $line->oldlc?></th>
<th class='w-num text-left'><?php if($line->type != 'old') echo $line->newlc?></th>
<td class='line-<?php echo $line->type?> code'><?php
$line->line = $repo->SCM == 'Subversion' ? htmlspecialchars($line->line) : $line->line;
echo $line->type == 'old' ? preg_replace('/^\-/', '&ndash;', $line->line) : ($line->type == 'new' ? $line->line : ' ' . $line->line);
?></td>
</tr>
<?php endforeach;?>
<?php else:?>
<?php foreach($content->lines as $line):?>
<tr data-line='<?php echo $line->newlc ?>'>
<?php
if($line->type == 'old')
{
$oldlc = $line->oldlc;
$newlc = '';
if(isset($content->new[$oldlc]))
{
$newlc = $line->oldlc;
$line->type = 'custom';
}
}
else
{
$oldlc = $line->oldlc;
$newlc = $line->newlc;
if(!isset($content->new[$newlc])) continue;
}
?>
<th class='w-num text-right'><?php echo $oldlc?></th>
<td class='w-code line-<?php if($line->type != 'new')echo $line->type?> <?php if($line->type == 'custom') echo "line-old"?> code'><?php
if(!isset($content->old[$oldlc])) $content->old[$oldlc] = '';
$content->old[$oldlc] = $repo->SCM == 'Subversion' ? htmlspecialchars($content->old[$oldlc]) : $content->old[$oldlc];
if(!empty($oldlc)) echo $line->type != 'all' ? preg_replace('/^\-/', '&ndash;', $content->old[$oldlc]) : ' ' . $content->old[$oldlc];
?></td>
<th class='w-num text-right'><?php echo $newlc?></th>
<td class='w-code line-<?php if($line->type != 'old') echo $line->type?> <?php if($line->type == 'custom') echo "line-new"?> code'><?php
if(!isset($content->new[$newlc])) $content->new[$newlc] = '';
$content->new[$newlc] = $repo->SCM == 'Subversion' ? htmlspecialchars($content->new[$newlc]) : $content->new[$newlc];
if(!empty($newlc)) echo $line->type != 'all' ? $content->new[$newlc] : ' ' . $content->new[$newlc];
?></td>
<?php
if(isset($content->old[$oldlc])) unset($content->old[$oldlc]);
if(isset($content->new[$newlc])) unset($content->new[$newlc]);
?>
</tr>
<?php endforeach;?>
<?php endif;?>
<?php endforeach;?>
</table>
</div>
<?php endforeach?>
</div>
<div class='revisions hidden'>
<?php
if($repo->SCM == 'Git')
{
$oldRevision = $oldRevision == '^' ? "$newRevision" : $oldRevision;
echo " <span class='label label-info'>" . substr($oldRevision, 0, 10) . " : " . substr($newRevision, 0, 10) . ' (' . $historys[$oldRevision] . ' : ' . $historys[$newRevision] . ')</span>';
}
else
{
$oldRevision = $oldRevision == '^' ? $newRevision - 1 : $oldRevision;
echo " <span class='label label-info'>$oldRevision : $newRevision</span>";
}
?>
</div>
<form method="post" id="exchange" class="hidden">
<input type="hidden" name="revision[]" value="<?php echo $oldRevision;?>"/>
<input type="hidden" name="revision[]" value="<?php echo $newRevision;?>"/>
</form>
<?php include '../../common/view/footer.html.php';?>
+76
View File
@@ -0,0 +1,76 @@
<?php
/**
* The log view file of repo module of ZenTaoPMS.
*
* @copyright Copyright 2009-2012 青岛易软天创网络科技有限公司 (QingDao Nature Easy Soft Network Technology Co,LTD www.cnezsoft.com)
* @author Wang Yidong, Zhu Jinyong
* @package repo
* @version $Id: log.html.php $
*/
?>
<?php include '../../common/view/header.html.php';?>
<div id='mainMenu' class='clearfix'>
<div class="btn-toolbar pull-left">
<div class="page-title">
<strong>
<?php
echo html::a($this->repo->createLink('log', "repoID=$repoID"), $repo->name);
$paths= explode('/', $entry);
$fileName = array_pop($paths);
$postPath = '';
foreach($paths as $pathName)
{
$postPath .= $pathName . '/';
echo '/' . ' ' . html::a($this->repo->createLink('log', "repoID=$repoID", "entry=" . $this->repo->encodePath($postPath)), trim($pathName, '/'));
}
echo '/' . ' ' . $fileName;
echo $repo->SCM == 'Git' ? " @ " . substr($revision, 0, 10) : " @ r" . $revision;;
?>
</strong>
</div>
</div>
</div>
<div id="mainContent">
<nav id="contentNav">
<ul class="nav nav-default">
<?php $encodeEntry = $this->repo->encodePath($entry);?>
<li><a><?php echo $lang->repo->log;?></a></li>
<?php if($info->kind == 'file') echo '<li>' . html::a($this->repo->createLink('download', "repoID=$repoID&path=&fromRevision=$revision", "path=$encodeEntry"), $lang->repo->download, 'hiddenwin') . '</li>';?>
</ul>
</nav>
<form id='logForm' class='main-table' data-ride='table' action='<?php echo $this->repo->createLink('diff', "repoID=$repoID", "entry=" . $this->repo->encodePath($entry))?>' method='post'>
<table class='table table-fixed' id='logList'>
<thead>
<tr>
<th class='w-40px'></th>
<th width='w-110px'><?php echo $lang->repo->revision?></th>
<th width='w-150px'><?php echo $lang->repo->date?></th>
<th width='w-80px'><?php echo $lang->repo->committer?></th>
<th><?php echo $lang->repo->comment?></th>
</tr>
</thead>
<tbody>
<?php foreach($logs as $log):?>
<tr>
<td>
<div class='checkbox-primary'>
<input type='checkbox' name='revision[]' value="<?php echo $log->revision?>" />
<label></label>
</div>
</td>
<td class='versions'><?php echo html::a($this->repo->createLink('revision', "repoID=$repoID&revision=" . $log->revision), substr($log->revision, 0, 10));?></td>
<td><?php echo $log->time;?></td>
<td><?php echo $log->committer;?></td>
<td class='comment'><?php echo $log->comment;?></td>
</tr>
<?php endforeach;?>
</tbody>
</table>
<div class='table-footer'>
<?php echo html::submitButton($lang->repo->diff, '', 'btn btn-primary')?>
<?php $pager->show('right', 'pagerjs');?>
</div>
</form>
</div>
<?php include '../../common/view/footer.html.php';?>
+91
View File
@@ -0,0 +1,91 @@
<?php
/**
* The revision view file of repo module of ZenTaoPMS.
*
* @copyright Copyright 2009-2012 青岛易软天创网络科技有限公司 (QingDao Nature Easy Soft Network Technology Co,LTD www.cnezsoft.com)
* @author Wang Yidong, Zhu Jinyong
* @package repo
* @version $Id: revision.html.php $
*/
?>
<?php
session_start();
$_SESSION['repoList'] = $this->app->getURI(true);
session_write_close();
$pathInfo = empty($path) ? '' : '&root=' . $this->repo->encodePath($path);
$preDir = empty($parentDir) ? $pathInfo : '&path=' . $this->repo->encodePath($parentDir);
$typeInfo = $type == 'file' ? '&type=file' : '';
?>
<?php include '../../common/view/header.html.php';?>
<div id='mainMenu' class='clearfix'>
<div class='btn-toolbar pull-left'>
<?php echo html::a($this->repo->createLink('browse', "repoID=$repoID" . $preDir), "<i class='icon icon-back'></i>" . $lang->goback, '', "class='btn btn-link'");?>
<div class="divider"></div>
<div class="page-title">
<?php echo $lang->repo->revisionA . ' ' . ($repo->SCM == 'Git' ? $this->repo->getGitRevisionName($revision, $log->commit) : $revision);?>
</div>
</div>
</div>
<div id='mainContent' class='main-row'>
<div class='main-col col-8'>
<div class='cell'>
<div class='detail'>
<div class='detail-title'>
<?php echo $lang->repo->changes;?>
<div class='pull-right'><?php if(common::hasPriv('repo', 'diff')) echo html::a($this->repo->createLink('diff', "repoID=$repoID&entry=&fromRevision=$oldRevision&toRevision=$revision"), $lang->repo->diffAll);?></div>
</div>
<div class='detail-content'>
<table class='table no-margin'>
<?php foreach($changes as $path => $change):?>
<tr>
<td><?php echo "<span class='label label-info label-badge'>" . $change['action'] . '</span> ' . $path?></td>
<td class='w-80px text-center'><?php echo zget($change, 'view', '') . zget($change, 'diff', '')?></td>
</tr>
<?php endforeach;?>
</table>
</div>
</div>
</div>
</div>
<div class='side-col col-4'>
<div class='cell'>
<div class='detail'>
<div class='detail-title'><?php echo $lang->repo->info?></div>
<div class='detail-content'>
<table class='table table-data'>
<tr>
<th class='w-80px'><?php echo $lang->repo->committer?></th>
<td><?php echo $log->committer?></td>
</tr>
<tr>
<th><?php echo $lang->repo->revisionA?></th>
<td><?php echo $log->revision?></td>
</tr>
<?php if($repo->SCM == 'Git'):?>
<tr>
<th><?php echo $lang->repo->commit?></th>
<td><?php echo $log->commit?></td>
</tr>
<?php endif;?>
<tr>
<th><?php echo $lang->repo->comment?></th>
<td><?php echo $log->comment?></td>
</tr>
<tr>
<th><?php echo $lang->repo->time?></th>
<td><?php echo $log->time?></td>
</tr>
</table>
</div>
</div>
</div>
</div>
</div>
<div id="mainActions" class='main-actions'>
<nav class="container">
<?php if(!empty($preAndNext->pre)) echo html::a($this->repo->createLink('revision', "repoID=$repoID&revision={$preAndNext->pre}" . $pathInfo . $typeInfo, "", 'html'), "<i class='icon-pre icon-chevron-left'></i>", '', "id='prevPage' class='btn btn-info' title='{$preAndNext->pre}'")?>
<?php if(!empty($preAndNext->next)) echo html::a($this->repo->createLink('revision', "repoID=$repoID&revision={$preAndNext->next}" . $pathInfo . $typeInfo, "", 'html'), "<i class='icon-pre icon-chevron-right'></i>", '', "id='nextPage' class='btn btn-info' title='{$preAndNext->next}'")?>
</nav>
</div>
<?php include '../../common/view/footer.html.php';?>
+87
View File
@@ -0,0 +1,87 @@
<?php
/**
* The settings view file of repo module of ZenTaoPMS.
*
* @copyright Copyright 2009-2012 青岛易软天创网络科技有限公司 (QingDao Nature Easy Soft Network Technology Co,LTD www.cnezsoft.com)
* @author Wang Yidong, Zhu Jinyong
* @package repo
* @version $Id: setting.html.php $
*/
?>
<?php include '../../common/view/header.html.php';?>
<?php if(common::checkNotCN()):?>
<style>
.user-addon{padding-right: 16px; padding-left: 16px;}
</style>
<?php endif;?>
<div id='mainContent' class='main-content'>
<div class='center-block'>
<div class='main-header'>
<h2><?php echo $lang->repo->settings;?></h2>
</div>
<form class='form-indicator main-form' method='post' target='hiddenwin'>
<table class='table table-form'>
<tr>
<th><?php echo $lang->repo->SCM;?></th>
<td><?php echo html::select('SCM', $lang->repo->scmList, $repo->SCM, "class='form-control'");?></td>
</tr>
<tr>
<th><?php echo $lang->repo->name;?></th>
<td><?php echo html::input('name', $repo->name, "class='form-control'");?></td>
</tr>
<tr>
<th><?php echo $lang->repo->path;?></th>
<td><?php echo html::input('path', $repo->path, "class='form-control'")?></td>
<td class='text-muted'><?php echo $lang->repo->example->path;?></td>
</tr>
<tr>
<th><?php echo $lang->repo->encoding;?></th>
<td><?php echo html::input('encoding', $repo->encoding, "class='form-control'")?></td>
<td class='text-muted'><?php echo $lang->repo->example->encoding;?></td>
</tr>
<tr>
<th><?php echo $lang->repo->client;?></th>
<td><?php echo html::input('client', $repo->client, "class='form-control'")?></td>
<td class='text-muted'><?php echo $lang->repo->example->client;?></td>
</tr>
<tr>
<th><?php echo $lang->repo->account;?></th>
<td>
<?php echo html::input('account', $repo->account, "class='form-control' autocomplete='off'");?>
<input type='text' style="display:none">
</td>
</tr>
<tr>
<th><?php echo $lang->repo->password;?></th>
<td>
<div class='input-group'>
<?php echo html::password('password', $repo->password, "class='form-control'");?>
<span class='input-group-addon fix-border fix-padding'></span>
<?php echo html::select('encrypt', $lang->repo->encryptList, $repo->encrypt, "class='form-control'");?>
</div>
</td>
</tr>
<tr>
<th><?php echo $lang->repo->acl;?></th>
<td>
<div class='input-group mgb-10'>
<span class='input-group-addon'><?php echo $lang->repo->group?></span>
<?php echo html::select('acl[groups][]', $groups, empty($repo->acl->groups) ? '' : join(',', $repo->acl->groups), "class='form-control chosen' multiple")?>
</div>
<div class='input-group'>
<span class='input-group-addon user-addon'><?php echo $lang->repo->user?></span>
<?php echo html::select('acl[users][]', $users, empty($repo->acl->users) ? '' : join(',', $repo->acl->users), "class='form-control chosen' multiple")?>
</div>
</td>
</tr>
<tr>
<td colspan='3' class='text-center form-actions'>
<?php echo html::submitButton();?>
<?php echo html::backButton();?>
</td>
</tr>
</table>
</form>
</div>
</div>
<?php include '../../common/view/footer.html.php';?>
+45
View File
@@ -0,0 +1,45 @@
<?php
/**
* The showSyncComment view file of repo module of ZenTaoPMS.
*
* @copyright Copyright 2009-2010 QingDao Nature Easy Soft Network Technology Co,LTD (www.cnezsoft.com)
* @license LGPL (http://www.gnu.org/licenses/lgpl.html)
* @author Yidong Wang <yidong@cnezsoft.com>
* @package repo
* @version $Id$
* @link http://www.zentao.net
*/
?>
<?php include '../../common/view/header.html.php';?>
<div id="mainContent" class="main-content">
<div class='cell'>
<div class='alert with-icon'>
<i class="icon-check-sign"></i>
<div class='content'>
<h3><?php echo $lang->repo->notice->syncing;?></h3>
<hr>
<p><?php echo $lang->repo->notice->syncedCount?><span id='commits'><?php echo $version?></span></p>
</div>
</div>
</div>
</div>
<script language='Javascript'>
$(function(){
var link = createLink('repo', 'ajaxSyncComment', "repoID=<?php echo $repoID?>");
function syncComments()
{
$.get(link, function(data)
{
if(data == 'finish')
{
$('#caption').text('<?php echo $lang->repo->notice->syncComplete?>');
return self.location = createLink('repo', 'log', "repoID=<?php echo $repoID?>");
}
$('#commits').html(parseInt($('#commits').html()) + parseInt(data));
setTimeout(syncComments, 10);
});
}
setTimeout(syncComments, 500);
})
</script>
<?php include '../../common/view/footer.html.php';?>
+98
View File
@@ -0,0 +1,98 @@
<?php
/**
* The create view file of repo module of ZenTaoPMS.
*
* @copyright Copyright 2009-2012 青岛易软天创网络科技有限公司 (QingDao Nature Easy Soft Network Technology Co,LTD www.cnezsoft.com)
* @author Wang Yidong, Zhu Jinyong
* @package repo
* @version $Id: create.html.php $
*/
?>
<?php
include '../../common/view/header.html.php';
include '../../common/view/form.html.php';
include '../../common/view/kindeditor.html.php';
js::import($jsRoot . 'misc/highlight/highlight.pack.js');
css::import($jsRoot . 'misc/highlight/styles/github.css');
$encodePath = $this->repo->encodePath($entry);
$version = " <span class=\"label label-info\">$revisionName</span>";
?>
<?php if(!isonlybody()):?>
<div id='mainMenu' class='clearfix'>
<div class='btn-toolbar pull-left'>
<?php echo html::a($this->session->repoList, "<i class='icon icon-back icon-sm'></i>" . $lang->goback, '', "class='btn btn-link'");?>
<div class="divider"></div>
<div class="page-title">
<strong>
<?php
echo html::a($this->repo->createLink('browse', "repoID=$repoID"), $repo->name);
$paths= explode('/', $entry);
$fileName = array_pop($paths);
$postPath = '';
foreach($paths as $pathName)
{
$postPath .= $pathName . '/';
echo '/' . ' ' . html::a($this->repo->createLink('browse', "repoID=$repoID", "path=" . $this->repo->encodePath($postPath)), trim($pathName, '/'));
}
echo '/' . ' ' . $fileName;
echo $version;
?>
</strong>
</div>
</div>
<div class="btn-toolbar pull-right">
<?php echo html::a($this->repo->createLink('revision', "repoID=$repoID&revision=$revision"), $lang->repo->allChanges, '', "class='btn btn-primary'")?>
</div>
</div>
<?php endif;?>
<?php if(!isonlybody()):?>
<div id="mainContent" class="main-row fade">
<?php endif;?>
<div class="main-col repoCode main">
<div class="content panel">
<div class='panel-heading'>
<div class='panel-title'><?php echo $entry?></div>
<div class='panel-actions'>
<?php if($suffix != 'binary' and strpos($config->repo->images, "|$suffix|") === false):?>
<?php
if(common::hasPriv('repo', 'download')) echo html::a($this->repo->createLink('download', "repoID=$repoID&path=&fromRevision=$revision", "path=$encodePath"), html::icon('download-alt') . $lang->repo->download, 'hiddenwin', "class='btn btn-sm btn-primary'");
?>
<?php endif;?>
<div class='btn-group'>
<?php echo html::commonButton(zget($lang->repo->encodingList, $encoding, $lang->repo->encoding) . "<span class='caret'></span>", "id='encoding' data-toggle='dropdown'", 'btn btn-sm btn-primary dropdown-toggle')?>
<ul class='dropdown-menu' role='menu' aria-labelledby='encoding'>
<?php foreach($lang->repo->encodingList as $key => $val):?>
<li><?php echo html::a($this->repo->createLink('view', "repoID=$repoID&entry=&revision=$revision&showBug=$showBug&encoding=$key", "entry=$encodePath", 'html', isonlybody()), $val)?></li>
<?php endforeach;?>
</ul>
</div>
</div>
</div>
<?php if(strpos($config->repo->images, "|$suffix|") !== false):?>
<div class='image'><img src='data:image/<?php echo $suffix?>;base64,<?php echo $content?>' /></div>
<?php elseif($suffix == 'binary'):?>
<div class='binary'><?php echo html::a($this->repo->createLink('download', "repoID=$repoID&path=&fromRevision=$revision", "path=" . $this->repo->encodePath($entry)), "<i class='icon-download'></i>", 'hiddenwin', "title='{$lang->repo->download}'"); ?></div>
<?php else:?>
<pre class="<?php echo $config->program->suffix[$suffix];?>"><?php echo trim(htmlspecialchars($content, defined('ENT_SUBSTITUTE') ? ENT_QUOTES | ENT_SUBSTITUTE : ENT_QUOTES));?></pre>
<?php endif;?>
</div>
</div>
<?php if(!isonlybody()):?>
<div class="side-col" id="sidebar">
<div class="sidebar-toggle"><i class="icon icon-angle-right"></i></div>
<div class='side-body'><?php include 'ajaxsidelogs.html.php';?></div>
</div>
<?php endif;?>
<?php if(!isonlybody()):?>
</div>
<?php endif;?>
<?php if(!isonlybody()):?>
<div id="mainActions" class='main-actions'>
<nav class="container">
<?php if(!empty($preAndNext->pre)) echo html::a($this->repo->createLink('view', "repoID=$repoID&entry=&revision={$preAndNext->pre}&showBug=$showBug", "entry=$encodePath", 'html', isonlybody()), "<i class='icon-pre icon-chevron-left'></i>", '', "id='prevPage' class='btn btn-info' title='{$preAndNext->pre}'")?>
<?php if(!empty($preAndNext->next)) echo html::a($this->repo->createLink('view', "repoID=$repoID&entry=&revision={$preAndNext->next}&showBug=$showBug", "entry=$encodePath", 'html', isonlybody()), "<i class='icon-pre icon-chevron-right'></i>", '', "id='nextPage' class='btn btn-info' title='{$preAndNext->next}'")?>
</nav>
</div>
<?php endif;?>
<?php include '../../common/view/footer.html.php';?>
+87
View File
@@ -0,0 +1,87 @@
<!-- saved from url=(0013)about:internet -->
<!-- ^^^ This is for IE not to show security warning for local files,
see http://www.microsoft.com/technet/prodtechnol/winxppro/maintain/sp2brows.mspx-->
<!--
Highlighted code export
Copyright (c) Vladimir Gubarkov <xonixx@gmail.com>
-->
<html>
<head>
<title>Highlited code export</title>
<link rel="stylesheet" href="styles/default.css">
<meta charset="utf-8">
<style type="text/css">
#t1, #t2 { width: 100%;}
tr { vertical-align: top; }
address { margin-top: 4em; }
</style>
<script src="highlight.pack.js"></script>
<script>hljs.initHighlightingOnLoad();</script>
</head>
<body>
<script type="text/javascript">
String.prototype.escape = function() {
return this.replace(/&/gm, '&amp;').replace(/</gm, '&lt;').replace(/>/gm, '&gt;');
}
function doIt() {
var viewDiv = document.getElementById("highlight-view");
var t1 = document.getElementById("t1");
var t2 = document.getElementById("t2");
var selector = document.getElementById("langSelector");
var selectedLang = selector.options[selector.selectedIndex].value.toLowerCase();
if(selectedLang) {
viewDiv.innerHTML = '<pre><code class="'+selectedLang+'">'+t1.value.escape()+"</code></pre>";
} else { // try auto
viewDiv.innerHTML = '<pre><code>' + t1.value.escape() + "</code></pre>";
}
hljs.highlightBlock(viewDiv.firstChild.firstChild);
t2.value = viewDiv.innerHTML;
}
function copyToBuffer(textToCopy) {
if (window.clipboardData) { // IE
window.clipboardData.setData("Text", textToCopy);
} else if (window.netscape) { // FF
// from http://developer.mozilla.org/en/docs/Using_the_Clipboard
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
var gClipboardHelper = Components.classes["@mozilla.org/widget/clipboardhelper;1"].getService(Components.interfaces.nsIClipboardHelper);
gClipboardHelper.copyString(textToCopy);
}
}
</script>
<script type="text/javascript">
var langSelectorHtml = '<label>Language <select id="langSelector">';
langSelectorHtml += '<option value="">Auto</option>';
for (var i in hljs.LANGUAGES) {
if (hljs.LANGUAGES.hasOwnProperty(i))
langSelectorHtml += '<option value=\"'+i+'\">'+i.charAt(0).toUpperCase()+i.substr(1)+'</option>';
}
langSelectorHtml += '</select></label>';
document.write(langSelectorHtml);
</script>
<table width="100%">
<tr>
<td><textarea rows="20" cols="50" id="t1"></textarea></td>
<td><textarea rows="20" cols="50" id="t2"></textarea></td>
</tr>
<tr>
<td>Write a code snippet</td>
<td>Get HTML to paste anywhere (for actual styles and colors see sample.css)</td>
</tr>
</table>
<table width="98%">
<tr>
<td><input type="button" value="Export &rarr;" onclick="doIt()"/></td>
<td align="right"><input type="button" value="Copy to buffer" onclick="copyToBuffer(document.getElementById('t2').value);"/></td>
</tr>
</table>
<div id="highlight-view"></div>
<address>
Export script: <a href="mailto:xonixx@gmail.com">Vladimir Gubarkov</a><br>
Highlighting: <a href="http://softwaremaniacs.org/soft/highlight/">highlight.js</a>
</address>
</body>
</html>
File diff suppressed because one or more lines are too long
+124
View File
@@ -0,0 +1,124 @@
/*
github.com style (c) Vasily Polovnyov <vast@whiteants.net>
*/
.hljs {
display: block;
overflow-x: auto;
padding: 0.5em;
color: #333;
background: #f8f8f8;
-webkit-text-size-adjust: none;
}
.hljs-comment,
.diff .hljs-header,
.hljs-javadoc {
color: #998;
font-style: italic;
}
.hljs-keyword,
.css .rule .hljs-keyword,
.hljs-winutils,
.nginx .hljs-title,
.hljs-subst,
.hljs-request,
.hljs-status {
color: #333;
font-weight: bold;
}
.hljs-number,
.hljs-hexcolor,
.ruby .hljs-constant {
color: #008080;
}
.hljs-string,
.hljs-tag .hljs-value,
.hljs-phpdoc,
.hljs-dartdoc,
.tex .hljs-formula {
color: #d14;
}
.hljs-title,
.hljs-id,
.scss .hljs-preprocessor {
color: #900;
font-weight: bold;
}
.hljs-list .hljs-keyword,
.hljs-subst {
font-weight: normal;
}
.hljs-class .hljs-title,
.hljs-type,
.vhdl .hljs-literal,
.tex .hljs-command {
color: #458;
font-weight: bold;
}
.hljs-tag,
.hljs-tag .hljs-title,
.hljs-rules .hljs-property,
.django .hljs-tag .hljs-keyword {
color: #000080;
font-weight: normal;
}
.hljs-attribute,
.hljs-variable,
.lisp .hljs-body {
color: #008080;
}
.hljs-regexp {
color: #009926;
}
.hljs-symbol,
.ruby .hljs-symbol .hljs-string,
.lisp .hljs-keyword,
.clojure .hljs-keyword,
.scheme .hljs-keyword,
.tex .hljs-special,
.hljs-prompt {
color: #990073;
}
.hljs-built_in {
color: #0086b3;
}
.hljs-preprocessor,
.hljs-pragma,
.hljs-pi,
.hljs-doctype,
.hljs-shebang,
.hljs-cdata {
color: #999;
font-weight: bold;
}
.hljs-deletion {
background: #fdd;
}
.hljs-addition {
background: #dfd;
}
.diff .hljs-change {
background: #0086b3;
}
.hljs-chunk {
color: #aaa;
}
+147
View File
@@ -0,0 +1,147 @@
/*
Google Code style (c) Aahan Krish <geekpanth3r@gmail.com>
*/
.hljs {
display: block;
overflow-x: auto;
padding: 0.5em;
background: white;
color: black;
-webkit-text-size-adjust: none;
}
.hljs-comment,
.hljs-javadoc {
color: #800;
}
.hljs-keyword,
.method,
.hljs-list .hljs-keyword,
.nginx .hljs-title,
.hljs-tag .hljs-title,
.setting .hljs-value,
.hljs-winutils,
.tex .hljs-command,
.http .hljs-title,
.hljs-request,
.hljs-status {
color: #008;
}
.hljs-envvar,
.tex .hljs-special {
color: #660;
}
.hljs-string,
.hljs-tag .hljs-value,
.hljs-cdata,
.hljs-filter .hljs-argument,
.hljs-attr_selector,
.apache .hljs-cbracket,
.hljs-date,
.hljs-regexp,
.coffeescript .hljs-attribute {
color: #080;
}
.hljs-sub .hljs-identifier,
.hljs-pi,
.hljs-tag,
.hljs-tag .hljs-keyword,
.hljs-decorator,
.ini .hljs-title,
.hljs-shebang,
.hljs-prompt,
.hljs-hexcolor,
.hljs-rules .hljs-value,
.hljs-literal,
.hljs-symbol,
.ruby .hljs-symbol .hljs-string,
.hljs-number,
.css .hljs-function,
.clojure .hljs-attribute {
color: #066;
}
.hljs-class .hljs-title,
.smalltalk .hljs-class,
.hljs-javadoctag,
.hljs-yardoctag,
.hljs-phpdoc,
.hljs-dartdoc,
.hljs-type,
.hljs-typename,
.hljs-tag .hljs-attribute,
.hljs-doctype,
.hljs-class .hljs-id,
.hljs-built_in,
.setting,
.hljs-params,
.hljs-variable {
color: #606;
}
.css .hljs-tag,
.hljs-rules .hljs-property,
.hljs-pseudo,
.hljs-subst {
color: #000;
}
.css .hljs-class,
.css .hljs-id {
color: #9b703f;
}
.hljs-value .hljs-important {
color: #ff7700;
font-weight: bold;
}
.hljs-rules .hljs-keyword {
color: #c5af75;
}
.hljs-annotation,
.apache .hljs-sqbracket,
.nginx .hljs-built_in {
color: #9b859d;
}
.hljs-preprocessor,
.hljs-preprocessor *,
.hljs-pragma {
color: #444;
}
.tex .hljs-formula {
background-color: #eee;
font-style: italic;
}
.diff .hljs-header,
.hljs-chunk {
color: #808080;
font-weight: bold;
}
.diff .hljs-change {
background-color: #bccff9;
}
.hljs-addition {
background-color: #baeeba;
}
.hljs-deletion {
background-color: #ffc8bd;
}
.hljs-comment .hljs-yardoctag {
font-weight: bold;
}