* move common file-specific functionality out of IDF_Views_Source into new
IDF_FileUtil and change all occurrences accordingly * cache /etc/mime.types (or whatever is configured) per request in a static variable in IDF_FileUtil * always link directly to the download of attached files in the issues view and place an additional "view" link only for those attachments which we recognize as text with our weak criteria (closes issue 575)
This commit is contained in:
parent
6d7d7ebbfa
commit
dffeb1f9d5
@ -169,8 +169,8 @@ class IDF_Diff
|
|||||||
$out = '';
|
$out = '';
|
||||||
foreach ($this->files as $filename=>$file) {
|
foreach ($this->files as $filename=>$file) {
|
||||||
$pretty = '';
|
$pretty = '';
|
||||||
$fileinfo = IDF_Views_Source::getMimeType($filename);
|
$fileinfo = IDF_FileUtil::getMimeType($filename);
|
||||||
if (IDF_Views_Source::isSupportedExtension($fileinfo[2])) {
|
if (IDF_FileUtil::isSupportedExtension($fileinfo[2])) {
|
||||||
$pretty = ' prettyprint';
|
$pretty = ' prettyprint';
|
||||||
}
|
}
|
||||||
$out .= "\n".'<table class="diff" summary="">'."\n";
|
$out .= "\n".'<table class="diff" summary="">'."\n";
|
||||||
@ -350,9 +350,9 @@ class IDF_Diff
|
|||||||
|
|
||||||
public function renderCompared($chunks, $filename)
|
public function renderCompared($chunks, $filename)
|
||||||
{
|
{
|
||||||
$fileinfo = IDF_Views_Source::getMimeType($filename);
|
$fileinfo = IDF_FileUtil::getMimeType($filename);
|
||||||
$pretty = '';
|
$pretty = '';
|
||||||
if (IDF_Views_Source::isSupportedExtension($fileinfo[2])) {
|
if (IDF_FileUtil::isSupportedExtension($fileinfo[2])) {
|
||||||
$pretty = ' prettyprint';
|
$pretty = ' prettyprint';
|
||||||
}
|
}
|
||||||
$out = '';
|
$out = '';
|
||||||
|
165
src/IDF/FileUtil.php
Normal file
165
src/IDF/FileUtil.php
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
<?php
|
||||||
|
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||||
|
/*
|
||||||
|
# ***** BEGIN LICENSE BLOCK *****
|
||||||
|
# This file is part of InDefero, an open source project management application.
|
||||||
|
# Copyright (C) 2010 Céondo Ltd and contributors.
|
||||||
|
#
|
||||||
|
# InDefero is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# InDefero is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
#
|
||||||
|
# ***** END LICENSE BLOCK ***** */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* File utilities.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class IDF_FileUtil
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Extension supported by the syntax highlighter.
|
||||||
|
*/
|
||||||
|
public static $supportedExtenstions = array(
|
||||||
|
'ascx', 'ashx', 'asmx', 'aspx', 'browser', 'bsh', 'c', 'cl', 'cc',
|
||||||
|
'config', 'cpp', 'cs', 'csh', 'csproj', 'css', 'cv', 'cyc', 'el', 'fs',
|
||||||
|
'h', 'hh', 'hpp', 'hs', 'html', 'html', 'java', 'js', 'lisp', 'master',
|
||||||
|
'pas', 'perl', 'php', 'pl', 'pm', 'py', 'rb', 'scm', 'sh', 'sitemap',
|
||||||
|
'skin', 'sln', 'svc', 'vala', 'vb', 'vbproj', 'vbs', 'wsdl', 'xhtml',
|
||||||
|
'xml', 'xsd', 'xsl', 'xslt');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test if an extension is supported by the syntax highlighter.
|
||||||
|
*
|
||||||
|
* @param string The extension to test
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public static function isSupportedExtension($extension)
|
||||||
|
{
|
||||||
|
return in_array($extension, self::$supportedExtenstions);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a HTML snippet with a line-by-line pre-rendered table
|
||||||
|
* for the given source content
|
||||||
|
*
|
||||||
|
* @param array file information as returned by getMimeType or getMimeTypeFromContent
|
||||||
|
* @param string the content of the file
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function highLight($fileinfo, $content)
|
||||||
|
{
|
||||||
|
$pretty = '';
|
||||||
|
if (self::isSupportedExtension($fileinfo[2])) {
|
||||||
|
$pretty = ' prettyprint';
|
||||||
|
}
|
||||||
|
$table = array();
|
||||||
|
$i = 1;
|
||||||
|
foreach (preg_split("/\015\012|\015|\012/", $content) as $line) {
|
||||||
|
$table[] = '<tr class="c-line"><td class="code-lc" id="L'.$i.'"><a href="#L'.$i.'">'.$i.'</a></td>'
|
||||||
|
.'<td class="code mono'.$pretty.'">'.IDF_Diff::padLine(Pluf_esc($line)).'</td></tr>';
|
||||||
|
$i++;
|
||||||
|
}
|
||||||
|
return Pluf_Template::markSafe(implode("\n", $table));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the mime type of a file.
|
||||||
|
*
|
||||||
|
* Use /etc/mime.types to find the type.
|
||||||
|
*
|
||||||
|
* @param string Filename/Filepath
|
||||||
|
* @param array Mime type found or 'application/octet-stream', basename, extension
|
||||||
|
*/
|
||||||
|
public static function getMimeType($file)
|
||||||
|
{
|
||||||
|
static $mimes = null;
|
||||||
|
if ($mimes == null) {
|
||||||
|
$mimes = array();
|
||||||
|
$src = Pluf::f('idf_mimetypes_db', '/etc/mime.types');
|
||||||
|
$filecontent = @file_get_contents($src);
|
||||||
|
if ($filecontent !== false) {
|
||||||
|
$mimes = preg_split("/\015\012|\015|\012/", $filecontent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$info = pathinfo($file);
|
||||||
|
if (isset($info['extension'])) {
|
||||||
|
foreach ($mimes as $mime) {
|
||||||
|
if ('#' != substr($mime, 0, 1)) {
|
||||||
|
$elts = preg_split('/ |\t/', $mime, -1, PREG_SPLIT_NO_EMPTY);
|
||||||
|
if (in_array($info['extension'], $elts)) {
|
||||||
|
return array($elts[0], $info['basename'], $info['extension']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// we consider that if no extension and base name is all
|
||||||
|
// uppercase, then we have a text file.
|
||||||
|
if ($info['basename'] == strtoupper($info['basename'])) {
|
||||||
|
return array('text/plain', $info['basename'], 'txt');
|
||||||
|
}
|
||||||
|
$info['extension'] = 'bin';
|
||||||
|
}
|
||||||
|
return array('application/octet-stream', $info['basename'], $info['extension']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the mime type of a file using the fileinfo class.
|
||||||
|
*
|
||||||
|
* @param string Filename/Filepath
|
||||||
|
* @param string File content
|
||||||
|
* @return array Mime type found or 'application/octet-stream', basename, extension
|
||||||
|
*/
|
||||||
|
public static function getMimeTypeFromContent($file, $filedata)
|
||||||
|
{
|
||||||
|
$info = pathinfo($file);
|
||||||
|
$res = array('application/octet-stream',
|
||||||
|
$info['basename'],
|
||||||
|
isset($info['extension']) ? $info['extension'] : 'bin');
|
||||||
|
if (function_exists('finfo_open')) {
|
||||||
|
$finfo = finfo_open(FILEINFO_MIME);
|
||||||
|
$mime = finfo_buffer($finfo, $filedata);
|
||||||
|
finfo_close($finfo);
|
||||||
|
if ($mime) {
|
||||||
|
$res[0] = $mime;
|
||||||
|
}
|
||||||
|
if (!isset($info['extension']) && $mime) {
|
||||||
|
$res[2] = (0 === strpos($mime, 'text/')) ? 'txt' : 'bin';
|
||||||
|
} elseif (!isset($info['extension'])) {
|
||||||
|
$res[2] = 'bin';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find if a given mime type is a text file.
|
||||||
|
* This uses the output of the self::getMimeType function.
|
||||||
|
*
|
||||||
|
* @param array (Mime type, file name, extension)
|
||||||
|
* @return bool Is text
|
||||||
|
*/
|
||||||
|
public static function isText($fileinfo)
|
||||||
|
{
|
||||||
|
if (0 === strpos($fileinfo[0], 'text/')) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
$ext = 'mdtext php-dist h gitignore diff patch';
|
||||||
|
$extra_ext = trim(Pluf::f('idf_extra_text_ext', ''));
|
||||||
|
if (!empty($extra_ext))
|
||||||
|
$ext .= ' ' . $extra_ext;
|
||||||
|
$ext = array_merge(self::$supportedExtenstions, explode(' ' , $ext));
|
||||||
|
return (in_array($fileinfo[2], $ext));
|
||||||
|
}
|
||||||
|
}
|
@ -39,9 +39,9 @@ class IDF_IssueFile extends Pluf_Model
|
|||||||
array(
|
array(
|
||||||
'type' => 'Pluf_DB_Field_Sequence',
|
'type' => 'Pluf_DB_Field_Sequence',
|
||||||
//It is automatically added.
|
//It is automatically added.
|
||||||
'blank' => true,
|
'blank' => true,
|
||||||
),
|
),
|
||||||
'comment' =>
|
'comment' =>
|
||||||
array(
|
array(
|
||||||
'type' => 'Pluf_DB_Field_Foreignkey',
|
'type' => 'Pluf_DB_Field_Foreignkey',
|
||||||
'model' => 'IDF_IssueComment',
|
'model' => 'IDF_IssueComment',
|
||||||
@ -49,7 +49,7 @@ class IDF_IssueFile extends Pluf_Model
|
|||||||
'verbose' => __('comment'),
|
'verbose' => __('comment'),
|
||||||
'relate_name' => 'attachment',
|
'relate_name' => 'attachment',
|
||||||
),
|
),
|
||||||
'submitter' =>
|
'submitter' =>
|
||||||
array(
|
array(
|
||||||
'type' => 'Pluf_DB_Field_Foreignkey',
|
'type' => 'Pluf_DB_Field_Foreignkey',
|
||||||
'model' => 'Pluf_User',
|
'model' => 'Pluf_User',
|
||||||
@ -63,7 +63,7 @@ class IDF_IssueFile extends Pluf_Model
|
|||||||
'size' => 100,
|
'size' => 100,
|
||||||
'verbose' => __('file name'),
|
'verbose' => __('file name'),
|
||||||
),
|
),
|
||||||
'attachment' =>
|
'attachment' =>
|
||||||
array(
|
array(
|
||||||
'type' => 'Pluf_DB_Field_File',
|
'type' => 'Pluf_DB_Field_File',
|
||||||
'blank' => false,
|
'blank' => false,
|
||||||
@ -76,7 +76,7 @@ class IDF_IssueFile extends Pluf_Model
|
|||||||
'verbose' => __('file size'),
|
'verbose' => __('file size'),
|
||||||
'help_text' => 'Size in bytes.',
|
'help_text' => 'Size in bytes.',
|
||||||
),
|
),
|
||||||
'type' =>
|
'type' =>
|
||||||
array(
|
array(
|
||||||
'type' => 'Pluf_DB_Field_Varchar',
|
'type' => 'Pluf_DB_Field_Varchar',
|
||||||
'blank' => false,
|
'blank' => false,
|
||||||
@ -111,7 +111,7 @@ class IDF_IssueFile extends Pluf_Model
|
|||||||
$file = Pluf::f('upload_issue_path').'/'.$this->attachment;
|
$file = Pluf::f('upload_issue_path').'/'.$this->attachment;
|
||||||
$this->filesize = filesize($file);
|
$this->filesize = filesize($file);
|
||||||
// remove .dummy
|
// remove .dummy
|
||||||
$this->filename = substr(basename($file), 0, -6);
|
$this->filename = substr(basename($file), 0, -6);
|
||||||
$img_extensions = array('jpeg', 'jpg', 'png', 'gif');
|
$img_extensions = array('jpeg', 'jpg', 'png', 'gif');
|
||||||
$info = pathinfo($this->filename);
|
$info = pathinfo($this->filename);
|
||||||
if (!isset($info['extension'])) $info['extension'] = '';
|
if (!isset($info['extension'])) $info['extension'] = '';
|
||||||
@ -128,4 +128,10 @@ class IDF_IssueFile extends Pluf_Model
|
|||||||
{
|
{
|
||||||
@unlink(Pluf::f('upload_issue_path').'/'.$this->attachment);
|
@unlink(Pluf::f('upload_issue_path').'/'.$this->attachment);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isText()
|
||||||
|
{
|
||||||
|
$info = IDF_FileUtil::getMimeType($this->filename);
|
||||||
|
return IDF_FileUtil::isText($info);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -93,7 +93,7 @@ class IDF_Template_Markdown extends Pluf_Template_Tag
|
|||||||
$info = pathinfo($m[1]);
|
$info = pathinfo($m[1]);
|
||||||
$fileinfo = array($res->headers['Content-Type'], $m[1],
|
$fileinfo = array($res->headers['Content-Type'], $m[1],
|
||||||
isset($info['extension']) ? $info['extension'] : 'bin');
|
isset($info['extension']) ? $info['extension'] : 'bin');
|
||||||
if (!IDF_Views_Source::isText($fileinfo)) {
|
if (!IDF_FileUtil::isText($fileinfo)) {
|
||||||
return $m[0];
|
return $m[0];
|
||||||
}
|
}
|
||||||
return $res->content;
|
return $res->content;
|
||||||
|
47
src/IDF/Tests/TestFileUtil.php
Normal file
47
src/IDF/Tests/TestFileUtil.php
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||||
|
/*
|
||||||
|
# ***** BEGIN LICENSE BLOCK *****
|
||||||
|
# This file is part of InDefero, an open source project management application.
|
||||||
|
# Copyright (C) 2008 Céondo Ltd and contributors.
|
||||||
|
#
|
||||||
|
# InDefero is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# InDefero is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
#
|
||||||
|
# ***** END LICENSE BLOCK ***** */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests some of the FileUtils
|
||||||
|
*/
|
||||||
|
class IDF_Tests_TestFileUtil extends UnitTestCase
|
||||||
|
{
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
parent::__construct('Test the file utils.');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetMimeType()
|
||||||
|
{
|
||||||
|
$files = array(
|
||||||
|
'whatever.php' => 'application/x-httpd-php',
|
||||||
|
'whatever.pht' => 'application/x-httpd-php',
|
||||||
|
'README' => 'text/plain',
|
||||||
|
);
|
||||||
|
foreach ($files as $file => $mime) {
|
||||||
|
$m = IDF_Views_Source::getMimeType($file);
|
||||||
|
$this->assertEqual($mime, $m[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -32,19 +32,6 @@ class IDF_Tests_TestSource extends UnitTestCase
|
|||||||
parent::__construct('Test the source class.');
|
parent::__construct('Test the source class.');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testGetMimeType()
|
|
||||||
{
|
|
||||||
$files = array(
|
|
||||||
'whatever.php' => 'application/x-httpd-php',
|
|
||||||
'whatever.pht' => 'application/x-httpd-php',
|
|
||||||
'README' => 'text/plain',
|
|
||||||
);
|
|
||||||
foreach ($files as $file => $mime) {
|
|
||||||
$m = IDF_Views_Source::getMimeType($file);
|
|
||||||
$this->assertEqual($mime, $m[0]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testRegexCommit()
|
public function testRegexCommit()
|
||||||
{
|
{
|
||||||
$regex = '#^/p/([\-\w]+)/source/tree/([^\/]+)/(.*)$#';
|
$regex = '#^/p/([\-\w]+)/source/tree/([^\/]+)/(.*)$#';
|
||||||
@ -61,4 +48,4 @@ class IDF_Tests_TestSource extends UnitTestCase
|
|||||||
$this->assertEqual($res[2], $m[3]);
|
$this->assertEqual($res[2], $m[3]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -79,7 +79,7 @@ class IDF_Views_Issue
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* View the issues of a given user.
|
* View the issues of a given user.
|
||||||
*
|
*
|
||||||
* Only open issues are shown.
|
* Only open issues are shown.
|
||||||
*/
|
*/
|
||||||
@ -201,7 +201,7 @@ class IDF_Views_Issue
|
|||||||
{
|
{
|
||||||
$prj = $request->project;
|
$prj = $request->project;
|
||||||
if (!isset($request->REQUEST['q']) or trim($request->REQUEST['q']) == '') {
|
if (!isset($request->REQUEST['q']) or trim($request->REQUEST['q']) == '') {
|
||||||
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Issue::index',
|
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Issue::index',
|
||||||
array($prj->shortname));
|
array($prj->shortname));
|
||||||
return new Pluf_HTTP_Response_Redirect($url);
|
return new Pluf_HTTP_Response_Redirect($url);
|
||||||
}
|
}
|
||||||
@ -263,7 +263,7 @@ class IDF_Views_Issue
|
|||||||
'issue' => $issue,
|
'issue' => $issue,
|
||||||
);
|
);
|
||||||
if ($request->method == 'POST') {
|
if ($request->method == 'POST') {
|
||||||
$form = new IDF_Form_IssueUpdate(array_merge($request->POST,
|
$form = new IDF_Form_IssueUpdate(array_merge($request->POST,
|
||||||
$request->FILES),
|
$request->FILES),
|
||||||
$params);
|
$params);
|
||||||
if (!isset($request->POST['preview']) && $form->isValid()) {
|
if (!isset($request->POST['preview']) && $form->isValid()) {
|
||||||
@ -306,7 +306,7 @@ class IDF_Views_Issue
|
|||||||
$prj = $request->project;
|
$prj = $request->project;
|
||||||
$attach = Pluf_Shortcuts_GetObjectOr404('IDF_IssueFile', $match[2]);
|
$attach = Pluf_Shortcuts_GetObjectOr404('IDF_IssueFile', $match[2]);
|
||||||
$prj->inOr404($attach->get_comment()->get_issue());
|
$prj->inOr404($attach->get_comment()->get_issue());
|
||||||
$info = IDF_Views_Source::getMimeType($attach->filename);
|
$info = IDF_FileUtil::getMimeType($attach->filename);
|
||||||
$mime = 'application/octet-stream';
|
$mime = 'application/octet-stream';
|
||||||
if (strpos($info[0], 'image/') === 0) {
|
if (strpos($info[0], 'image/') === 0) {
|
||||||
$mime = $info[0];
|
$mime = $info[0];
|
||||||
@ -330,14 +330,14 @@ class IDF_Views_Issue
|
|||||||
$prj->inOr404($attach->get_comment()->get_issue());
|
$prj->inOr404($attach->get_comment()->get_issue());
|
||||||
// If one cannot see the attachement, redirect to the
|
// If one cannot see the attachement, redirect to the
|
||||||
// getAttachment view.
|
// getAttachment view.
|
||||||
$info = IDF_Views_Source::getMimeType($attach->filename);
|
$info = IDF_FileUtil::getMimeType($attach->filename);
|
||||||
if (!IDF_Views_Source::isText($info)) {
|
if (!IDF_FileUtil::isText($info)) {
|
||||||
return $this->getAttachment($request, $match);
|
return $this->getAttachment($request, $match);
|
||||||
}
|
}
|
||||||
// Now we want to look at the file but with links back to the
|
// Now we want to look at the file but with links back to the
|
||||||
// issue.
|
// issue.
|
||||||
$file = IDF_Views_Source::highLight($info,
|
$file = IDF_FileUtil::highLight($info,
|
||||||
file_get_contents(Pluf::f('upload_issue_path').'/'.$attach->attachment));
|
file_get_contents(Pluf::f('upload_issue_path').'/'.$attach->attachment));
|
||||||
$title = sprintf(__('View %s'), $attach->filename);
|
$title = sprintf(__('View %s'), $attach->filename);
|
||||||
return Pluf_Shortcuts_RenderToResponse('idf/issues/attachment.html',
|
return Pluf_Shortcuts_RenderToResponse('idf/issues/attachment.html',
|
||||||
array(
|
array(
|
||||||
@ -406,7 +406,7 @@ class IDF_Views_Issue
|
|||||||
{
|
{
|
||||||
$prj = $request->project;
|
$prj = $request->project;
|
||||||
$tag = Pluf_Shortcuts_GetObjectOr404('IDF_Tag', $match[2]);
|
$tag = Pluf_Shortcuts_GetObjectOr404('IDF_Tag', $match[2]);
|
||||||
$status = $match[3];
|
$status = $match[3];
|
||||||
if ($tag->project != $prj->id or !in_array($status, array('open', 'closed'))) {
|
if ($tag->project != $prj->id or !in_array($status, array('open', 'closed'))) {
|
||||||
throw new Pluf_HTTP_Error404();
|
throw new Pluf_HTTP_Error404();
|
||||||
}
|
}
|
||||||
@ -414,7 +414,7 @@ class IDF_Views_Issue
|
|||||||
$title = sprintf(__('%1$s Issues with Label %2$s'), (string) $prj,
|
$title = sprintf(__('%1$s Issues with Label %2$s'), (string) $prj,
|
||||||
(string) $tag);
|
(string) $tag);
|
||||||
} else {
|
} else {
|
||||||
$title = sprintf(__('%1$s Closed Issues with Label %2$s'),
|
$title = sprintf(__('%1$s Closed Issues with Label %2$s'),
|
||||||
(string) $prj, (string) $tag);
|
(string) $prj, (string) $tag);
|
||||||
}
|
}
|
||||||
// Get stats about the open/closed issues having this tag.
|
// Get stats about the open/closed issues having this tag.
|
||||||
@ -547,11 +547,11 @@ class IDF_Views_Issue
|
|||||||
*/
|
*/
|
||||||
function IDF_Views_Issue_SummaryAndLabels($field, $issue, $extra='')
|
function IDF_Views_Issue_SummaryAndLabels($field, $issue, $extra='')
|
||||||
{
|
{
|
||||||
$edit = Pluf_HTTP_URL_urlForView('IDF_Views_Issue::view',
|
$edit = Pluf_HTTP_URL_urlForView('IDF_Views_Issue::view',
|
||||||
array($issue->shortname, $issue->id));
|
array($issue->shortname, $issue->id));
|
||||||
$tags = array();
|
$tags = array();
|
||||||
foreach ($issue->get_tags_list() as $tag) {
|
foreach ($issue->get_tags_list() as $tag) {
|
||||||
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Issue::listLabel',
|
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Issue::listLabel',
|
||||||
array($issue->shortname, $tag->id, 'open'));
|
array($issue->shortname, $tag->id, 'open'));
|
||||||
$tags[] = sprintf('<a class="label" href="%s">%s</a>', $url, Pluf_esc((string) $tag));
|
$tags[] = sprintf('<a class="label" href="%s">%s</a>', $url, Pluf_esc((string) $tag));
|
||||||
}
|
}
|
||||||
@ -574,4 +574,4 @@ function IDF_Views_Issue_SummaryAndLabels($field, $issue, $extra='')
|
|||||||
function IDF_Views_Issue_ShowStatus($field, $issue, $extra='')
|
function IDF_Views_Issue_ShowStatus($field, $issue, $extra='')
|
||||||
{
|
{
|
||||||
return Pluf_esc($issue->get_status()->name);
|
return Pluf_esc($issue->get_status()->name);
|
||||||
}
|
}
|
||||||
|
@ -31,17 +31,6 @@ Pluf::loadFunction('Pluf_Shortcuts_GetFormForModel');
|
|||||||
*/
|
*/
|
||||||
class IDF_Views_Source
|
class IDF_Views_Source
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* Extension supported by the syntax highlighter.
|
|
||||||
*/
|
|
||||||
public static $supportedExtenstions = array(
|
|
||||||
'ascx', 'ashx', 'asmx', 'aspx', 'browser', 'bsh', 'c', 'cl', 'cc',
|
|
||||||
'config', 'cpp', 'cs', 'csh', 'csproj', 'css', 'cv', 'cyc', 'el', 'fs',
|
|
||||||
'h', 'hh', 'hpp', 'hs', 'html', 'html', 'java', 'js', 'lisp', 'master',
|
|
||||||
'pas', 'perl', 'php', 'pl', 'pm', 'py', 'rb', 'scm', 'sh', 'sitemap',
|
|
||||||
'skin', 'sln', 'svc', 'vala', 'vb', 'vbproj', 'vbs', 'wsdl', 'xhtml',
|
|
||||||
'xml', 'xsd', 'xsl', 'xslt');
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display help on how to checkout etc.
|
* Display help on how to checkout etc.
|
||||||
*/
|
*/
|
||||||
@ -211,7 +200,7 @@ class IDF_Views_Source
|
|||||||
if ($request_file_info->type != 'tree') {
|
if ($request_file_info->type != 'tree') {
|
||||||
$info = self::getRequestedFileMimeType($request_file_info,
|
$info = self::getRequestedFileMimeType($request_file_info,
|
||||||
$commit, $scm);
|
$commit, $scm);
|
||||||
if (!self::isText($info)) {
|
if (!IDF_FileUtil::isText($info)) {
|
||||||
$rep = new Pluf_HTTP_Response($scm->getFile($request_file_info),
|
$rep = new Pluf_HTTP_Response($scm->getFile($request_file_info),
|
||||||
$info[0]);
|
$info[0]);
|
||||||
$rep->headers['Content-Disposition'] = 'attachment; filename="'.$info[1].'"';
|
$rep->headers['Content-Disposition'] = 'attachment; filename="'.$info[1].'"';
|
||||||
@ -373,7 +362,7 @@ class IDF_Views_Source
|
|||||||
$previous = substr($request_file, 0, -strlen($l.' '));
|
$previous = substr($request_file, 0, -strlen($l.' '));
|
||||||
$scmConf = $request->conf->getVal('scm', 'git');
|
$scmConf = $request->conf->getVal('scm', 'git');
|
||||||
$props = $scm->getProperties($commit, $request_file);
|
$props = $scm->getProperties($commit, $request_file);
|
||||||
$content = self::highLight($extra['mime'], $scm->getFile($request_file_info));
|
$content = IDF_FileUtil::highLight($extra['mime'], $scm->getFile($request_file_info));
|
||||||
return Pluf_Shortcuts_RenderToResponse('idf/source/'.$scmConf.'/file.html',
|
return Pluf_Shortcuts_RenderToResponse('idf/source/'.$scmConf.'/file.html',
|
||||||
array(
|
array(
|
||||||
'page_title' => $page_title,
|
'page_title' => $page_title,
|
||||||
@ -451,121 +440,12 @@ class IDF_Views_Source
|
|||||||
*/
|
*/
|
||||||
public static function getRequestedFileMimeType($file_info, $commit, $scm)
|
public static function getRequestedFileMimeType($file_info, $commit, $scm)
|
||||||
{
|
{
|
||||||
$mime = self::getMimeType($file_info->file);
|
$mime = IDF_FileUtil::getMimeType($file_info->file);
|
||||||
if ('application/octet-stream' != $mime[0]) {
|
if ('application/octet-stream' != $mime[0]) {
|
||||||
return $mime;
|
return $mime;
|
||||||
}
|
}
|
||||||
return self::getMimeTypeFromContent($file_info->file,
|
return IDF_FileUtil::getMimeTypeFromContent($file_info->file,
|
||||||
$scm->getFile($file_info));
|
$scm->getFile($file_info));
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Find the mime type of a file using the fileinfo class.
|
|
||||||
*
|
|
||||||
* @param string Filename/Filepath
|
|
||||||
* @param string File content
|
|
||||||
* @return array Mime type found or 'application/octet-stream', basename, extension
|
|
||||||
*/
|
|
||||||
public static function getMimeTypeFromContent($file, $filedata)
|
|
||||||
{
|
|
||||||
$info = pathinfo($file);
|
|
||||||
$res = array('application/octet-stream',
|
|
||||||
$info['basename'],
|
|
||||||
isset($info['extension']) ? $info['extension'] : 'bin');
|
|
||||||
if (function_exists('finfo_open')) {
|
|
||||||
$finfo = finfo_open(FILEINFO_MIME);
|
|
||||||
$mime = finfo_buffer($finfo, $filedata);
|
|
||||||
finfo_close($finfo);
|
|
||||||
if ($mime) {
|
|
||||||
$res[0] = $mime;
|
|
||||||
}
|
|
||||||
if (!isset($info['extension']) && $mime) {
|
|
||||||
$res[2] = (0 === strpos($mime, 'text/')) ? 'txt' : 'bin';
|
|
||||||
} elseif (!isset($info['extension'])) {
|
|
||||||
$res[2] = 'bin';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $res;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Find the mime type of a file.
|
|
||||||
*
|
|
||||||
* Use /etc/mime.types to find the type.
|
|
||||||
*
|
|
||||||
* @param string Filename/Filepath
|
|
||||||
* @param array Mime type found or 'application/octet-stream', basename, extension
|
|
||||||
*/
|
|
||||||
public static function getMimeType($file)
|
|
||||||
{
|
|
||||||
$src= Pluf::f('idf_mimetypes_db', '/etc/mime.types');
|
|
||||||
$mimes = preg_split("/\015\012|\015|\012/", file_get_contents($src));
|
|
||||||
$info = pathinfo($file);
|
|
||||||
if (isset($info['extension'])) {
|
|
||||||
foreach ($mimes as $mime) {
|
|
||||||
if ('#' != substr($mime, 0, 1)) {
|
|
||||||
$elts = preg_split('/ |\t/', $mime, -1, PREG_SPLIT_NO_EMPTY);
|
|
||||||
if (in_array($info['extension'], $elts)) {
|
|
||||||
return array($elts[0], $info['basename'], $info['extension']);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// we consider that if no extension and base name is all
|
|
||||||
// uppercase, then we have a text file.
|
|
||||||
if ($info['basename'] == strtoupper($info['basename'])) {
|
|
||||||
return array('text/plain', $info['basename'], 'txt');
|
|
||||||
}
|
|
||||||
$info['extension'] = 'bin';
|
|
||||||
}
|
|
||||||
return array('application/octet-stream', $info['basename'], $info['extension']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Find if a given mime type is a text file.
|
|
||||||
* This uses the output of the self::getMimeType function.
|
|
||||||
*
|
|
||||||
* @param array (Mime type, file name, extension)
|
|
||||||
* @return bool Is text
|
|
||||||
*/
|
|
||||||
public static function isText($fileinfo)
|
|
||||||
{
|
|
||||||
if (0 === strpos($fileinfo[0], 'text/')) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
$ext = 'mdtext php-dist h gitignore diff patch';
|
|
||||||
$extra_ext = trim(Pluf::f('idf_extra_text_ext', ''));
|
|
||||||
if (!empty($extra_ext))
|
|
||||||
$ext .= ' ' . $extra_ext;
|
|
||||||
$ext = array_merge(self::$supportedExtenstions, explode(' ' , $ext));
|
|
||||||
return (in_array($fileinfo[2], $ext));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function highLight($fileinfo, $content)
|
|
||||||
{
|
|
||||||
$pretty = '';
|
|
||||||
if (self::isSupportedExtension($fileinfo[2])) {
|
|
||||||
$pretty = ' prettyprint';
|
|
||||||
}
|
|
||||||
$table = array();
|
|
||||||
$i = 1;
|
|
||||||
foreach (preg_split("/\015\012|\015|\012/", $content) as $line) {
|
|
||||||
$table[] = '<tr class="c-line"><td class="code-lc" id="L'.$i.'"><a href="#L'.$i.'">'.$i.'</a></td>'
|
|
||||||
.'<td class="code mono'.$pretty.'">'.IDF_Diff::padLine(Pluf_esc($line)).'</td></tr>';
|
|
||||||
$i++;
|
|
||||||
}
|
|
||||||
return Pluf_Template::markSafe(implode("\n", $table));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test if an extension is supported by the syntax highlighter.
|
|
||||||
*
|
|
||||||
* @param string The extension to test
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public static function isSupportedExtension($extension)
|
|
||||||
{
|
|
||||||
return in_array($extension, self::$supportedExtenstions);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
{extends "idf/issues/base.html"}
|
{extends "idf/issues/base.html"}
|
||||||
{block titleicon}{if $form}<form class="star" method="post" action="{url 'IDF_Views_Issue::star', array($project.shortname, $issue.id)}"><input type="image" src="{if $starred}{media '/idf/img/star.png'}{else}{media '/idf/img/star-grey.png'}{/if}" name="submit" /></form> {/if}{/block}
|
{block titleicon}{if $form}<form class="star" method="post" action="{url 'IDF_Views_Issue::star', array($project.shortname, $issue.id)}"><input type="image" src="{if $starred}{media '/idf/img/star.png'}{else}{media '/idf/img/star-grey.png'}{/if}" name="submit" /></form> {/if}{/block}
|
||||||
{block body}
|
{block body}
|
||||||
{assign $i = 0}
|
{assign $i = 0}
|
||||||
{assign $nc = $comments.count()}
|
{assign $nc = $comments.count()}
|
||||||
{foreach $comments as $c}{ashowuser 'submitter', $c.get_submitter(), $request}{assign $who = $c.get_submitter()}
|
{foreach $comments as $c}{ashowuser 'submitter', $c.get_submitter(), $request}{assign $who = $c.get_submitter()}
|
||||||
<div class="issue-comment{if $i == 0} issue-comment-first{/if}{if $i == ($nc-1)} issue-comment-last{/if}" id="ic{$c.id}"><img style="float:right; position: relative;" src="http://www.gravatar.com/avatar/{$who.email|md5}.jpg?s=60&d={media}/idf/img/spacer.gif" alt=" " />
|
<div class="issue-comment{if $i == 0} issue-comment-first{/if}{if $i == ($nc-1)} issue-comment-last{/if}" id="ic{$c.id}"><img style="float:right; position: relative;" src="http://www.gravatar.com/avatar/{$who.email|md5}.jpg?s=60&d={media}/idf/img/spacer.gif" alt=" " />
|
||||||
{if $i == 0}
|
{if $i == 0}
|
||||||
@ -20,14 +20,13 @@
|
|||||||
{if $attachments.count() > 0}
|
{if $attachments.count() > 0}
|
||||||
<hr align="left" class="attach" />
|
<hr align="left" class="attach" />
|
||||||
<ul>
|
<ul>
|
||||||
{foreach $attachments as $a}<li><a href="{url 'IDF_Views_Issue::viewAttachment', array($project.shortname, $a.id, $a.filename)}">{$a.filename}</a> - {$a.filesize|size}</li>{/foreach}
|
{foreach $attachments as $a}<li><a href="{url 'IDF_Views_Issue::getAttachment', array($project.shortname, $a.id, $a.filename)}" title="{trans 'download'}">{$a.filename}</a> - {$a.filesize|size}{if $a.isText()} - <a href="{url 'IDF_Views_Issue::viewAttachment', array($project.shortname, $a.id, $a.filename)}">{trans 'view'}</a>{/if}</li>{/foreach}</ul>{/if}
|
||||||
</ul>{/if}
|
|
||||||
{if $i> 0 and $c.changedIssue()}
|
{if $i> 0 and $c.changedIssue()}
|
||||||
<div class="issue-changes">
|
<div class="issue-changes">
|
||||||
{foreach $c.changes as $w => $v}
|
{foreach $c.changes as $w => $v}
|
||||||
<strong>{if $w == 'su'}{trans 'Summary:'}{/if}{if $w == 'st'}{trans 'Status:'}{/if}{if $w == 'ow'}{trans 'Owner:'}{/if}{if $w == 'lb'}{trans 'Labels:'}{/if}</strong> {if $w == 'lb'}{assign $l = implode(', ', $v)}{$l}{else}{$v}{/if}<br />
|
<strong>{if $w == 'su'}{trans 'Summary:'}{/if}{if $w == 'st'}{trans 'Status:'}{/if}{if $w == 'ow'}{trans 'Owner:'}{/if}{if $w == 'lb'}{trans 'Labels:'}{/if}</strong> {if $w == 'lb'}{assign $l = implode(', ', $v)}{$l}{else}{$v}{/if}<br />
|
||||||
{/foreach}
|
{/foreach}
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>{assign $i = $i + 1}{if $i == $nc and false == $form}
|
</div>{assign $i = $i + 1}{if $i == $nc and false == $form}
|
||||||
<div class="issue-comment-signin">
|
<div class="issue-comment-signin">
|
||||||
@ -119,7 +118,7 @@
|
|||||||
<td> </td>
|
<td> </td>
|
||||||
<td>
|
<td>
|
||||||
<input type="submit" value="{trans 'Submit Changes'}" name="submit" />
|
<input type="submit" value="{trans 'Submit Changes'}" name="submit" />
|
||||||
<input type="submit" value="{trans 'Preview'}" name="preview" /> |
|
<input type="submit" value="{trans 'Preview'}" name="preview" /> |
|
||||||
<a href="{url 'IDF_Views_Issue::view', array($project.shortname, $issue.id)}">{trans 'Cancel'}</a>
|
<a href="{url 'IDF_Views_Issue::view', array($project.shortname, $issue.id)}">{trans 'Cancel'}</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
Loading…
Reference in New Issue
Block a user