Merge branch 'develop'

master
Loïc d'Anterroches 2010-12-23 11:18:07 +01:00
commit 81acb276d8
48 changed files with 4787 additions and 374 deletions

View File

@ -17,8 +17,11 @@
# git$ ln -s /home/www/indefero/scripts/git-post-update post-update
#
SCRIPTDIR=$(dirname $(readlink -f $0))
FULL_GIT_DIR=$(readlink -f $GIT_DIR)
dir=$(dirname "$0")
res=$(cd "$dir" && /bin/pwd || "$dir")
SCRIPTDIR="$res/$(readlink $0)"
FULL_GIT_DIR=$(cd "$GIT_DIR" && /bin/pwd || "$GIT_DIR")
PHP_POST_UPDATE=$SCRIPTDIR/gitpostupdate.php
echo php $PHP_POST_UPDATE $FULL_GIT_DIR | at now > /dev/null 2>&1

View File

@ -18,7 +18,9 @@
# www$ ln -s /home/www/indefero/scripts/svn-post-commit post-commit
#
SCRIPTDIR=$(dirname $(readlink -f $0))
dir=$(dirname "$0")
res=$(cd "$dir" && /bin/pwd || "$dir")
SCRIPTDIR="$res/$(readlink $0)"
PHP_POST_COMMIT=$SCRIPTDIR/svnpostcommit.php
echo php $PHP_POST_COMMIT "$1" "$2" | at now > /dev/null 2>&1

View File

@ -18,7 +18,9 @@
# www$ ln -s /home/www/indefero/scripts/svn-post-revprop-change post-revprop-change
#
SCRIPTDIR=$(dirname $(readlink -f $0))
dir=$(dirname "$0")
res=$(cd "$dir" && /bin/pwd || "$dir")
SCRIPTDIR="$res/$(readlink $0)"
PHP_POST_REVPROP=$SCRIPTDIR/svnpostrevpropchange.php
echo php $PHP_POST_REVPROP "$1" "$2" "$3" "$4" "$5" | at now > /dev/null 2>&1

View File

@ -44,9 +44,9 @@ class IDF_Commit extends Pluf_Model
'id' =>
array(
'type' => 'Pluf_DB_Field_Sequence',
'blank' => true,
'blank' => true,
),
'project' =>
'project' =>
array(
'type' => 'Pluf_DB_Field_Foreignkey',
'model' => 'IDF_Project',
@ -54,7 +54,7 @@ class IDF_Commit extends Pluf_Model
'verbose' => __('project'),
'relate_name' => 'commits',
),
'author' =>
'author' =>
array(
'type' => 'Pluf_DB_Field_Foreignkey',
'model' => 'Pluf_User',
@ -118,7 +118,7 @@ class IDF_Commit extends Pluf_Model
{
IDF_Search::index($this);
if ($create) {
IDF_Timeline::insert($this, $this->get_project(),
IDF_Timeline::insert($this, $this->get_project(),
$this->get_author(), $this->creation_dtime);
}
}
@ -200,13 +200,13 @@ class IDF_Commit extends Pluf_Model
* Returns the timeline fragment for the commit.
*
*
* @param Pluf_HTTP_Request
* @param Pluf_HTTP_Request
* @return Pluf_Template_SafeString
*/
public function timelineFragment($request)
{
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Source::commit',
array($request->project->shortname,
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Source::commit',
array($request->project->shortname,
$this->scm_id));
$out = '<tr class="log"><td><a href="'.$url.'">'.
Pluf_esc(Pluf_Template_dateAgo($this->creation_dtime, 'without')).
@ -222,24 +222,24 @@ class IDF_Commit extends Pluf_Model
</tr>
<tr class="extra">
<td colspan="2">
<div class="helptext right">'.sprintf(__('Commit&nbsp;%s, by %s'), '<a href="'.$url.'" class="mono">'.$this->scm_id.'</a>', $user).'</div></td></tr>';
<div class="helptext right">'.sprintf(__('Commit&nbsp;%s, by %s'), '<a href="'.$url.'" class="mono">'.$this->scm_id.'</a>', $user).'</div></td></tr>';
return Pluf_Template::markSafe($out);
}
/**
* Returns the feed fragment for the commit.
*
* @param Pluf_HTTP_Request
* @param Pluf_HTTP_Request
* @return Pluf_Template_SafeString
*/
public function feedFragment($request)
{
$url = Pluf::f('url_base')
.Pluf_HTTP_URL_urlForView('IDF_Views_Source::commit',
array($request->project->shortname,
.Pluf_HTTP_URL_urlForView('IDF_Views_Source::commit',
array($request->project->shortname,
$this->scm_id));
$date = Pluf_Date::gmDateToGmString($this->creation_dtime);
$author = ($this->get_author()) ?
$author = ($this->get_author()) ?
$this->get_author() : $this->origauthor;
$cproject = $this->get_project();
$context = new Pluf_Template_Context_Request(
@ -298,7 +298,7 @@ class IDF_Commit extends Pluf_Model
$current_locale = Pluf_Translation::getLocale();
$langs = Pluf::f('languages', array('en'));
Pluf_Translation::loadSetLocale($langs[0]);
Pluf_Translation::loadSetLocale($langs[0]);
$context = new Pluf_Template_Context(
array(
@ -309,13 +309,16 @@ class IDF_Commit extends Pluf_Model
);
$tmpl = new Pluf_Template('idf/source/commit-created-email.txt');
$text_email = $tmpl->render($context);
$email = new Pluf_Mail(Pluf::f('from_email'),
$conf->getVal('source_notification_email'),
sprintf(__('New Commit %s - %s (%s)'),
$this->scm_id, $this->summary,
$this->get_project()->shortname));
$email->addTextMessage($text_email);
$email->sendMail();
$addresses = explode(',', $conf->getVal('source_notification_email'));
foreach ($addresses as $address) {
$email = new Pluf_Mail(Pluf::f('from_email'),
$address,
sprintf(__('New Commit %s - %s (%s)'),
$this->scm_id, $this->summary,
$this->get_project()->shortname));
$email->addTextMessage($text_email);
$email->sendMail();
}
Pluf_Translation::loadSetLocale($current_locale);
}
}

View File

@ -169,8 +169,8 @@ class IDF_Diff
$out = '';
foreach ($this->files as $filename=>$file) {
$pretty = '';
$fileinfo = IDF_Views_Source::getMimeType($filename);
if (IDF_Views_Source::isSupportedExtension($fileinfo[2])) {
$fileinfo = IDF_FileUtil::getMimeType($filename);
if (IDF_FileUtil::isSupportedExtension($fileinfo[2])) {
$pretty = ' prettyprint';
}
$out .= "\n".'<table class="diff" summary="">'."\n";
@ -350,9 +350,9 @@ class IDF_Diff
public function renderCompared($chunks, $filename)
{
$fileinfo = IDF_Views_Source::getMimeType($filename);
$fileinfo = IDF_FileUtil::getMimeType($filename);
$pretty = '';
if (IDF_Views_Source::isSupportedExtension($fileinfo[2])) {
if (IDF_FileUtil::isSupportedExtension($fileinfo[2])) {
$pretty = ' prettyprint';
}
$out = '';

View 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));
}
}

View File

@ -24,13 +24,15 @@
/**
* Update user's details.
*/
class IDF_Form_Admin_UserUpdate extends Pluf_Form
class IDF_Form_Admin_UserUpdate extends Pluf_Form
{
public $user = null;
public function initFields($extra=array())
{
$this->user = $extra['user'];
$user_data = IDF_UserData::factory($this->user);
$this->fields['first_name'] = new Pluf_Form_Field_Varchar(
array('required' => false,
'label' => __('First name'),
@ -66,7 +68,7 @@ class IDF_Form_Admin_UserUpdate extends Pluf_Form
'initial' => $this->user->language,
'widget' => 'Pluf_Form_Widget_SelectInput',
'widget_attrs' => array(
'choices' =>
'choices' =>
Pluf_L10n::getInstalledLanguages()
),
));
@ -93,6 +95,66 @@ class IDF_Form_Admin_UserUpdate extends Pluf_Form
),
));
$this->fields['description'] = new Pluf_Form_Field_Varchar(
array('required' => false,
'label' => __('Description'),
'initial' => $user_data->description,
'widget_attrs' => array('rows' => 3,
'cols' => 40),
'widget' => 'Pluf_Form_Widget_TextareaInput',
));
$this->fields['twitter'] = new Pluf_Form_Field_Varchar(
array('required' => false,
'label' => __('Twitter username'),
'initial' => $user_data->twitter,
'widget_attrs' => array(
'maxlength' => 50,
'size' => 15,
),
));
$this->fields['public_email'] = new Pluf_Form_Field_Email(
array('required' => false,
'label' => __('Public email address'),
'initial' => $user_data->public_email,
'widget_attrs' => array(
'maxlength' => 50,
'size' => 15,
),
));
$this->fields['website'] = new Pluf_Form_Field_Url(
array('required' => false,
'label' => __('Website URL'),
'initial' => $user_data->website,
'widget_attrs' => array(
'maxlength' => 50,
'size' => 15,
),
));
$this->fields['custom_avatar'] = new Pluf_Form_Field_File(
array('required' => false,
'label' => __('Upload custom avatar'),
'initial' => '',
'max_size' => Pluf::f('max_upload_size', 2097152),
'move_function_params' => array('upload_path' => Pluf::f('upload_path').'/avatars',
'upload_path_create' => true,
'upload_overwrite' => true,
'file_name' => 'user_'.$this->user->id.'_%s'),
'help_text' => __('An image file with a width and height not larger than 60 pixels (bigger images are scaled down).'),
));
$this->fields['remove_custom_avatar'] = new Pluf_Form_Field_Boolean(
array('required' => false,
'label' => __('Remove custom avatar'),
'initial' => false,
'widget' => 'Pluf_Form_Widget_CheckboxInput',
'widget_attrs' => array(),
'help_text' => __('Tick this to delete the custom avatar.'),
));
if ($extra['request']->user->administrator) {
$this->fields['staff'] = new Pluf_Form_Field_Boolean(
array('required' => false,
@ -136,8 +198,37 @@ class IDF_Form_Admin_UserUpdate extends Pluf_Form
$update_pass = true;
}
$this->user->setFromFormData($this->cleaned_data);
if ($commit) {
$this->user->update();
// FIXME: go the extra mile and check the input lengths for
// all fields here!
// FIXME: this is all doubled in UserAccount!
$user_data = IDF_UserData::factory($this->user);
// Add or remove avatar - we need to do this here because every
// single setter directly leads to a save in the database
if ($user_data->avatar != '' &&
($this->cleaned_data['remove_custom_avatar'] == 1 ||
$this->cleaned_data['custom_avatar'] != '')) {
$avatar_path = Pluf::f('upload_path').'/avatars/'.basename($user_data->avatar);
if (basename($avatar_path) != '' && is_file($avatar_path)) {
unlink($avatar_path);
}
$user_data->avatar = '';
}
if ($this->cleaned_data['custom_avatar'] != '') {
$user_data->avatar = $this->cleaned_data['custom_avatar'];
}
$user_data->description = $this->cleaned_data['description'];
$user_data->twitter = $this->cleaned_data['twitter'];
$user_data->public_email = $this->cleaned_data['public_email'];
$user_data->website = $this->cleaned_data['website'];
if ($update_pass) {
/**
* [signal]
@ -170,7 +261,7 @@ class IDF_Form_Admin_UserUpdate extends Pluf_Form
{
$last_name = trim($this->cleaned_data['last_name']);
if ($last_name == mb_strtoupper($last_name)) {
return mb_convert_case(mb_strtolower($last_name),
return mb_convert_case(mb_strtolower($last_name),
MB_CASE_TITLE, 'UTF-8');
}
return $last_name;
@ -183,7 +274,7 @@ class IDF_Form_Admin_UserUpdate extends Pluf_Form
throw new Pluf_Form_Invalid(__('--- is not a valid first name.'));
}
if ($first_name == mb_strtoupper($first_name)) {
$first_name = mb_convert_case(mb_strtolower($first_name),
$first_name = mb_convert_case(mb_strtolower($first_name),
MB_CASE_TITLE, 'UTF-8');
}
return $first_name;
@ -201,12 +292,23 @@ class IDF_Form_Admin_UserUpdate extends Pluf_Form
return $email;
}
function clean_custom_avatar()
{
// Just png, jpeg/jpg or gif
if (!preg_match('/\.(png|jpg|jpeg|gif)$/i', $this->cleaned_data['custom_avatar']) &&
$this->cleaned_data['custom_avatar'] != '') {
@unlink(Pluf::f('upload_path').'/avatars/'.$this->cleaned_data['custom_avatar']);
throw new Pluf_Form_Invalid(__('For security reason, you cannot upload a file with this extension.'));
}
return $this->cleaned_data['custom_avatar'];
}
/**
* Check to see if the 2 passwords are the same.
* Check to see if the two passwords are the same.
*/
public function clean()
{
if (!isset($this->errors['password'])
if (!isset($this->errors['password'])
&& !isset($this->errors['password2'])) {
$password1 = $this->cleaned_data['password'];
$password2 = $this->cleaned_data['password2'];

View File

@ -0,0 +1,51 @@
<?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.
#
# Plume Framework is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Plume Framework 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser 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 ***** */
/**
* Similar to Pluf_Form_Field_Email, this form field validates one or more
* email addresses separated by a comma
*/
class IDF_Form_Field_EmailList extends Pluf_Form_Field
{
public $widget = 'Pluf_Form_Widget_TextInput';
public function clean($value)
{
parent::clean($value);
if (in_array($value, $this->empty_values)) {
$value = '';
}
if ($value == '') {
return $value;
}
$emails = preg_split('/\s*,\s*/', $value, -1, PREG_SPLIT_NO_EMPTY);
foreach ($emails as $email) {
if (!Pluf_Utils::isValidEmail($email)) {
throw new Pluf_Form_Invalid(__(
'Please enter one or more valid email addresses.'
));
}
}
return implode(',', $emails);
}
}

View File

@ -45,7 +45,7 @@ class IDF_Form_TabsConf extends Pluf_Form
array('required' => true,
'label' => $label,
'initial' => $this->conf->getVal($key, 'all'),
'widget_attrs' => array('choices' =>
'widget_attrs' => array('choices' =>
array(
__('Open to all') => 'all',
__('Signed in users') => 'login',
@ -63,10 +63,11 @@ class IDF_Form_TabsConf extends Pluf_Form
'source_notification_email',
'issues_notification_email',);
foreach ($ak as $key) {
$this->fields[$key] = new Pluf_Form_Field_Email(
$this->fields[$key] = new IDF_Form_Field_EmailList(
array('required' => false,
'label' => $key,
'initial' => $this->conf->getVal($key, ''),
'widget_attrs' => array('size' => 40),
));
}

View File

@ -33,6 +33,8 @@ class IDF_Form_UserAccount extends Pluf_Form
public function initFields($extra=array())
{
$this->user = $extra['user'];
$user_data = IDF_UserData::factory($this->user);
$this->fields['first_name'] = new Pluf_Form_Field_Varchar(
array('required' => false,
'label' => __('First name'),
@ -92,6 +94,66 @@ class IDF_Form_UserAccount extends Pluf_Form
),
));
$this->fields['description'] = new Pluf_Form_Field_Varchar(
array('required' => false,
'label' => __('Description'),
'initial' => $user_data->description,
'widget_attrs' => array('rows' => 3,
'cols' => 40),
'widget' => 'Pluf_Form_Widget_TextareaInput',
));
$this->fields['twitter'] = new Pluf_Form_Field_Varchar(
array('required' => false,
'label' => __('Twitter username'),
'initial' => $user_data->twitter,
'widget_attrs' => array(
'maxlength' => 50,
'size' => 15,
),
));
$this->fields['public_email'] = new Pluf_Form_Field_Email(
array('required' => false,
'label' => __('Public email address'),
'initial' => $user_data->public_email,
'widget_attrs' => array(
'maxlength' => 50,
'size' => 15,
),
));
$this->fields['website'] = new Pluf_Form_Field_Url(
array('required' => false,
'label' => __('Website URL'),
'initial' => $user_data->website,
'widget_attrs' => array(
'maxlength' => 50,
'size' => 15,
),
));
$this->fields['custom_avatar'] = new Pluf_Form_Field_File(
array('required' => false,
'label' => __('Upload custom avatar'),
'initial' => '',
'max_size' => Pluf::f('max_upload_size', 2097152),
'move_function_params' => array('upload_path' => Pluf::f('upload_path').'/avatars',
'upload_path_create' => true,
'upload_overwrite' => true,
'file_name' => 'user_'.$this->user->id.'_%s'),
'help_text' => __('An image file with a width and height not larger than 60 pixels (bigger images are scaled down).'),
));
$this->fields['remove_custom_avatar'] = new Pluf_Form_Field_Boolean(
array('required' => false,
'label' => __('Remove custom avatar'),
'initial' => false,
'widget' => 'Pluf_Form_Widget_CheckboxInput',
'widget_attrs' => array(),
'help_text' => __('Tick this to delete the custom avatar.'),
));
$this->fields['public_key'] = new Pluf_Form_Field_Varchar(
array('required' => false,
'label' => __('Add a public key'),
@ -138,7 +200,7 @@ class IDF_Form_UserAccount extends Pluf_Form
'email' => $new_email,
'user'=> $this->user,
)
);
);
$tmpl = new Pluf_Template('idf/user/changeemail-email.txt');
$text_email = $tmpl->render($context);
$email = new Pluf_Mail(Pluf::f('from_email'), $new_email,
@ -157,8 +219,37 @@ class IDF_Form_UserAccount extends Pluf_Form
$key->create();
}
}
if ($commit) {
$this->user->update();
// FIXME: go the extra mile and check the input lengths for
// all fields here!
// FIXME: this is all doubled in admin/UserUpdate!
$user_data = IDF_UserData::factory($this->user);
// Add or remove avatar - we need to do this here because every
// single setter directly leads to a save in the database
if ($user_data->avatar != '' &&
($this->cleaned_data['remove_custom_avatar'] == 1 ||
$this->cleaned_data['custom_avatar'] != '')) {
$avatar_path = Pluf::f('upload_path').'/avatars/'.basename($user_data->avatar);
if (basename($avatar_path) != '' && is_file($avatar_path)) {
unlink($avatar_path);
}
$user_data->avatar = '';
}
if ($this->cleaned_data['custom_avatar'] != '') {
$user_data->avatar = $this->cleaned_data['custom_avatar'];
}
$user_data->description = $this->cleaned_data['description'];
$user_data->twitter = $this->cleaned_data['twitter'];
$user_data->public_email = $this->cleaned_data['public_email'];
$user_data->website = $this->cleaned_data['website'];
if ($update_pass) {
/**
* [signal]
@ -266,6 +357,19 @@ class IDF_Form_UserAccount extends Pluf_Form
return $key;
}
function clean_custom_avatar()
{
// Just png, jpeg/jpg or gif
if (!preg_match('/\.(png|jpg|jpeg|gif)$/i', $this->cleaned_data['custom_avatar']) &&
$this->cleaned_data['custom_avatar'] != '') {
@unlink(Pluf::f('upload_path').'/avatars/'.$this->cleaned_data['custom_avatar']);
throw new Pluf_Form_Invalid(__('For security reason, you cannot upload a file with this extension.'));
}
return $this->cleaned_data['custom_avatar'];
}
function clean_last_name()
{
$last_name = trim($this->cleaned_data['last_name']);
@ -322,4 +426,6 @@ class IDF_Form_UserAccount extends Pluf_Form
return $this->cleaned_data;
}
}

View File

@ -46,7 +46,7 @@ class IDF_Gconf extends Pluf_Model
array(
'type' => 'Pluf_DB_Field_Sequence',
//It is automatically added.
'blank' => true,
'blank' => true,
),
'model_class' =>
array(
@ -108,7 +108,7 @@ class IDF_Gconf extends Pluf_Model
*/
function setVal($key, $value)
{
if (!is_null($this->getVal($key, null))
if (!is_null($this->getVal($key, null))
and $value == $this->getVal($key)) {
return;
}
@ -121,7 +121,7 @@ class IDF_Gconf extends Pluf_Model
$this->datacache[$key] = $value;
return;
}
}
}
// we insert
$conf = new IDF_Gconf();
$conf->model_class = $this->_mod->_model;

View File

@ -42,9 +42,9 @@ class IDF_Issue extends Pluf_Model
'id' =>
array(
'type' => 'Pluf_DB_Field_Sequence',
'blank' => true,
'blank' => true,
),
'project' =>
'project' =>
array(
'type' => 'Pluf_DB_Field_Foreignkey',
'model' => 'IDF_Project',
@ -59,7 +59,7 @@ class IDF_Issue extends Pluf_Model
'size' => 250,
'verbose' => __('summary'),
),
'submitter' =>
'submitter' =>
array(
'type' => 'Pluf_DB_Field_Foreignkey',
'model' => 'Pluf_User',
@ -67,7 +67,7 @@ class IDF_Issue extends Pluf_Model
'verbose' => __('submitter'),
'relate_name' => 'submitted_issue',
),
'owner' =>
'owner' =>
array(
'type' => 'Pluf_DB_Field_Foreignkey',
'model' => 'Pluf_User',
@ -76,7 +76,7 @@ class IDF_Issue extends Pluf_Model
'verbose' => __('owner'),
'relate_name' => 'owned_issue',
),
'interested' =>
'interested' =>
array(
'type' => 'Pluf_DB_Field_Manytomany',
'model' => 'Pluf_User',
@ -86,14 +86,14 @@ class IDF_Issue extends Pluf_Model
),
'tags' =>
array(
'type' => 'Pluf_DB_Field_Manytomany',
'type' => 'Pluf_DB_Field_Manytomany',
'blank' => true,
'model' => 'IDF_Tag',
'verbose' => __('labels'),
),
'status' =>
'status' =>
array(
'type' => 'Pluf_DB_Field_Foreignkey',
'type' => 'Pluf_DB_Field_Foreignkey',
'blank' => false,
'model' => 'IDF_Tag',
'verbose' => __('status'),
@ -111,7 +111,7 @@ class IDF_Issue extends Pluf_Model
'verbose' => __('modification date'),
),
);
$this->_a['idx'] = array(
$this->_a['idx'] = array(
'modif_dtime_idx' =>
array(
'col' => 'modif_dtime',
@ -120,7 +120,7 @@ class IDF_Issue extends Pluf_Model
);
$table = $this->_con->pfx.'idf_issue_idf_tag_assoc';
$this->_a['views'] = array(
'join_tags' =>
'join_tags' =>
array(
'join' => 'LEFT JOIN '.$table
.' ON idf_issue_id=id',
@ -164,7 +164,7 @@ class IDF_Issue extends Pluf_Model
// that the issue as at least one comment in the database when
// doing the indexing.
if ($create) {
IDF_Timeline::insert($this, $this->get_project(),
IDF_Timeline::insert($this, $this->get_project(),
$this->get_submitter());
}
}
@ -177,12 +177,12 @@ class IDF_Issue extends Pluf_Model
* as such create links to other items etc. You can consider that
* if displayed, you can create a link to it.
*
* @param Pluf_HTTP_Request
* @param Pluf_HTTP_Request
* @return Pluf_Template_SafeString
*/
public function timelineFragment($request)
{
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Issue::view',
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Issue::view',
array($request->project->shortname,
$this->id));
$out = '<tr class="log"><td><a href="'.$url.'">'.
@ -193,14 +193,14 @@ class IDF_Issue extends Pluf_Model
$ic = (in_array($this->status, $request->project->getTagIdsByStatus('closed'))) ? 'issue-c' : 'issue-o';
$out .= sprintf(__('<a href="%1$s" class="%2$s" title="View issue">Issue %3$d</a>, %4$s'), $url, $ic, $this->id, Pluf_esc($this->summary)).'</td>';
$out .= "\n".'<tr class="extra"><td colspan="2">
<div class="helptext right">'.sprintf(__('Creation of <a href="%s" class="%s">issue&nbsp;%d</a>, by %s'), $url, $ic, $this->id, $user).'</div></td></tr>';
<div class="helptext right">'.sprintf(__('Creation of <a href="%s" class="%s">issue&nbsp;%d</a>, by %s'), $url, $ic, $this->id, $user).'</div></td></tr>';
return Pluf_Template::markSafe($out);
}
public function feedFragment($request)
{
$url = Pluf::f('url_base')
.Pluf_HTTP_URL_urlForView('IDF_Views_Issue::view',
.Pluf_HTTP_URL_urlForView('IDF_Views_Issue::view',
array($request->project->shortname,
$this->id));
$title = sprintf(__('%s: Issue %d created - %s'),
@ -241,15 +241,17 @@ class IDF_Issue extends Pluf_Model
$prj = $this->get_project();
$to_email = array();
if ('' != $conf->getVal('issues_notification_email', '')) {
$langs = Pluf::f('languages', array('en'));
$to_email[] = array($conf->getVal('issues_notification_email'),
$langs[0]);
$langs = Pluf::f('languages', array('en'));
$addresses = explode(',', $conf->getVal('issues_notification_email'));
foreach ($addresses as $address) {
$to_email[] = array($address, $langs[0]);
}
}
$current_locale = Pluf_Translation::getLocale();
$id = '<'.md5($this->id.md5(Pluf::f('secret_key'))).'@'.Pluf::f('mail_host', 'localhost').'>';
if ($create) {
if (null != $this->get_owner() and $this->owner != $this->submitter) {
$email_lang = array($this->get_owner()->email,
if (null != $this->get_owner() and $this->owner != $this->submitter) {
$email_lang = array($this->get_owner()->email,
$this->get_owner()->language);
if (!in_array($email_lang, $to_email)) {
$to_email[] = $email_lang;

View File

@ -41,9 +41,9 @@ class IDF_IssueComment extends Pluf_Model
'id' =>
array(
'type' => 'Pluf_DB_Field_Sequence',
'blank' => true,
'blank' => true,
),
'issue' =>
'issue' =>
array(
'type' => 'Pluf_DB_Field_Foreignkey',
'model' => 'IDF_Issue',
@ -57,7 +57,7 @@ class IDF_IssueComment extends Pluf_Model
'blank' => false,
'verbose' => __('comment'),
),
'submitter' =>
'submitter' =>
array(
'type' => 'Pluf_DB_Field_Foreignkey',
'model' => 'Pluf_User',
@ -79,7 +79,7 @@ class IDF_IssueComment extends Pluf_Model
'verbose' => __('creation date'),
),
);
$this->_a['idx'] = array(
$this->_a['idx'] = array(
'creation_dtime_idx' =>
array(
'col' => 'creation_dtime',
@ -119,7 +119,7 @@ class IDF_IssueComment extends Pluf_Model
$sql = new Pluf_SQL('issue=%s', array($this->issue));
$co = Pluf::factory('IDF_IssueComment')->getList(array('filter'=>$sql->gen()));
if ($co->count() > 1) {
IDF_Timeline::insert($this, $this->get_issue()->get_project(),
IDF_Timeline::insert($this, $this->get_issue()->get_project(),
$this->get_submitter());
}
}
@ -129,7 +129,7 @@ class IDF_IssueComment extends Pluf_Model
public function timelineFragment($request)
{
$issue = $this->get_issue();
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Issue::view',
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Issue::view',
array($request->project->shortname,
$issue->id));
$url .= '#ic'.$this->id;
@ -168,7 +168,7 @@ class IDF_IssueComment extends Pluf_Model
}
$out .= '</td></tr>';
$out .= "\n".'<tr class="extra"><td colspan="2">
<div class="helptext right">'.sprintf(__('Comment on <a href="%s" class="%s">issue&nbsp;%d</a>, by %s'), $url, $ic, $issue->id, $user).'</div></td></tr>';
<div class="helptext right">'.sprintf(__('Comment on <a href="%s" class="%s">issue&nbsp;%d</a>, by %s'), $url, $ic, $issue->id, $user).'</div></td></tr>';
return Pluf_Template::markSafe($out);
}
@ -176,7 +176,7 @@ class IDF_IssueComment extends Pluf_Model
{
$issue = $this->get_issue();
$url = Pluf::f('url_base')
.Pluf_HTTP_URL_urlForView('IDF_Views_Issue::view',
.Pluf_HTTP_URL_urlForView('IDF_Views_Issue::view',
array($request->project->shortname,
$issue->id));
$title = sprintf(__('%s: Comment on issue %d - %s'),
@ -196,4 +196,9 @@ class IDF_IssueComment extends Pluf_Model
$tmpl = new Pluf_Template('idf/issues/feedfragment.xml');
return $tmpl->render($context);
}
public function get_submitter_data()
{
return IDF_UserData::factory($this->get_submitter());
}
}

View File

@ -39,9 +39,9 @@ class IDF_IssueFile extends Pluf_Model
array(
'type' => 'Pluf_DB_Field_Sequence',
//It is automatically added.
'blank' => true,
'blank' => true,
),
'comment' =>
'comment' =>
array(
'type' => 'Pluf_DB_Field_Foreignkey',
'model' => 'IDF_IssueComment',
@ -49,7 +49,7 @@ class IDF_IssueFile extends Pluf_Model
'verbose' => __('comment'),
'relate_name' => 'attachment',
),
'submitter' =>
'submitter' =>
array(
'type' => 'Pluf_DB_Field_Foreignkey',
'model' => 'Pluf_User',
@ -63,7 +63,7 @@ class IDF_IssueFile extends Pluf_Model
'size' => 100,
'verbose' => __('file name'),
),
'attachment' =>
'attachment' =>
array(
'type' => 'Pluf_DB_Field_File',
'blank' => false,
@ -76,7 +76,7 @@ class IDF_IssueFile extends Pluf_Model
'verbose' => __('file size'),
'help_text' => 'Size in bytes.',
),
'type' =>
'type' =>
array(
'type' => 'Pluf_DB_Field_Varchar',
'blank' => false,
@ -111,7 +111,7 @@ class IDF_IssueFile extends Pluf_Model
$file = Pluf::f('upload_issue_path').'/'.$this->attachment;
$this->filesize = filesize($file);
// remove .dummy
$this->filename = substr(basename($file), 0, -6);
$this->filename = substr(basename($file), 0, -6);
$img_extensions = array('jpeg', 'jpg', 'png', 'gif');
$info = pathinfo($this->filename);
if (!isset($info['extension'])) $info['extension'] = '';
@ -128,4 +128,10 @@ class IDF_IssueFile extends Pluf_Model
{
@unlink(Pluf::f('upload_issue_path').'/'.$this->attachment);
}
function isText()
{
$info = IDF_FileUtil::getMimeType($this->filename);
return IDF_FileUtil::isText($info);
}
}

View File

@ -25,12 +25,12 @@
* A comment set on a review.
*
* A comment is associated to a patch as a review can have many
* patches associated to it.
* patches associated to it.
*
* A comment is also tracking the changes in the review in the same
* way the issue comment is tracking the changes in the issue.
*
*
*
*/
class IDF_Review_Comment extends Pluf_Model
{
@ -45,9 +45,9 @@ class IDF_Review_Comment extends Pluf_Model
'id' =>
array(
'type' => 'Pluf_DB_Field_Sequence',
'blank' => true,
'blank' => true,
),
'patch' =>
'patch' =>
array(
'type' => 'Pluf_DB_Field_Foreignkey',
'model' => 'IDF_Review_Patch',
@ -61,7 +61,7 @@ class IDF_Review_Comment extends Pluf_Model
'blank' => true, // if only commented on lines
'verbose' => __('comment'),
),
'submitter' =>
'submitter' =>
array(
'type' => 'Pluf_DB_Field_Foreignkey',
'model' => 'Pluf_User',
@ -118,8 +118,8 @@ class IDF_Review_Comment extends Pluf_Model
function postSave($create=false)
{
if ($create) {
IDF_Timeline::insert($this,
$this->get_patch()->get_review()->get_project(),
IDF_Timeline::insert($this,
$this->get_patch()->get_review()->get_project(),
$this->get_submitter());
}
}
@ -127,7 +127,7 @@ class IDF_Review_Comment extends Pluf_Model
public function timelineFragment($request)
{
$review = $this->get_patch()->get_review();
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Review::view',
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Review::view',
array($request->project->shortname,
$review->id));
$out = '<tr class="log"><td><a href="'.$url.'">'.
@ -138,14 +138,14 @@ class IDF_Review_Comment extends Pluf_Model
$ic = (in_array($review->status, $request->project->getTagIdsByStatus('closed'))) ? 'issue-c' : 'issue-o';
$out .= sprintf(__('<a href="%1$s" class="%2$s" title="View review">Review %3$d</a>, %4$s'), $url, $ic, $review->id, Pluf_esc($review->summary)).'</td>';
$out .= "\n".'<tr class="extra"><td colspan="2">
<div class="helptext right">'.sprintf(__('Update of <a href="%s" class="%s">review&nbsp;%d</a>, by %s'), $url, $ic, $review->id, $user).'</div></td></tr>';
<div class="helptext right">'.sprintf(__('Update of <a href="%s" class="%s">review&nbsp;%d</a>, by %s'), $url, $ic, $review->id, $user).'</div></td></tr>';
return Pluf_Template::markSafe($out);
}
public function feedFragment($request)
{
$review = $this->get_patch()->get_review();
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Review::view',
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Review::view',
array($request->project->shortname,
$review->id));
$title = sprintf(__('%s: Updated review %d - %s'),
@ -221,4 +221,9 @@ class IDF_Review_Comment extends Pluf_Model
}
Pluf_Translation::loadSetLocale($current_locale);
}
public function get_submitter_data()
{
return IDF_UserData::factory($this->get_submitter());
}
}

View File

@ -197,14 +197,17 @@ class IDF_Review_Patch extends Pluf_Model
);
$tmpl = new Pluf_Template('idf/review/review-created-email.txt');
$text_email = $tmpl->render($context);
$email = new Pluf_Mail(Pluf::f('from_email'),
$conf->getVal('review_notification_email'),
sprintf(__('New Code Review %s - %s (%s)'),
$this->get_review()->id,
$this->get_review()->summary,
$this->get_review()->get_project()->shortname));
$email->addTextMessage($text_email);
$email->sendMail();
$addresses = explode(';',$conf->getVal('review_notification_email'));
foreach ($addresses as $address) {
$email = new Pluf_Mail(Pluf::f('from_email'),
$address,
sprintf(__('New Code Review %s - %s (%s)'),
$this->get_review()->id,
$this->get_review()->summary,
$this->get_review()->get_project()->shortname));
$email->addTextMessage($text_email);
$email->sendMail();
}
Pluf_Translation::loadSetLocale($current_locale);
}
}

View File

@ -316,6 +316,34 @@ class IDF_Scm
throw new Pluf_Exception_NotImplemented();
}
/**
* Returns all recorded changes which lead to the particular commit
* or revision.
*
* Example output:
*
* stdClass object {
* 'additions' => array('path/to/file', 'path/to/directory', ...),
* 'deletions' => array('path/to/file', 'path/to/directory', ...),
* 'renames' => array('old/path/to/file' => 'new/path/to/file', ...)
* 'patches' => array('path/to/file', ...),
* 'properties' => array('path/to/file' => array(
* 'propname' => 'propvalue', 'deletedprop' => null, ...)
* ),
* ...)
* }
*
* Each member of the returned object is mandatory, but may contain
* an empty array if no changes were recorded.
*
* @param string A commit identifier
* @return object with arrays of individual changes
*/
public function getChanges($commit)
{
throw new Pluf_Exception_NotImplemented();
}
/**
* Get latest changes.
*

View File

@ -85,6 +85,8 @@ class IDF_Scm_Cache_Git extends Pluf_Model
array($this->_project->id));
foreach (Pluf::factory(__CLASS__)->getList(array('filter' => $sql->gen())) as $blob) {
$tmp = explode(chr(31), $blob->content, 3);
// sometimes the title might be empty
if (!isset($tmp[2])) $tmp[2] = '';
$res[$blob->githash] = (object) array(
'hash' => $blob->githash,
@ -131,4 +133,4 @@ class IDF_Scm_Cache_Git extends Pluf_Model
),
);
}
}
}

View File

@ -431,13 +431,13 @@ class IDF_Scm_Git extends IDF_Scm
}
}
$out = self::parseLog($log);
$out[0]->changes = implode("\n", $change);
$out[0]->diff = implode("\n", $change);
} else {
$out = self::parseLog($out);
$out[0]->changes = '';
$out[0]->diff = '';
}
$out[0]->branch = $this->inBranches($commit, null);
$out[0]->branch = implode(', ', $this->inBranches($commit, null));
return $out[0];
}

View File

@ -359,7 +359,7 @@ class IDF_Scm_Mercurial extends IDF_Scm
}
}
$out = self::parseLog($log, 6);
$out[0]->changes = implode("\n", $change);
$out[0]->diff = implode("\n", $change);
return $out[0];
}

View File

@ -599,6 +599,75 @@ class IDF_Scm_Monotone extends IDF_Scm
);
}
/**
* @see IDF_Scm::getChanges()
*/
public function getChanges($commit)
{
$revs = $this->_resolveSelector($commit);
if (count($revs) == 0)
return null;
$revision = $revs[0];
$out = $this->stdio->exec(array('get_revision', $revision));
$stanzas = IDF_Scm_Monotone_BasicIO::parse($out);
$return = (object) array(
'additions' => array(),
'deletions' => array(),
'renames' => array(),
'patches' => array(),
'properties' => array(),
);
foreach ($stanzas as $stanza) {
if ($stanza[0]['key'] == 'format_version' ||
$stanza[0]['key'] == 'old_revision' ||
$stanza[0]['key'] == 'new_manifest')
continue;
if ($stanza[0]['key'] == 'add_file' ||
$stanza[0]['key'] == 'add_dir') {
$return->additions[] = $stanza[0]['values'][0];
continue;
}
if ($stanza[0]['key'] == 'delete') {
$return->deletions[] = $stanza[0]['values'][0];
continue;
}
if ($stanza[0]['key'] == 'rename') {
$return->renames[$stanza[0]['values'][0]] =
$stanza[1]['values'][0];
continue;
}
if ($stanza[0]['key'] == 'patch') {
$return->patches[] = $stanza[0]['values'][0];
continue;
}
if ($stanza[0]['key'] == 'clear' ||
$stanza[0]['key'] == 'set') {
$filename = $stanza[0]['values'][0];
if (!array_key_exists($filename, $return->properties)) {
$return->properties[$filename] = array();
}
$key = $stanza[1]['values'][0];
$value = null;
if (isset($stanza[2])) {
$value = $stanza[2]['values'][0];
}
$return->properties[$filename][$key] = $value;
continue;
}
}
return $return;
}
/**
* @see IDF_Scm::getCommit()
*/
@ -626,7 +695,7 @@ class IDF_Scm_Monotone extends IDF_Scm
$res['branch'] = implode(', ', $certs['branch']);
$res['commit'] = $revs[0];
$res['changes'] = ($getdiff) ? $this->_getDiff($revs[0]) : '';
$res['diff'] = ($getdiff) ? $this->_getDiff($revs[0]) : '';
return (object) $res;
}
@ -709,10 +778,10 @@ class IDF_Scm_Monotone extends IDF_Scm
$log['commit'] = $rev;
$logs[] = (object)$log;
}
$out = $this->stdio->exec(array('parents', $rev));
$horizont += preg_split("/\n/", $out, -1, PREG_SPLIT_NO_EMPTY);
$out = $this->stdio->exec(array('parents', $rev));
$horizont += preg_split("/\n/", $out, -1, PREG_SPLIT_NO_EMPTY);
}
}
return $logs;

View File

@ -398,7 +398,7 @@ class IDF_Scm_Svn extends IDF_Scm
*/
public function getCommit($commit, $getdiff=false)
{
if (!$this->isValidRevision($commit)) {
if ($this->validateRevision($commit) != IDF_Scm::REVISION_VALID) {
return false;
}
$res = array();
@ -414,7 +414,7 @@ class IDF_Scm_Svn extends IDF_Scm
$res['date'] = gmdate('Y-m-d H:i:s', strtotime((string) $xml->logentry->date));
$res['title'] = (string) $xml->logentry->msg;
$res['commit'] = (string) $xml->logentry['revision'];
$res['changes'] = ($getdiff) ? $this->getDiff($commit) : '';
$res['diff'] = ($getdiff) ? $this->getDiff($commit) : '';
$res['tree'] = '';
$res['branch'] = '';
return (object) $res;

View File

@ -51,9 +51,13 @@ class IDF_Template_IssueComment extends Pluf_Template_Tag
array($this, 'callbackReviews'), $text);
}
if ($request->rights['hasSourceAccess']) {
$text = preg_replace_callback('#(commits?\s+)([0-9a-f]{1,40}(?:(?:\s+and|\s+or|,)\s+[0-9a-f]{1,40})*)\b#i',
$verbs = array('added', 'fixed', 'reverted', 'changed', 'removed');
$nouns = array('commit', 'commits', 'revision', 'revisions', 'rev', 'revs');
$prefix = implode(' in|', $verbs).' in' . '|'.
implode('|', $nouns);
$text = preg_replace_callback('#((?:'.$prefix.')(?:\s+r?))([0-9a-f]{1,40}((?:\s+and|\s+or|,)\s+r?[0-9a-f]{1,40})*)\b#i',
array($this, 'callbackCommits'), $text);
$text = preg_replace_callback('#(src:)([^\s\(\)\\\\]+(?:(\\\\)\s+[^\s\(\)\\\\]+){0,})+#im',
$text = preg_replace_callback('=(src:)([^\s@#,\(\)\\\\]+(?:(\\\\)[\s@#][^\s@#,\(\)\\\\]+){0,})+(?:\@([^\s#,]+))(?:#(\d+))?=im',
array($this, 'callbackSource'), $text);
}
if ($wordwrap) $text = Pluf_Text::wrapHtml($text, 69, "\n");
@ -122,15 +126,12 @@ class IDF_Template_IssueComment extends Pluf_Template_Tag
function callbackCommits($m)
{
$keyword = rtrim($m[1]);
if ('commits' === $keyword) {
// Multiple commits like 'commits 6e030e6, a25bfc1 and
// 3c094f8'.
return $m[1].preg_replace_callback('#\b[0-9a-f]{4,40}\b#i', array($this, 'callbackCommit'), $m[2]);
} else if ('commit' === $keyword) {
if (empty($m[3])) {
// Single commit like 'commit 6e030e6'.
return $m[1].call_user_func(array($this, 'callbackCommit'), array($m[2]));
}
return $m[0];
// Multiple commits like 'commits 6e030e6, a25bfc1 and 3c094f8'.
return $m[1].preg_replace_callback('#\b[0-9a-f]{1,40}\b#i', array($this, 'callbackCommit'), $m[2]);
}
/**
@ -189,17 +190,38 @@ class IDF_Template_IssueComment extends Pluf_Template_Tag
function callbackSource($m)
{
if (!$this->scm->isAvailable()) return $m[0];
if (!$this->scm->isAvailable())
return $m[0];
$commit = null;
if (!empty($m[4])) {
if (!$this->scm->getCommit($m[4])) {
return $m[0];
}
$commit = $m[4];
}
$file = $m[2];
if (!empty($m[3])) $file = str_replace($m[3], '', $file);
$request_file_info = $this->scm->getPathInfo($file);
if (!empty($m[3]))
$file = str_replace($m[3], '', $file);
$linktext = $file;
if (!empty($commit))
$linktext .= '@'.$commit;
$request_file_info = $this->scm->getPathInfo($file, $commit);
if (!$request_file_info) {
return $m[0];
}
if ($request_file_info->type != 'tree') {
return $m[1].'<a href="'.Pluf_HTTP_URL_urlForView('IDF_Views_Source::tree', array($this->project->shortname, $this->scm->getMainBranch(), $file)).'">'.$file.'</a>';
if ($request_file_info->type == 'tree') {
return $m[0];
}
return $m[0];
$link = Pluf_HTTP_URL_urlForView('IDF_Views_Source::tree', array(
$this->project->shortname,
$commit == null ? $this->scm->getMainBranch() : $commit,
$file
));
if (!empty($m[5])) {
$link .= '#L'.$m[5];
$linktext .= '#'.$m[5];
}
return $m[1].'<a href="'.$link.'">'.$linktext.'</a>';
}
/**

View File

@ -93,7 +93,7 @@ class IDF_Template_Markdown extends Pluf_Template_Tag
$info = pathinfo($m[1]);
$fileinfo = array($res->headers['Content-Type'], $m[1],
isset($info['extension']) ? $info['extension'] : 'bin');
if (!IDF_Views_Source::isText($fileinfo)) {
if (!IDF_FileUtil::isText($fileinfo)) {
return $m[0];
}
return $res->content;

View 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]);
}
}
}

View File

@ -32,19 +32,6 @@ class IDF_Tests_TestSource extends UnitTestCase
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()
{
$regex = '#^/p/([\-\w]+)/source/tree/([^\/]+)/(.*)$#';
@ -61,4 +48,4 @@ class IDF_Tests_TestSource extends UnitTestCase
$this->assertEqual($res[2], $m[3]);
}
}
}
}

View File

@ -39,9 +39,9 @@ class IDF_Upload extends Pluf_Model
'id' =>
array(
'type' => 'Pluf_DB_Field_Sequence',
'blank' => true,
'blank' => true,
),
'project' =>
'project' =>
array(
'type' => 'Pluf_DB_Field_Foreignkey',
'model' => 'IDF_Project',
@ -77,7 +77,7 @@ class IDF_Upload extends Pluf_Model
'default' => 0,
'verbose' => __('file size in bytes'),
),
'submitter' =>
'submitter' =>
array(
'type' => 'Pluf_DB_Field_Foreignkey',
'model' => 'Pluf_User',
@ -87,7 +87,7 @@ class IDF_Upload extends Pluf_Model
),
'tags' =>
array(
'type' => 'Pluf_DB_Field_Manytomany',
'type' => 'Pluf_DB_Field_Manytomany',
'blank' => true,
'model' => 'IDF_Tag',
'verbose' => __('labels'),
@ -112,7 +112,7 @@ class IDF_Upload extends Pluf_Model
'verbose' => __('modification date'),
),
);
$this->_a['idx'] = array(
$this->_a['idx'] = array(
'modif_dtime_idx' =>
array(
'col' => 'modif_dtime',
@ -121,7 +121,7 @@ class IDF_Upload extends Pluf_Model
);
$table = $this->_con->pfx.'idf_tag_idf_upload_assoc';
$this->_a['views'] = array(
'join_tags' =>
'join_tags' =>
array(
'join' => 'LEFT JOIN '.$table
.' ON idf_upload_id=id',
@ -150,7 +150,7 @@ class IDF_Upload extends Pluf_Model
function postSave($create=false)
{
if ($create) {
IDF_Timeline::insert($this, $this->get_project(),
IDF_Timeline::insert($this, $this->get_project(),
$this->get_submitter(), $this->creation_dtime);
}
}
@ -173,13 +173,13 @@ class IDF_Upload extends Pluf_Model
* Returns the timeline fragment for the file.
*
*
* @param Pluf_HTTP_Request
* @param Pluf_HTTP_Request
* @return Pluf_Template_SafeString
*/
public function timelineFragment($request)
{
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Download::view',
array($request->project->shortname,
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Download::view',
array($request->project->shortname,
$this->id));
$out = '<tr class="log"><td><a href="'.$url.'">'.
Pluf_esc(Pluf_Template_dateAgo($this->creation_dtime, 'without')).
@ -189,15 +189,15 @@ class IDF_Upload extends Pluf_Model
$out .= sprintf(__('<a href="%1$s" title="View download">Download %2$d</a>, %3$s'), $url, $this->id, Pluf_esc($this->summary)).'</td>';
$out .= '</tr>';
$out .= "\n".'<tr class="extra"><td colspan="2">
<div class="helptext right">'.sprintf(__('Addition of <a href="%s">download&nbsp;%d</a>, by %s'), $url, $this->id, $user).'</div></td></tr>';
<div class="helptext right">'.sprintf(__('Addition of <a href="%s">download&nbsp;%d</a>, by %s'), $url, $this->id, $user).'</div></td></tr>';
return Pluf_Template::markSafe($out);
}
public function feedFragment($request)
{
$url = Pluf::f('url_base')
.Pluf_HTTP_URL_urlForView('IDF_Views_Download::view',
array($request->project->shortname,
.Pluf_HTTP_URL_urlForView('IDF_Views_Download::view',
array($request->project->shortname,
$this->id));
$title = sprintf(__('%s: Download %d added - %s'),
$request->project->name,
@ -227,7 +227,7 @@ class IDF_Upload extends Pluf_Model
}
$current_locale = Pluf_Translation::getLocale();
$langs = Pluf::f('languages', array('en'));
Pluf_Translation::loadSetLocale($langs[0]);
Pluf_Translation::loadSetLocale($langs[0]);
$context = new Pluf_Template_Context(
array('file' => $this,
@ -237,14 +237,16 @@ class IDF_Upload extends Pluf_Model
));
$tmpl = new Pluf_Template('idf/downloads/download-created-email.txt');
$text_email = $tmpl->render($context);
$email = new Pluf_Mail(Pluf::f('from_email'),
$conf->getVal('downloads_notification_email'),
sprintf(__('New download - %s (%s)'),
$this->summary,
$this->get_project()->shortname));
$email->addTextMessage($text_email);
$email->sendMail();
$addresses = explode(',', $conf->getVal('downloads_notification_email'));
foreach ($addresses as $address) {
$email = new Pluf_Mail(Pluf::f('from_email'),
$address,
sprintf(__('New download - %s (%s)'),
$this->summary,
$this->get_project()->shortname));
$email->addTextMessage($text_email);
$email->sendMail();
}
Pluf_Translation::loadSetLocale($current_locale);
}
}

View File

@ -0,0 +1,59 @@
<?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 ***** */
/**
* Thin wrapper around the general purpose Gconf data driver
* to model a userdata object as key value store
*/
class IDF_UserData extends IDF_Gconf
{
/** columns for the underlying model for which we do not want to
override __get and __set */
private static $protectedVars =
array('id', 'model_class', 'model_id', 'vkey', 'vdesc');
function __set($key, $value)
{
if (in_array($key, self::$protectedVars))
{
parent::__set($key, $value);
return;
}
$this->setVal($key, $value);
}
function __get($key)
{
if (in_array($key, self::$protectedVars))
return parent::__get($key);
return $this->getVal($key, null);
}
public static function factory($user)
{
$conf = new IDF_UserData();
$conf->setModel((object) array('_model'=>'IDF_UserData', 'id' => $user->id));
$conf->initCache();
return $conf;
}
}

View File

@ -86,7 +86,10 @@ class IDF_Views
$title = __('Create Your Account');
$params = array('request'=>$request);
if ($request->method == 'POST') {
$form = new IDF_Form_Register($request->POST, $params);
$form = new IDF_Form_Register(array_merge(
(array)$request->POST,
(array)$request->FILES
), $params);
if ($form->isValid()) {
$user = $form->save(); // It is sending the confirmation email
$url = Pluf_HTTP_URL_urlForView('IDF_Views::registerInputKey');

View File

@ -268,7 +268,9 @@ class IDF_Views_Admin
}
if ($request->method == 'POST') {
$form = new IDF_Form_Admin_UserUpdate($request->POST, $params);
$form = new IDF_Form_Admin_UserUpdate(array_merge($request->POST,
$request->FILES),
$params);
if ($form->isValid()) {
$form->save();
$request->user->setMessage(__('The user has been updated.'));
@ -299,7 +301,9 @@ class IDF_Views_Admin
'request' => $request,
);
if ($request->method == 'POST') {
$form = new IDF_Form_Admin_UserCreate($request->POST, $params);
$form = new IDF_Form_Admin_UserCreate(array_merge($request->POST,
$request->FILES),
$params);
if ($form->isValid()) {
$cuser = $form->save();
$request->user->setMessage(sprintf(__('The user %s has been created.'), (string) $cuser));

View File

@ -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.
*/
@ -201,7 +201,7 @@ class IDF_Views_Issue
{
$prj = $request->project;
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));
return new Pluf_HTTP_Response_Redirect($url);
}
@ -263,7 +263,7 @@ class IDF_Views_Issue
'issue' => $issue,
);
if ($request->method == 'POST') {
$form = new IDF_Form_IssueUpdate(array_merge($request->POST,
$form = new IDF_Form_IssueUpdate(array_merge($request->POST,
$request->FILES),
$params);
if (!isset($request->POST['preview']) && $form->isValid()) {
@ -279,6 +279,7 @@ class IDF_Views_Issue
$form = new IDF_Form_IssueUpdate(null, $params);
}
}
$arrays = self::autoCompleteArrays($prj);
return Pluf_Shortcuts_RenderToResponse('idf/issues/view.html',
array_merge(
@ -290,7 +291,7 @@ class IDF_Views_Issue
'page_title' => $title,
'closed' => $closed,
'preview' => $preview,
'interested' =>$interested->count(),
'interested' => $interested->count(),
),
$arrays),
$request);
@ -306,7 +307,7 @@ class IDF_Views_Issue
$prj = $request->project;
$attach = Pluf_Shortcuts_GetObjectOr404('IDF_IssueFile', $match[2]);
$prj->inOr404($attach->get_comment()->get_issue());
$info = IDF_Views_Source::getMimeType($attach->filename);
$info = IDF_FileUtil::getMimeType($attach->filename);
$mime = 'application/octet-stream';
if (strpos($info[0], 'image/') === 0) {
$mime = $info[0];
@ -330,14 +331,14 @@ class IDF_Views_Issue
$prj->inOr404($attach->get_comment()->get_issue());
// If one cannot see the attachement, redirect to the
// getAttachment view.
$info = IDF_Views_Source::getMimeType($attach->filename);
if (!IDF_Views_Source::isText($info)) {
$info = IDF_FileUtil::getMimeType($attach->filename);
if (!IDF_FileUtil::isText($info)) {
return $this->getAttachment($request, $match);
}
// Now we want to look at the file but with links back to the
// issue.
$file = IDF_Views_Source::highLight($info,
file_get_contents(Pluf::f('upload_issue_path').'/'.$attach->attachment));
$file = IDF_FileUtil::highLight($info,
file_get_contents(Pluf::f('upload_issue_path').'/'.$attach->attachment));
$title = sprintf(__('View %s'), $attach->filename);
return Pluf_Shortcuts_RenderToResponse('idf/issues/attachment.html',
array(
@ -406,7 +407,7 @@ class IDF_Views_Issue
{
$prj = $request->project;
$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'))) {
throw new Pluf_HTTP_Error404();
}
@ -414,7 +415,7 @@ class IDF_Views_Issue
$title = sprintf(__('%1$s Issues with Label %2$s'), (string) $prj,
(string) $tag);
} 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);
}
// Get stats about the open/closed issues having this tag.
@ -547,11 +548,11 @@ class IDF_Views_Issue
*/
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));
$tags = array();
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'));
$tags[] = sprintf('<a class="label" href="%s">%s</a>', $url, Pluf_esc((string) $tag));
}
@ -574,4 +575,4 @@ function IDF_Views_Issue_SummaryAndLabels($field, $issue, $extra='')
function IDF_Views_Issue_ShowStatus($field, $issue, $extra='')
{
return Pluf_esc($issue->get_status()->name);
}
}

View File

@ -147,7 +147,7 @@ class IDF_Views_Project
array($prj->id));
$pag->sort_order = array('creation_dtime', 'ASC');
$pag->sort_reverse_order = array('creation_dtime');
$pag->action = array('IDF_Views_Project::timeline', array($prj->shortname));
$pag->action = array('IDF_Views_Project::timeline', array($prj->shortname, $model_filter));
$list_display = array(
'creation_dtime' => __('Age'),
'id' => __('Change'),

View File

@ -89,10 +89,10 @@ class IDF_Views_Review
));
if ($form->isValid()) {
$review = $form->save();
$urlr = Pluf_HTTP_URL_urlForView('IDF_Views_Review::view',
$urlr = Pluf_HTTP_URL_urlForView('IDF_Views_Review::view',
array($prj->shortname, $review->id));
$request->user->setMessage(sprintf(__('The <a href="%s">code review %d</a> has been created.'), $urlr, $review->id));
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Review::index',
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Review::index',
array($prj->shortname));
return new Pluf_HTTP_Response_Redirect($url);
}
@ -155,10 +155,10 @@ class IDF_Views_Review
if ($form->isValid()) {
$review_comment = $form->save();
$review = $patch->get_review();
$urlr = Pluf_HTTP_URL_urlForView('IDF_Views_Review::view',
$urlr = Pluf_HTTP_URL_urlForView('IDF_Views_Review::view',
array($prj->shortname, $review->id));
$request->user->setMessage(sprintf(__('Your <a href="%s">code review %d</a> has been published.'), $urlr, $review->id));
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Review::index',
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Review::index',
array($prj->shortname));
$review_comment->notify($request->conf);
return new Pluf_HTTP_Response_Redirect($url);
@ -181,7 +181,7 @@ class IDF_Views_Review
foreach ($cts as $ct) {
$reviewers[] = $ct->get_comment()->get_submitter();
}
if (count($def['chunks'])) {
if (count($def['chunks'])) {
$orig_file = ($fileinfo) ? $scm->getFile($fileinfo) : '';
$files[$filename] = array(
$diff->fileCompare($orig_file, $def, $filename),
@ -192,6 +192,7 @@ class IDF_Views_Review
$files[$filename] = array('', $form->f->{md5($filename)}, $cts);
}
}
$reviewers = Pluf_Model_RemoveDuplicates($reviewers);
return Pluf_Shortcuts_RenderToResponse('idf/review/view.html',
array_merge(
@ -219,7 +220,7 @@ class IDF_Views_Review
*/
function IDF_Views_Review_SummaryAndLabels($field, $review, $extra='')
{
$edit = Pluf_HTTP_URL_urlForView('IDF_Views_Review::view',
$edit = Pluf_HTTP_URL_urlForView('IDF_Views_Review::view',
array($review->shortname, $review->id));
$tags = array();
foreach ($review->get_tags_list() as $tag) {

View File

@ -31,17 +31,6 @@ Pluf::loadFunction('Pluf_Shortcuts_GetFormForModel');
*/
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.
*/
@ -211,7 +200,7 @@ class IDF_Views_Source
if ($request_file_info->type != 'tree') {
$info = self::getRequestedFileMimeType($request_file_info,
$commit, $scm);
if (!self::isText($info)) {
if (!IDF_FileUtil::isText($info)) {
$rep = new Pluf_HTTP_Response($scm->getFile($request_file_info),
$info[0]);
$rep->headers['Content-Disposition'] = 'attachment; filename="'.$info[1].'"';
@ -308,8 +297,9 @@ class IDF_Views_Source
$title = sprintf(__('%s Commit Details'), (string) $request->project);
$page_title = sprintf(__('%s Commit Details - %s'), (string) $request->project, $commit);
$rcommit = IDF_Commit::getOrAdd($cobject, $request->project);
$diff = new IDF_Diff($cobject->changes);
$diff = new IDF_Diff($cobject->diff);
$diff->parse();
$changes = $scm->getChanges($commit);
$scmConf = $request->conf->getVal('scm', 'git');
$branches = $scm->getBranches();
$in_branches = $scm->inBranches($cobject->commit, '');
@ -322,6 +312,7 @@ class IDF_Views_Source
'diff' => $diff,
'cobject' => $cobject,
'commit' => $commit,
'changes' => $changes,
'branches' => $branches,
'tree_in' => $in_branches,
'tags' => $tags,
@ -373,7 +364,7 @@ class IDF_Views_Source
$previous = substr($request_file, 0, -strlen($l.' '));
$scmConf = $request->conf->getVal('scm', 'git');
$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',
array(
'page_title' => $page_title,
@ -451,121 +442,12 @@ class IDF_Views_Source
*/
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]) {
return $mime;
}
return self::getMimeTypeFromContent($file_info->file,
$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);
return IDF_FileUtil::getMimeTypeFromContent($file_info->file,
$scm->getFile($file_info));
}
/**

View File

@ -33,13 +33,13 @@ Pluf::loadFunction('Pluf_Shortcuts_RenderToResponse');
class IDF_Views_User
{
/**
* Dashboard of a user.
* Dashboard of a user.
*
* Shows all the open issues assigned to the user.
*
* TODO: This views is a SQL horror. What needs to be done to cut
* by many the number of SQL queries:
* - Add a table to cache the open/closed status ids for all the
* - Add a table to cache the open/closed status ids for all the
* projects.
* - Left join the issues with the project to get the shortname.
*
@ -110,7 +110,10 @@ class IDF_Views_User
$ext_pass = substr(sha1($request->user->password.Pluf::f('secret_key')), 0, 8);
$params = array('user' => $request->user);
if ($request->method == 'POST') {
$form = new IDF_Form_UserAccount($request->POST, $params);
$form = new IDF_Form_UserAccount(array_merge(
(array)$request->POST,
(array)$request->FILES
), $params);
if ($form->isValid()) {
$user = $form->save();
$url = Pluf_HTTP_URL_urlForView('IDF_Views_User::myAccount');
@ -121,10 +124,11 @@ class IDF_Views_User
} else {
$data = $request->user->getData();
unset($data['password']);
$form = new IDF_Form_UserAccount($data, $params);
$form = new IDF_Form_UserAccount(null, $params);
}
$keys = $request->user->get_idf_key_list();
return Pluf_Shortcuts_RenderToResponse('idf/user/myaccount.html',
return Pluf_Shortcuts_RenderToResponse('idf/user/myaccount.html',
array('page_title' => __('Your Account'),
'api_key' => $api_key,
'ext_pass' => $ext_pass,
@ -170,11 +174,11 @@ class IDF_Views_User
} else {
$form = new IDF_Form_UserChangeEmail();
}
return Pluf_Shortcuts_RenderToResponse('idf/user/changeemail.html',
return Pluf_Shortcuts_RenderToResponse('idf/user/changeemail.html',
array('page_title' => __('Confirm The Email Change'),
'form' => $form),
$request);
}
/**
@ -208,13 +212,17 @@ class IDF_Views_User
public function view($request, $match)
{
$sql = new Pluf_SQL('login=%s', array($match[1]));
$users = Pluf::factory('Pluf_User')->getList(array('filter'=>$sql->gen()));
$users = Pluf::factory('Pluf_User')->getList(array('filter'=>$sql->gen()));
if (count($users) != 1 or !$users[0]->active) {
throw new Pluf_HTTP_Error404();
}
return Pluf_Shortcuts_RenderToResponse('idf/user/public.html',
array('page_title' => (string) $users[0],
'member' => $users[0],
$user = $users[0];
$user_data = IDF_UserData::factory($user);
return Pluf_Shortcuts_RenderToResponse('idf/user/public.html',
array('page_title' => (string) $user,
'member' => $user,
'user_data' => $user_data,
),
$request);
}
@ -230,11 +238,11 @@ class IDF_Views_User
function IDF_Views_IssueSummaryAndLabels($field, $issue, $extra='')
{
$project = $issue->get_project();
$edit = Pluf_HTTP_URL_urlForView('IDF_Views_Issue::view',
$edit = Pluf_HTTP_URL_urlForView('IDF_Views_Issue::view',
array($project->shortname, $issue->id));
$tags = array();
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($project->shortname, $tag->id, 'open'));
$tags[] = sprintf('<a class="label" href="%s">%s</a>', $url, Pluf_esc((string) $tag));
}

View File

@ -38,9 +38,9 @@ class IDF_WikiRevision extends Pluf_Model
'id' =>
array(
'type' => 'Pluf_DB_Field_Sequence',
'blank' => true,
'blank' => true,
),
'wikipage' =>
'wikipage' =>
array(
'type' => 'Pluf_DB_Field_Foreignkey',
'model' => 'IDF_WikiPage',
@ -55,7 +55,7 @@ class IDF_WikiRevision extends Pluf_Model
'default' => false,
'help_text' => 'If this revision is the latest, we mark it as being the head revision.',
'index' => true,
),
'summary' =>
array(
@ -71,7 +71,7 @@ class IDF_WikiRevision extends Pluf_Model
'blank' => false,
'verbose' => __('content'),
),
'submitter' =>
'submitter' =>
array(
'type' => 'Pluf_DB_Field_Foreignkey',
'model' => 'Pluf_User',
@ -92,7 +92,7 @@ class IDF_WikiRevision extends Pluf_Model
'verbose' => __('creation date'),
),
);
$this->_a['idx'] = array(
$this->_a['idx'] = array(
'creation_dtime_idx' =>
array(
'col' => 'creation_dtime',
@ -138,7 +138,7 @@ class IDF_WikiRevision extends Pluf_Model
$sql = new Pluf_SQL('wikipage=%s', array($this->wikipage));
$rev = Pluf::factory('IDF_WikiRevision')->getList(array('filter'=>$sql->gen()));
if ($rev->count() > 1) {
IDF_Timeline::insert($this, $this->get_wikipage()->get_project(),
IDF_Timeline::insert($this, $this->get_wikipage()->get_project(),
$this->get_submitter());
foreach ($rev as $r) {
if ($r->id != $this->id and $r->is_head) {
@ -156,7 +156,7 @@ class IDF_WikiRevision extends Pluf_Model
public function timelineFragment($request)
{
$page = $this->get_wikipage();
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Wiki::view',
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Wiki::view',
array($request->project->shortname,
$page->title));
$out = "\n".'<tr class="log"><td><a href="'.$url.'">'.
@ -186,7 +186,7 @@ class IDF_WikiRevision extends Pluf_Model
}
$out .= '</td></tr>';
$out .= "\n".'<tr class="extra"><td colspan="2">
<div class="helptext right">'.sprintf(__('Change of <a href="%s">%s</a>, by %s'), $url, Pluf_esc($page->title), $user).'</div></td></tr>';
<div class="helptext right">'.sprintf(__('Change of <a href="%s">%s</a>, by %s'), $url, Pluf_esc($page->title), $user).'</div></td></tr>';
return Pluf_Template::markSafe($out);
}
@ -195,13 +195,13 @@ class IDF_WikiRevision extends Pluf_Model
$page = $this->get_wikipage();
if (!$this->is_head) {
$url = Pluf::f('url_base')
.Pluf_HTTP_URL_urlForView('IDF_Views_Wiki::view',
.Pluf_HTTP_URL_urlForView('IDF_Views_Wiki::view',
array($request->project->shortname,
$page->title),
array('rev' => $this->id));
} else {
$url = Pluf::f('url_base')
.Pluf_HTTP_URL_urlForView('IDF_Views_Wiki::view',
.Pluf_HTTP_URL_urlForView('IDF_Views_Wiki::view',
array($request->project->shortname,
$page->title));
}
@ -248,7 +248,7 @@ class IDF_WikiRevision extends Pluf_Model
}
$current_locale = Pluf_Translation::getLocale();
$langs = Pluf::f('languages', array('en'));
Pluf_Translation::loadSetLocale($langs[0]);
Pluf_Translation::loadSetLocale($langs[0]);
$context = new Pluf_Template_Context(
array(
'page' => $this->get_wikipage(),
@ -260,23 +260,28 @@ class IDF_WikiRevision extends Pluf_Model
if ($create) {
$template = 'idf/wiki/wiki-created-email.txt';
$title = sprintf(__('New Documentation Page %s - %s (%s)'),
$this->get_wikipage()->title,
$this->get_wikipage()->summary,
$this->get_wikipage()->title,
$this->get_wikipage()->summary,
$this->get_wikipage()->get_project()->shortname);
} else {
$template = 'idf/wiki/wiki-updated-email.txt';
$title = sprintf(__('Documentation Page Changed %s - %s (%s)'),
$this->get_wikipage()->title,
$this->get_wikipage()->summary,
$this->get_wikipage()->title,
$this->get_wikipage()->summary,
$this->get_wikipage()->get_project()->shortname);
}
$tmpl = new Pluf_Template($template);
$text_email = $tmpl->render($context);
$email = new Pluf_Mail(Pluf::f('from_email'),
$conf->getVal('wiki_notification_email'),
$title);
$email->addTextMessage($text_email);
$email->sendMail();
$addresses = explode(',', $conf->getVal('wiki_notification_email'));
foreach ($addresses as $address) {
$email = new Pluf_Mail(Pluf::f('from_email'),
$address,
$title);
$email->addTextMessage($text_email);
$email->sendMail();
}
Pluf_Translation::loadSetLocale($current_locale);
}
}

View File

@ -2193,13 +2193,13 @@ msgid ""
"If you are changing the email address of the user, you\n"
"need to ensure that you are providing a valid email\n"
"address"
msgstr "Si vous changez l'adresse email d'un utilisateur, vousdevez vous assurez que l'adresse est bien valide."
msgstr "Si vous changez l'adresse email d'un utilisateur, vous devez vous assurez que l'adresse est bien valide."
#: IDF/gettexttemplates/idf/gadmin/users/update.html.php:6
msgid ""
"If you give the user staff rights, the user will be\n"
"able to create new projects and update other non staff users.\n"
msgstr "Si vous ajoutez un utilisateur au staff, l'utilisateur va avoirla possibilité de créer de nouveaux projets et d'éditer lesinformations des autres utilisateurs."
msgstr "Si vous ajoutez un utilisateur au staff, l'utilisateur va avoir la possibilité de créer de nouveaux projets et d'éditer les informations des autres utilisateurs."
#: IDF/gettexttemplates/idf/gadmin/users/update.html.php:9
msgid "The form contains some errors. Please correct them to update the user."
@ -2321,7 +2321,7 @@ msgid ""
"<strong>Attention!</strong> Deleting a project is a one second operation\n"
"with the consequences that <strong>all the data</strong> related to the \n"
"project <strong>will be deleted</strong>.\n"
msgstr "<strong>Attention !</strong> Supprimer un projet est une opération rapide pour conséquence<strong>la suppression de toutes les données relatives au projet</strong>."
msgstr "<strong>Attention !</strong> Supprimer un projet est une opération rapide qui a pour conséquence <strong>la suppression de toutes les données relatives au projet</strong>."
#: IDF/gettexttemplates/idf/gadmin/projects/delete.html.php:10
msgid "The form contains some errors. Please correct them to delete the project."

File diff suppressed because it is too large Load Diff

View File

@ -43,6 +43,8 @@ $m['IDF_Conf'] = array('relate_to' => array('IDF_Project'));
$m['IDF_Commit'] = array('relate_to' => array('IDF_Project', 'Pluf_User'));
$m['IDF_Scm_Cache_Git'] = array('relate_to' => array('IDF_Project'));
$m['IDF_UserData'] = array('relate_to' => array('Pluf_User'));
Pluf_Signal::connect('Pluf_Template_Compiler::construct_template_tags_modifiers',
array('IDF_Middleware', 'updateTemplateTagsModifiers'));

View File

@ -57,7 +57,7 @@
<td colspan="2" class="helptext">
{blocktrans}
Only project members and admins have write access to the source.<br />
If you restrict the access to the source, anonymous access is<br />
If you restrict the access to the source, anonymous access is<br />
not provided and the users must authenticate themselves with their<br />
password or SSH key.{/blocktrans}
</td></tr>
@ -86,7 +86,7 @@ password or SSH key.{/blocktrans}
<tr>
<td>&nbsp;</td>
<td colspan="2">
<input type="submit" value="{trans 'Save Changes'}" name="submit" />
<input type="submit" value="{trans 'Save Changes'}" name="submit" />
</td>
</tr>
</table>
@ -96,7 +96,7 @@ password or SSH key.{/blocktrans}
<div class="issue-submit-info">
<p><strong>{trans 'Instructions:'}</strong></p>
<p>{blocktrans}You can configure here the project tabs access rights and notification emails.{/blocktrans}</p>
<p>{blocktrans}Notification emails will be sent from the <strong>{$from_email}</strong> address, if you send the email to a mailing list, you may need to register this email address. If you do not want to send emails for a given type of changes, simply leave the corresponding field empty.{/blocktrans}</p>
<p>{blocktrans}Notification emails will be sent from the <strong>{$from_email}</strong> address, if you send the email to a mailing list, you may need to register this email address. Multiple email addresses must be separated through commas (','). If you do not want to send emails for a given type of changes, simply leave the corresponding field empty.{/blocktrans}</p>
<p>{blocktrans}If you mark a project as private, only the project members and administrators, together with the extra authorized users you provide will have access to the project. You will still be able to define further access rights for the different tabs but the "Open to all" and "Signed in users" will default to authorized users only.{/blocktrans}</p>
<p>{blocktrans}Specify each person by its login. Each person must have already registered with the given login. Separate the logins with commas and/or new lines.{/blocktrans}</p>
</div>
@ -111,7 +111,7 @@ $(document).ready(function(){
$("#id_private_project").click(function(){
if ($("#id_private_project").is(":checked")) {
$("#authorized-users-row").show();
} else {
} else {
$("#authorized-users-row").hide();
}
});

View File

@ -9,7 +9,7 @@
{/if}
</div>
{/if}
<form method="post" action=".">
<form method="post" enctype="multipart/form-data" action=".">
<table class="form" summary="">
<tr>
<th>{trans 'Login:'}</th>{aurl 'url', 'IDF_Views_User::view', array($cuser.login)}
@ -51,7 +51,48 @@
<td>{if $form.f.password2.errors}{$form.f.password2.fieldErrors}{/if}
{$form.f.password2|unsafe}
</td>
</tr>{if $user.administrator}
</tr>
<tr><td colspan="2" class="separator">{trans "Public Profile"}</td></tr>
<tr>
<th>{$form.f.description.labelTag}:</th>
<td>{if $form.f.description.errors}{$form.f.description.fieldErrors}{/if}
{$form.f.description|unsafe}
</td>
</tr>
<tr>
<th>{$form.f.twitter.labelTag}:</th>
<td>{if $form.f.twitter.errors}{$form.f.twitter.fieldErrors}{/if}
{$form.f.twitter|unsafe}
</td>
</tr>
<tr>
<th>{$form.f.public_email.labelTag}:</th>
<td>{if $form.f.public_email.errors}{$form.f.public_email.fieldErrors}{/if}
{$form.f.public_email|unsafe}
</td>
</tr>
<tr>
<th>{$form.f.website.labelTag}:</th>
<td>{if $form.f.website.errors}{$form.f.website.fieldErrors}{/if}
{$form.f.website|unsafe}
</td>
</tr>
<tr>
<th>{$form.f.custom_avatar.labelTag}:</th>
<td>{if $form.f.custom_avatar.errors}{$form.f.custom_avatar.fieldErrors}{/if}
{$form.f.custom_avatar|unsafe}<br />
<span class="helptext">{$form.f.custom_avatar.help_text}</span>
</td>
</tr>
<tr>
<th>{if $form.f.remove_custom_avatar.errors}{$form.f.remove_custom_avatar.fieldErrors}{/if}
{$form.f.remove_custom_avatar|unsafe}
</th>
<td>{$form.f.remove_custom_avatar.labelTag}<br />
<span class="helptext">{$form.f.remove_custom_avatar.help_text}</span></td>
</tr>
{if $user.administrator}
<tr><td colspan="2" class="separator">{trans "Administrative"}</td></tr>
<tr>
<th>{if $form.f.staff.errors}{$form.f.staff.fieldErrors}{/if}
{$form.f.staff|unsafe}
@ -69,7 +110,7 @@
<tr>
<td>&nbsp;</td>
<td>
<input type="submit" value="{trans 'Update User'}" name="submit" />
<input type="submit" value="{trans 'Update User'}" name="submit" />
| <a href="{url 'IDF_Views_Admin::users'}">{trans 'Cancel'}</a>
</td>
</tr>

View File

@ -1,10 +1,17 @@
{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 body}
{assign $i = 0}
{assign $nc = $comments.count()}
{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&amp;d={media}/idf/img/spacer.gif" alt=" " />
{assign $i = 0}
{assign $nc = $comments.count()}
{foreach $comments as $c}{ashowuser 'submitter', $c.get_submitter(), $request}
{assign $submitter = $c.get_submitter()}
{assign $submitter_data = $c.get_submitter_data()}
<div class="issue-comment{if $i == 0} issue-comment-first{/if}{if $i == ($nc-1)} issue-comment-last{/if}" id="ic{$c.id}">
{if $submitter_data.avatar != ''}
<img style="float:right; position: relative; max-height: 60px; max-width: 60px;" src="{media}/upload/avatars/{$submitter_data.avatar}" alt=" " />
{else}
<img style="float:right; position: relative; max-height: 60px; max-width: 60px;" src="http://www.gravatar.com/avatar/{$submitter.email|md5}.jpg?s=60&amp;d={media}/idf/img/spacer.gif" alt=" " />
{/if}
{if $i == 0}
<p>{blocktrans}Reported by {$submitter}, {$c.creation_dtime|date}{/blocktrans}</p>
{else}
@ -20,14 +27,13 @@
{if $attachments.count() > 0}
<hr align="left" class="attach" />
<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}
</ul>{/if}
{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}
{if $i> 0 and $c.changedIssue()}
<div class="issue-changes">
<div class="issue-changes">
{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 />
{/foreach}
</div>
</div>
{/if}
</div>{assign $i = $i + 1}{if $i == $nc and false == $form}
<div class="issue-comment-signin">
@ -119,7 +125,7 @@
<td>&nbsp;</td>
<td>
<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>
</td>
</tr>

View File

@ -3,7 +3,7 @@
{block tabhome} class="active"{/block}
{block subtabs}
<div id="sub-tabs">
{trans 'Welcome'} | <strong><a href="{url 'IDF_Views_Project::timeline', array($project.shortname, 'all')}">{trans 'Latest Updates'}</a></strong>{superblock}
<a href="{url 'IDF_Views_Project::home', array($project.shortname)}" class="active">{trans 'Welcome'}</a> | <strong><a href="{url 'IDF_Views_Project::timeline', array($project.shortname, 'all')}">{trans 'Latest Updates'}</a></strong>{superblock}
</div>
{/block}
{block body}

View File

@ -79,9 +79,9 @@ to propose more contributions</strong>.
</tbody>
</table>
{assign $fcomments = $def[2]}
{assign $nc = $fcomments.count()}
{assign $nc = $fcomments.count()}
{assign $i = 1}
{foreach $fcomments as $c}
{foreach $fcomments as $c}
<div class="issue-comment{if $i == 1} issue-comment-first{/if}{if $i == $nc} issue-comment-last{/if}" id="ic{$c.id}">{assign $who = $c.get_comment().get_submitter()}{aurl 'whourl', 'IDF_Views_User::view', array($who.login)}
{aurl 'url', 'IDF_Views_Review::view', array($project.shortname, $review.id)}
{assign $id = $c.id}
@ -101,13 +101,18 @@ to propose more contributions</strong>.
</tr></table>{/if}
{/foreach}
{assign $i = 1}
{assign $nc = $comments.count()}
{assign $i = 1}
{assign $nc = $comments.count()}
{if $nc}<hr align="left" class="attach" />
<h2>{trans 'General Comments'}</h2>
{/if}
{foreach $comments as $c}{ashowuser 'submitter', $c.get_submitter(), $request}{assign $who = $c.get_submitter()}
<div class="issue-comment{if $i == 1} issue-comment-first{/if}{if $i == ($nc)} 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&amp;d={media}/idf/img/spacer.gif" alt=" " />
{foreach $comments as $c}{ashowuser 'submitter', $c.get_submitter(), $request}{assign $submitter = $c.get_submitter()}{assign $submitter_data = $c.get_submitter_data()}
<div class="issue-comment{if $i == 1} issue-comment-first{/if}{if $i == ($nc)} issue-comment-last{/if}" id="ic{$c.id}">
{if $submitter_data.avatar != ''}
<img style="float:right; position: relative; max-height: 60px; max-width: 60px;" src="{media}/upload/avatars/{$submitter_data.avatar}" alt=" " />
{else}
<img style="float:right; position: relative;" src="http://www.gravatar.com/avatar/{$submitter.email|md5}.jpg?s=60&amp;d={media}/idf/img/spacer.gif" alt=" " />
{/if}
{aurl 'url', 'IDF_Views_Review::view', array($project.shortname, $review.id)}
{assign $id = $c.id}
{assign $url = $url~'#ic'~$c.id}
@ -118,11 +123,11 @@ to propose more contributions</strong>.
{if strlen($c.content) > 0}<pre class="issue-comment-text">{issuetext $c.content, $request}</pre>{/if}
{if $c.changedReview()}
<div class="issue-changes">
<div class="issue-changes">
{foreach $c.changes as $w => $v}
<strong>{if $w == 'su'}{trans 'Summary:'}{/if}{if $w == 'st'}{trans 'Status:'}{/if}</strong> {$v}<br />
{/foreach}
</div>
</div>
{/if}
</div>{assign $i = $i + 1}{if $i == $nc+1 and $user.isAnonymous()}
<div class="issue-comment-signin">

View File

@ -18,20 +18,45 @@
<tr>
<th><strong>{trans 'Message:'}</strong></th><td>{issuetext $cobject.title, $request}{if isset($cobject.full_message)}<br/><br/>{issuetext $cobject.full_message, $request, true, false, true, true, true}{/if}</td>
</tr>
{if count($diff.files)}
<tr>
<th><strong>{trans 'Files:'}</strong></th>
<th><strong>{trans 'Changes:'}</strong></th>
<td>
{foreach $diff.files as $filename=>$diffdef}
{assign $ndiff = count($diffdef['chunks'])}
<a href="{url 'IDF_Views_Source::tree', array($project.shortname, $commit, $filename)}">{$filename}</a> (<a href="#diff-{$filename|md5}">{blocktrans $ndiff}{$ndiff} diff{plural}{$ndiff} diffs{/blocktrans}</a>)<br/>
<table class="changes">
{foreach $changes.deletions as $filename}
<tr><td>D</td><td>{$filename}{if !empty($diff.files[$filename])} (<a href="#diff-{$filename|md5}">{trans 'full'}</a>){/if}</td></tr>
{/foreach}
{foreach $changes.renames as $oldname => $newname}
<tr><td>R</td><td><a href="{url 'IDF_Views_Source::tree', array($project.shortname, $commit, $newname)}">{$oldname} -> {$newname}</a></td></tr>
{/foreach}
{foreach $changes.additions as $filename}
<tr><td>A</td><td><a href="{url 'IDF_Views_Source::tree', array($project.shortname, $commit, $filename)}">{$filename}</a>{if !empty($diff.files[$filename])} (<a href="#diff-{$filename|md5}">{trans 'full'}</a>){/if}</td></tr>
{/foreach}
{foreach $changes.patches as $filename}
{assign $ndiff = count($diff.files[$filename]['chunks'])}
<tr><td>M</td><td><a href="{url 'IDF_Views_Source::tree', array($project.shortname, $commit, $filename)}">{$filename}</a>{if !empty($diff.files[$filename])} (<a href="#diff-{$filename|md5}">{blocktrans $ndiff}{$ndiff} diff{plural}{$ndiff} diffs{/blocktrans}</a>){/if}</td></tr>
{/foreach}
{foreach $changes.properties as $filename => $properties}
<tr><td>P</td><td><a href="{url 'IDF_Views_Source::tree', array($project.shortname, $commit, $filename)}">{$filename}</a>
<table class="properties">
{foreach $properties as $key => $value}
<tr><td>{$key}</td>
{if $value == null}
<td class="removed">{trans 'removed'}</td>
{else}
<td>{$value}</td>
{/if}
</tr>
{/foreach}
</table>
</td></tr>
{/foreach}
</table>
</td>
</tr>
{/if}
</table>
{if count($diff.files)}
<h2>{trans 'Change Details'}</h2>
<h2>{trans 'File differences'}</h2>
{$diff.as_html()}
{/if}{if count($diff.files) or $large_commit}

View File

@ -9,7 +9,7 @@
</div>
{/if}
<form method="post" action=".">
<form method="post" enctype="multipart/form-data" action=".">
<table class="form" summary="">
<tr>
<th>{trans 'Login:'}</th>{aurl 'url', 'IDF_Views_User::view', array($user.login)}
@ -53,6 +53,46 @@
{$form.f.password2|unsafe}
</td>
</tr>
<tr><td colspan="2" class="separator">{trans "Public Profile"}</td></tr>
<tr>
<th>{$form.f.description.labelTag}:</th>
<td>{if $form.f.description.errors}{$form.f.description.fieldErrors}{/if}
{$form.f.description|unsafe}
</td>
</tr>
<tr>
<th>{$form.f.twitter.labelTag}:</th>
<td>{if $form.f.twitter.errors}{$form.f.twitter.fieldErrors}{/if}
{$form.f.twitter|unsafe}
</td>
</tr>
<tr>
<th>{$form.f.public_email.labelTag}:</th>
<td>{if $form.f.public_email.errors}{$form.f.public_email.fieldErrors}{/if}
{$form.f.public_email|unsafe}
</td>
</tr>
<tr>
<th>{$form.f.website.labelTag}:</th>
<td>{if $form.f.website.errors}{$form.f.website.fieldErrors}{/if}
{$form.f.website|unsafe}
</td>
</tr>
<tr>
<th>{$form.f.custom_avatar.labelTag}:</th>
<td>{if $form.f.custom_avatar.errors}{$form.f.custom_avatar.fieldErrors}{/if}
{$form.f.custom_avatar|unsafe}<br />
<span class="helptext">{$form.f.custom_avatar.help_text}</span>
</td>
</tr>
<tr>
<th>{if $form.f.remove_custom_avatar.errors}{$form.f.remove_custom_avatar.fieldErrors}{/if}
{$form.f.remove_custom_avatar|unsafe}
</th>
<td>{$form.f.remove_custom_avatar.labelTag}<br />
<span class="helptext">{$form.f.remove_custom_avatar.help_text}</span></td>
</tr>
<tr><td colspan="2" class="separator">{trans "Key Management"}</td></tr>
<tr>
<th>{$form.f.public_key.labelTag}:</th>
<td>{if $form.f.public_key.errors}{$form.f.public_key.fieldErrors}{/if}

View File

@ -2,9 +2,39 @@
{block body}
<table class="form" summary="">
<tr>
<th></th>
<th style="text-align: right">{if $user_data.avatar != ''}
<img style="max-height: 60px; max-width: 60px;" src="{media}/upload/avatars/{$user_data.avatar}" alt=" " />
{else}
<img src="http://www.gravatar.com/avatar/{$member.email|md5}.jpg?s=60&amp;d={media}/idf/img/spacer.gif" alt=" " />
{/if}
</th>
<td>{$member}</td>
</tr>
{if $user_data.description != ''}
<tr>
<th>{trans 'Description:'}</th>
<td>{$user_data.description}</td>
</tr>
{/if}
{if $user_data.twitter != ''}
<tr>
<th>{trans 'Twitter:'}</th>
<td><a rel="nofollow" target="_blank" href='http://twitter.com/{$user_data.twitter}'>{$user_data.twitter}</a></td>
</tr>
{/if}
{if $user_data.public_email != ''}
<tr>
<th>{trans 'Public Email:'}</th>
<td><a href='mailto:{$user_data.public_email}'>{$user_data.public_email}</a></td>
</tr>
{/if}
{if $user_data.website != ''}
<tr>
<th>{trans 'Website:'}</th>
<td><a rel="nofollow" target="_blank" href='{$user_data.website}'>{$user_data.website}</a></td>
</tr>
{/if}
<tr>
<th>{trans 'Last time seen:'}</th>
<td>{$member.last_login|dateago}</td>

View File

@ -104,6 +104,11 @@ table.form th {
font-weight: normal;
}
table.form td.separator {
font-weight: bold;
text-align: center;
}
.px-message-error {
padding-left: 37px;
background: url("../img/dialog-error.png");
@ -499,6 +504,21 @@ table.commit th {
table.commit td, table.commit th {
padding: 3px;
}
table.commit table.changes td {
padding: 2px;
}
table.commit table.changes table.properties {
margin: 0;
}
table.commit table.changes table.properties tr:nth-child(even) {
background: #E4E8E0;
}
table.commit table.changes table.properties td {
white-space: pre-wrap;
}
table.commit table.changes table.properties td.removed {
font-style: italic;
}
/**
* syntax highlighting of diffs