Initial commit
This commit is contained in:
47
indefero/src/IDF/Form/Admin/ForgeConf.php
Normal file
47
indefero/src/IDF/Form/Admin/ForgeConf.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-2011 Céondo Ltd and contributors.
|
||||
#
|
||||
# InDefero is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
#(at your option) any later version.
|
||||
#
|
||||
# InDefero is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# ***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
/**
|
||||
* Configuration of the forge's start page.
|
||||
*/
|
||||
class IDF_Form_Admin_ForgeConf extends Pluf_Form
|
||||
{
|
||||
public function initFields($extra=array())
|
||||
{
|
||||
$this->fields['enabled'] = new Pluf_Form_Field_Boolean(
|
||||
array('required' => false,
|
||||
'label' => __('Custom forge page enabled'),
|
||||
'widget' => 'Pluf_Form_Widget_CheckboxInput',
|
||||
));
|
||||
$this->fields['content'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Content'),
|
||||
'widget' => 'Pluf_Form_Widget_TextareaInput',
|
||||
'widget_attrs' => array(
|
||||
'cols' => 68,
|
||||
'rows' => 26,
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
62
indefero/src/IDF/Form/Admin/LabelConf.php
Normal file
62
indefero/src/IDF/Form/Admin/LabelConf.php
Normal file
@@ -0,0 +1,62 @@
|
||||
<?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-2011 Céondo Ltd and contributors.
|
||||
#
|
||||
# InDefero is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
#(at your option) any later version.
|
||||
#
|
||||
# InDefero is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# ***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
/**
|
||||
* Configuration of forge labels.
|
||||
*/
|
||||
class IDF_Form_Admin_LabelConf extends Pluf_Form
|
||||
{
|
||||
const init_project_labels = 'UI:GUI = Applications with graphical user interfaces
|
||||
UI:CLI = Applications with no graphical user interfaces
|
||||
License:BSD = Applications with BSD license
|
||||
License:GPL = Applications with GPL license
|
||||
';
|
||||
|
||||
public function initFields($extra=array())
|
||||
{
|
||||
$this->fields['project_labels'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Predefined project labels'),
|
||||
'initial' => self::init_project_labels,
|
||||
'widget_attrs' => array('rows' => 13,
|
||||
'cols' => 75),
|
||||
'widget' => 'Pluf_Form_Widget_TextareaInput',
|
||||
));
|
||||
}
|
||||
|
||||
public function clean_project_labels()
|
||||
{
|
||||
$labels = preg_split("/\s*\n\s*/", $this->cleaned_data['project_labels'], -1, PREG_SPLIT_NO_EMPTY);
|
||||
for ($i=0; $i<count($labels); ++$i) {
|
||||
$labels[$i] = trim($labels[$i]);
|
||||
if (!preg_match('/^[\w-]+(:[\w-]+)?(\s*=\s*[^=]+)?$/', $labels[$i])) {
|
||||
throw new Pluf_Form_Invalid(sprintf(
|
||||
__('The label "%s" is invalid: A label must only consist of alphanumeric '.
|
||||
'characters and dashes, and can optionally contain a ":" with a group prefix.'),
|
||||
$labels[$i]));
|
||||
}
|
||||
}
|
||||
return implode("\n", $labels);
|
||||
}
|
||||
}
|
422
indefero/src/IDF/Form/Admin/ProjectCreate.php
Normal file
422
indefero/src/IDF/Form/Admin/ProjectCreate.php
Normal file
@@ -0,0 +1,422 @@
|
||||
<?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-2011 Céondo Ltd and contributors.
|
||||
#
|
||||
# InDefero is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# InDefero is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# ***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
/**
|
||||
* Create a project.
|
||||
*
|
||||
* A kind of merge of the member configuration, overview and the
|
||||
* former source tab.
|
||||
*
|
||||
*/
|
||||
class IDF_Form_Admin_ProjectCreate extends Pluf_Form
|
||||
{
|
||||
public function initFields($extra=array())
|
||||
{
|
||||
$choices = array();
|
||||
$options = array(
|
||||
'git' => __('git'),
|
||||
'svn' => __('Subversion'),
|
||||
'mercurial' => __('mercurial'),
|
||||
'mtn' => __('monotone'),
|
||||
);
|
||||
foreach (Pluf::f('allowed_scm', array()) as $key => $class) {
|
||||
$choices[$options[$key]] = $key;
|
||||
}
|
||||
|
||||
$this->fields['name'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Name'),
|
||||
'initial' => '',
|
||||
));
|
||||
|
||||
$this->fields['private_project'] = new Pluf_Form_Field_Boolean(
|
||||
array('required' => false,
|
||||
'label' => __('Private project'),
|
||||
'initial' => false,
|
||||
'widget' => 'Pluf_Form_Widget_CheckboxInput',
|
||||
));
|
||||
|
||||
$this->fields['shortname'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Shortname'),
|
||||
'initial' => '',
|
||||
'help_text' => __('It must be unique for each project and composed only of letters, digits and dash (-) like "my-project".'),
|
||||
));
|
||||
|
||||
$this->fields['shortdesc'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Short description'),
|
||||
'help_text' => __('A one line description of the project.'),
|
||||
'initial' => '',
|
||||
'widget_attrs' => array('size' => '35'),
|
||||
));
|
||||
|
||||
$this->fields['external_project_url'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
'label' => __('External URL'),
|
||||
'widget_attrs' => array('size' => '35'),
|
||||
'initial' => '',
|
||||
));
|
||||
|
||||
$this->fields['scm'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Repository type'),
|
||||
'initial' => 'git',
|
||||
'widget_attrs' => array('choices' => $choices),
|
||||
'widget' => 'Pluf_Form_Widget_SelectInput',
|
||||
));
|
||||
|
||||
$this->fields['svn_remote_url'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
'label' => __('Remote Subversion repository'),
|
||||
'initial' => '',
|
||||
'widget_attrs' => array('size' => '30'),
|
||||
));
|
||||
|
||||
$this->fields['svn_username'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
'label' => __('Repository username'),
|
||||
'initial' => '',
|
||||
'widget_attrs' => array('size' => '15'),
|
||||
));
|
||||
|
||||
$this->fields['svn_password'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
'label' => __('Repository password'),
|
||||
'initial' => '',
|
||||
'widget' => 'Pluf_Form_Widget_PasswordInput',
|
||||
));
|
||||
|
||||
$this->fields['mtn_master_branch'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
'label' => __('Master branch'),
|
||||
'initial' => '',
|
||||
'widget_attrs' => array('size' => '35'),
|
||||
'help_text' => __('This should be a world-wide unique identifier for your project. A reverse DNS notation like "com.my-domain.my-project" is a good idea.'),
|
||||
));
|
||||
|
||||
$this->fields['owners'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
'label' => __('Project owners'),
|
||||
'initial' => $extra['user']->login,
|
||||
'widget' => 'Pluf_Form_Widget_TextareaInput',
|
||||
'widget_attrs' => array('rows' => 5,
|
||||
'cols' => 40),
|
||||
));
|
||||
|
||||
$this->fields['members'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
'label' => __('Project members'),
|
||||
'initial' => '',
|
||||
'widget_attrs' => array('rows' => 7,
|
||||
'cols' => 40),
|
||||
'widget' => 'Pluf_Form_Widget_TextareaInput',
|
||||
));
|
||||
|
||||
for ($i=1;$i<7;$i++) {
|
||||
$this->fields['label'.$i] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
'label' => __('Labels'),
|
||||
'initial' => '',
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 50,
|
||||
'size' => 20,
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
$projects = array('--' => '--');
|
||||
foreach (Pluf::factory('IDF_Project')->getList(array('order' => 'name ASC')) as $proj) {
|
||||
$projects[$proj->name] = $proj->shortname;
|
||||
}
|
||||
$this->fields['template'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
'label' => __('Project template'),
|
||||
'initial' => '--',
|
||||
'help_text' => __('Use the given project to initialize the new project. Access rights and general configuration will be taken from the template project.'),
|
||||
'widget' => 'Pluf_Form_Widget_SelectInput',
|
||||
'widget_attrs' => array('choices' => $projects),
|
||||
));
|
||||
|
||||
/**
|
||||
* [signal]
|
||||
*
|
||||
* IDF_Form_Admin_ProjectCreate::initFields
|
||||
*
|
||||
* [sender]
|
||||
*
|
||||
* IDF_Form_Admin_ProjectCreate
|
||||
*
|
||||
* [description]
|
||||
*
|
||||
* This signal allows an application to modify the form
|
||||
* for the creation of a project.
|
||||
*
|
||||
* [parameters]
|
||||
*
|
||||
* array('form' => $form)
|
||||
*
|
||||
*/
|
||||
$params = array('form' => $this);
|
||||
Pluf_Signal::send('IDF_Form_Admin_ProjectCreate::initFields',
|
||||
'IDF_Form_Admin_ProjectCreate', $params);
|
||||
}
|
||||
|
||||
public function clean_owners()
|
||||
{
|
||||
return IDF_Form_MembersConf::checkBadLogins($this->cleaned_data['owners']);
|
||||
}
|
||||
|
||||
public function clean_members()
|
||||
{
|
||||
return IDF_Form_MembersConf::checkBadLogins($this->cleaned_data['members']);
|
||||
}
|
||||
|
||||
public function clean_svn_remote_url()
|
||||
{
|
||||
$this->cleaned_data['svn_remote_url'] = (!empty($this->cleaned_data['svn_remote_url'])) ? $this->cleaned_data['svn_remote_url'] : '';
|
||||
$url = trim($this->cleaned_data['svn_remote_url']);
|
||||
if (strlen($url) == 0) return $url;
|
||||
// we accept only starting with http(s):// to avoid people
|
||||
// trying to access the local filesystem.
|
||||
if (!preg_match('#^(http|https)://#', $url)) {
|
||||
throw new Pluf_Form_Invalid(__('Only a remote repository available through HTTP or HTTPS is allowed. For example "http://somewhere.com/svn/trunk".'));
|
||||
}
|
||||
return $url;
|
||||
}
|
||||
|
||||
public function clean_mtn_master_branch()
|
||||
{
|
||||
// do not validate, but empty the field if a different
|
||||
// SCM should be used
|
||||
if ($this->cleaned_data['scm'] != 'mtn')
|
||||
return '';
|
||||
|
||||
$mtn_master_branch = mb_strtolower($this->cleaned_data['mtn_master_branch']);
|
||||
if (!preg_match('/^([\w\d]+([-][\w\d]+)*)(\.[\w\d]+([-][\w\d]+)*)*$/',
|
||||
$mtn_master_branch)) {
|
||||
throw new Pluf_Form_Invalid(__(
|
||||
'The master branch is empty or contains illegal characters, '.
|
||||
'please use only letters, digits, dashes and dots as separators.'
|
||||
));
|
||||
}
|
||||
|
||||
$sql = new Pluf_SQL('vkey=%s AND vdesc=%s',
|
||||
array('mtn_master_branch', $mtn_master_branch));
|
||||
$l = Pluf::factory('IDF_Conf')->getList(array('filter'=>$sql->gen()));
|
||||
if ($l->count() > 0) {
|
||||
throw new Pluf_Form_Invalid(__(
|
||||
'This master branch is already used. Please select another one.'
|
||||
));
|
||||
}
|
||||
|
||||
return $mtn_master_branch;
|
||||
}
|
||||
|
||||
public function clean_shortname()
|
||||
{
|
||||
$shortname = mb_strtolower($this->cleaned_data['shortname']);
|
||||
if (preg_match('/[^\-A-Za-z0-9]/', $shortname)) {
|
||||
throw new Pluf_Form_Invalid(__('This shortname contains illegal characters, please use only letters, digits and dash (-).'));
|
||||
}
|
||||
if (mb_substr($shortname, 0, 1) == '-') {
|
||||
throw new Pluf_Form_Invalid(__('The shortname cannot start with the dash (-) character.'));
|
||||
}
|
||||
if (mb_substr($shortname, -1) == '-') {
|
||||
throw new Pluf_Form_Invalid(__('The shortname cannot end with the dash (-) character.'));
|
||||
}
|
||||
$sql = new Pluf_SQL('shortname=%s', array($shortname));
|
||||
$l = Pluf::factory('IDF_Project')->getList(array('filter'=>$sql->gen()));
|
||||
if ($l->count() > 0) {
|
||||
throw new Pluf_Form_Invalid(__('This shortname is already used. Please select another one.'));
|
||||
}
|
||||
return $shortname;
|
||||
}
|
||||
|
||||
public function clean_external_project_url()
|
||||
{
|
||||
return IDF_Form_ProjectConf::checkWebURL($this->cleaned_data['external_project_url']);
|
||||
}
|
||||
|
||||
public function clean()
|
||||
{
|
||||
if ($this->cleaned_data['scm'] != 'svn') {
|
||||
foreach (array('svn_remote_url', 'svn_username', 'svn_password')
|
||||
as $key) {
|
||||
$this->cleaned_data[$key] = '';
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->cleaned_data['scm'] != 'mtn') {
|
||||
$this->cleaned_data['mtn_master_branch'] = '';
|
||||
}
|
||||
|
||||
/**
|
||||
* [signal]
|
||||
*
|
||||
* IDF_Form_Admin_ProjectCreate::clean
|
||||
*
|
||||
* [sender]
|
||||
*
|
||||
* IDF_Form_Admin_ProjectCreate
|
||||
*
|
||||
* [description]
|
||||
*
|
||||
* This signal allows an application to clean the form
|
||||
* for the creation of a project.
|
||||
*
|
||||
* [parameters]
|
||||
*
|
||||
* array('cleaned_data' => $cleaned_data)
|
||||
*
|
||||
*/
|
||||
$params = array('cleaned_data' => $this->cleaned_data);
|
||||
Pluf_Signal::send('IDF_Form_Admin_ProjectCreate::clean',
|
||||
'IDF_Form_Admin_ProjectCreate', $params);
|
||||
return $this->cleaned_data;
|
||||
}
|
||||
|
||||
public function save($commit=true)
|
||||
{
|
||||
if (!$this->isValid()) {
|
||||
throw new Exception(__('Cannot save the model from an invalid form.'));
|
||||
}
|
||||
|
||||
// Add a tag for each label
|
||||
$tagids = array();
|
||||
for ($i=1;$i<7;$i++) {
|
||||
if (strlen($this->cleaned_data['label'.$i]) > 0) {
|
||||
if (strpos($this->cleaned_data['label'.$i], ':') !== false) {
|
||||
list($class, $name) = explode(':', $this->cleaned_data['label'.$i], 2);
|
||||
list($class, $name) = array(trim($class), trim($name));
|
||||
} else {
|
||||
$class = 'Other';
|
||||
$name = trim($this->cleaned_data['label'.$i]);
|
||||
}
|
||||
$tag = IDF_Tag::addGlobal($name, $class);
|
||||
$tagids[] = $tag->id;
|
||||
}
|
||||
}
|
||||
|
||||
$project = new IDF_Project();
|
||||
$project->name = $this->cleaned_data['name'];
|
||||
$project->shortname = $this->cleaned_data['shortname'];
|
||||
$project->shortdesc = $this->cleaned_data['shortdesc'];
|
||||
|
||||
$tagids = array();
|
||||
if ($this->cleaned_data['template'] != '--') {
|
||||
// Find the template project
|
||||
$sql = new Pluf_SQL('shortname=%s',
|
||||
array($this->cleaned_data['template']));
|
||||
$tmpl = Pluf::factory('IDF_Project')->getOne(array('filter' => $sql->gen()));
|
||||
$project->private = $tmpl->private;
|
||||
$project->description = $tmpl->description;
|
||||
|
||||
foreach ($tmpl->get_tags_list() as $tag) {
|
||||
$tagids[] = $tag->id;
|
||||
}
|
||||
} else {
|
||||
$project->private = $this->cleaned_data['private_project'];
|
||||
$project->description = __('Click on the Project Management tab to set the description of your project.');
|
||||
|
||||
// Add a tag for each label
|
||||
for ($i=1;$i<7;$i++) {
|
||||
if (strlen($this->cleaned_data['label'.$i]) > 0) {
|
||||
if (strpos($this->cleaned_data['label'.$i], ':') !== false) {
|
||||
list($class, $name) = explode(':', $this->cleaned_data['label'.$i], 2);
|
||||
list($class, $name) = array(trim($class), trim($name));
|
||||
} else {
|
||||
$class = 'Other';
|
||||
$name = trim($this->cleaned_data['label'.$i]);
|
||||
}
|
||||
$tag = IDF_Tag::addGlobal($name, $class);
|
||||
$tagids[] = $tag->id;
|
||||
}
|
||||
}
|
||||
}
|
||||
$project->create();
|
||||
$project->batchAssoc('IDF_Tag', $tagids);
|
||||
|
||||
$conf = new IDF_Conf();
|
||||
$conf->setProject($project);
|
||||
|
||||
if ($this->cleaned_data['template'] != '--') {
|
||||
$tmplconf = new IDF_Conf();
|
||||
$tmplconf->setProject($tmpl);
|
||||
|
||||
$allKeys = $tmplconf->getKeys();
|
||||
$scm = $this->cleaned_data['scm'];
|
||||
$ignoreKeys = array('scm', 'external_project_url', 'logo');
|
||||
|
||||
// copy over all existing variables, except scm-related data and
|
||||
// the project url / logo
|
||||
foreach ($allKeys as $key) {
|
||||
if (in_array($key, $ignoreKeys) || strpos($key, $scm.'_') === 0) {
|
||||
continue;
|
||||
}
|
||||
$conf->setVal($key, $tmplconf->getVal($key));
|
||||
}
|
||||
}
|
||||
|
||||
$keys = array(
|
||||
'scm', 'svn_remote_url', 'svn_username',
|
||||
'svn_password', 'mtn_master_branch',
|
||||
'external_project_url'
|
||||
);
|
||||
foreach ($keys as $key) {
|
||||
$this->cleaned_data[$key] = !empty($this->cleaned_data[$key]) ?
|
||||
$this->cleaned_data[$key] : '';
|
||||
$conf->setVal($key, $this->cleaned_data[$key]);
|
||||
}
|
||||
$project->created();
|
||||
|
||||
if ($this->cleaned_data['template'] == '--') {
|
||||
IDF_Form_MembersConf::updateMemberships($project,
|
||||
$this->cleaned_data);
|
||||
} else {
|
||||
// Get the membership of the template $tmpl
|
||||
IDF_Form_MembersConf::updateMemberships($project,
|
||||
$tmpl->getMembershipData('string'));
|
||||
}
|
||||
$project->membershipsUpdated();
|
||||
return $project;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that the template project exists.
|
||||
*/
|
||||
public function clean_template()
|
||||
{
|
||||
if ($this->cleaned_data['template'] == '--') {
|
||||
return $this->cleaned_data['template'];
|
||||
}
|
||||
$sql = new Pluf_SQL('shortname=%s', array($this->cleaned_data['template']));
|
||||
if (Pluf::factory('IDF_Project')->getOne(array('filter' => $sql->gen())) == null) {
|
||||
throw new Pluf_Form_Invalid(__('This project is not available.'));
|
||||
}
|
||||
return $this->cleaned_data['template'];
|
||||
}
|
||||
}
|
||||
|
||||
|
88
indefero/src/IDF/Form/Admin/ProjectDelete.php
Normal file
88
indefero/src/IDF/Form/Admin/ProjectDelete.php
Normal file
@@ -0,0 +1,88 @@
|
||||
<?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-2011 Céondo Ltd and contributors.
|
||||
#
|
||||
# InDefero is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# InDefero is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# ***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
/**
|
||||
* Delete a project.
|
||||
*
|
||||
* It is also removing the SCM files, so handle with care.
|
||||
*
|
||||
*/
|
||||
class IDF_Form_Admin_ProjectDelete extends Pluf_Form
|
||||
{
|
||||
public $project = null;
|
||||
|
||||
public function initFields($extra=array())
|
||||
{
|
||||
$this->project = $extra['project'];
|
||||
$this->user = $extra['user'];
|
||||
$this->fields['code'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Confirmation code'),
|
||||
'initial' => '',
|
||||
));
|
||||
$this->fields['agree'] = new Pluf_Form_Field_Boolean(
|
||||
array('required' => true,
|
||||
'label' => __('I have made a backup of all the important data of this project.'),
|
||||
'initial' => '',
|
||||
));
|
||||
}
|
||||
|
||||
public function clean_code()
|
||||
{
|
||||
$code = $this->cleaned_data['code'];
|
||||
if ($code != $this->getCode()) {
|
||||
throw new Pluf_Form_Invalid(__('The confirmation code does not match. Please provide a valid confirmation code to delete the project.'));
|
||||
}
|
||||
return $code;
|
||||
}
|
||||
|
||||
public function clean_agree()
|
||||
{
|
||||
if (!$this->cleaned_data['agree']) {
|
||||
throw new Pluf_Form_Invalid(__('Sorry, you really need to backup your data before deletion.'));
|
||||
}
|
||||
return $this->cleaned_data['agree'];
|
||||
}
|
||||
|
||||
public function getCode()
|
||||
{
|
||||
return substr(md5(Pluf::f('secret_key').$this->user->id.'.'.$this->project->id),
|
||||
0, 8);
|
||||
}
|
||||
|
||||
|
||||
public function save($commit=true)
|
||||
{
|
||||
if (!$this->isValid()) {
|
||||
throw new Exception(__('Cannot save the model from an invalid form.'));
|
||||
}
|
||||
// So, we drop the project, it will cascade and delete all the
|
||||
// elements of the project. For large projects, this may use
|
||||
// quite some memory.
|
||||
$this->project->delete();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
196
indefero/src/IDF/Form/Admin/ProjectUpdate.php
Normal file
196
indefero/src/IDF/Form/Admin/ProjectUpdate.php
Normal file
@@ -0,0 +1,196 @@
|
||||
<?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-2011 Céondo Ltd and contributors.
|
||||
#
|
||||
# InDefero is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# InDefero is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# ***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
/**
|
||||
* Update a project.
|
||||
*
|
||||
* A kind of merge of the member configuration and overview in the
|
||||
* project administration area.
|
||||
*
|
||||
*/
|
||||
class IDF_Form_Admin_ProjectUpdate extends Pluf_Form
|
||||
{
|
||||
public $project = null;
|
||||
|
||||
public function initFields($extra=array())
|
||||
{
|
||||
$this->project = $extra['project'];
|
||||
$members = $this->project->getMembershipData('string');
|
||||
$conf = $this->project->getConf();
|
||||
|
||||
$this->fields['name'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Name'),
|
||||
'initial' => $this->project->name,
|
||||
));
|
||||
|
||||
$this->fields['shortdesc'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Short description'),
|
||||
'help_text' => __('A one line description of the project.'),
|
||||
'initial' => $this->project->shortdesc,
|
||||
'widget_attrs' => array('size' => '35'),
|
||||
));
|
||||
|
||||
$this->fields['external_project_url'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
'label' => __('External URL'),
|
||||
'widget_attrs' => array('size' => '35'),
|
||||
'initial' => $conf->getVal('external_project_url'),
|
||||
));
|
||||
|
||||
if ($this->project->getConf()->getVal('scm') == 'mtn') {
|
||||
$this->fields['mtn_master_branch'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
'label' => __('Master branch'),
|
||||
'initial' => $conf->getVal('mtn_master_branch'),
|
||||
'widget_attrs' => array('size' => '35'),
|
||||
'help_text' => __('This should be a world-wide unique identifier for your project. A reverse DNS notation like "com.my-domain.my-project" is a good idea.'),
|
||||
));
|
||||
}
|
||||
|
||||
$tags = $this->project->get_tags_list();
|
||||
for ($i=1;$i<7;$i++) {
|
||||
$initial = '';
|
||||
if (isset($tags[$i-1])) {
|
||||
if ($tags[$i-1]->class != 'Other') {
|
||||
$initial = (string) $tags[$i-1];
|
||||
} else {
|
||||
$initial = $tags[$i-1]->name;
|
||||
}
|
||||
}
|
||||
$this->fields['label'.$i] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
'label' => __('Labels'),
|
||||
'initial' => $initial,
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 50,
|
||||
'size' => 20,
|
||||
),
|
||||
));
|
||||
}
|
||||
$this->fields['owners'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
'label' => __('Project owners'),
|
||||
'initial' => $members['owners'],
|
||||
'widget' => 'Pluf_Form_Widget_TextareaInput',
|
||||
'widget_attrs' => array('rows' => 5,
|
||||
'cols' => 40),
|
||||
));
|
||||
$this->fields['members'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
'label' => __('Project members'),
|
||||
'initial' => $members['members'],
|
||||
'widget_attrs' => array('rows' => 7,
|
||||
'cols' => 40),
|
||||
'widget' => 'Pluf_Form_Widget_TextareaInput',
|
||||
));
|
||||
}
|
||||
|
||||
public function clean_mtn_master_branch()
|
||||
{
|
||||
$mtn_master_branch = mb_strtolower($this->cleaned_data['mtn_master_branch']);
|
||||
if (!preg_match('/^([\w\d]+([-][\w\d]+)*)(\.[\w\d]+([-][\w\d]+)*)*$/',
|
||||
$mtn_master_branch)) {
|
||||
throw new Pluf_Form_Invalid(__(
|
||||
'The master branch is empty or contains illegal characters, '.
|
||||
'please use only letters, digits, dashes and dots as separators.'
|
||||
));
|
||||
}
|
||||
|
||||
$sql = new Pluf_SQL('vkey=%s AND vdesc=%s AND project!=%s',
|
||||
array('mtn_master_branch', $mtn_master_branch,
|
||||
(string)$this->project->id));
|
||||
$l = Pluf::factory('IDF_Conf')->getList(array('filter'=>$sql->gen()));
|
||||
if ($l->count() > 0) {
|
||||
throw new Pluf_Form_Invalid(__(
|
||||
'This master branch is already used. Please select another one.'
|
||||
));
|
||||
}
|
||||
|
||||
return $mtn_master_branch;
|
||||
}
|
||||
|
||||
public function clean_owners()
|
||||
{
|
||||
return IDF_Form_MembersConf::checkBadLogins($this->cleaned_data['owners']);
|
||||
}
|
||||
|
||||
public function clean_members()
|
||||
{
|
||||
return IDF_Form_MembersConf::checkBadLogins($this->cleaned_data['members']);
|
||||
}
|
||||
|
||||
public function clean_external_project_url()
|
||||
{
|
||||
return IDF_Form_ProjectConf::checkWebURL($this->cleaned_data['external_project_url']);
|
||||
}
|
||||
|
||||
public function save($commit=true)
|
||||
{
|
||||
if (!$this->isValid()) {
|
||||
throw new Exception(__('Cannot save the model from an invalid form.'));
|
||||
}
|
||||
|
||||
// Add a tag for each label
|
||||
$tagids = array();
|
||||
for ($i=1;$i<7;$i++) {
|
||||
if (strlen($this->cleaned_data['label'.$i]) > 0) {
|
||||
if (strpos($this->cleaned_data['label'.$i], ':') !== false) {
|
||||
list($class, $name) = explode(':', $this->cleaned_data['label'.$i], 2);
|
||||
list($class, $name) = array(trim($class), trim($name));
|
||||
} else {
|
||||
$class = 'Other';
|
||||
$name = trim($this->cleaned_data['label'.$i]);
|
||||
}
|
||||
$tag = IDF_Tag::addGlobal($name, $class);
|
||||
$tagids[] = $tag->id;
|
||||
}
|
||||
}
|
||||
$this->project->batchAssoc('IDF_Tag', $tagids);
|
||||
|
||||
IDF_Form_MembersConf::updateMemberships($this->project,
|
||||
$this->cleaned_data);
|
||||
$this->project->membershipsUpdated();
|
||||
|
||||
$this->project->name = $this->cleaned_data['name'];
|
||||
$this->project->shortdesc = $this->cleaned_data['shortdesc'];
|
||||
$this->project->update();
|
||||
|
||||
$conf = $this->project->getConf();
|
||||
$keys = array('mtn_master_branch', 'external_project_url');
|
||||
foreach ($keys as $key) {
|
||||
if (array_key_exists($key, $this->cleaned_data)) {
|
||||
if (!empty($this->cleaned_data[$key])) {
|
||||
$conf->setVal($key, $this->cleaned_data[$key]);
|
||||
}
|
||||
else {
|
||||
$conf->delVal($key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
215
indefero/src/IDF/Form/Admin/UserCreate.php
Normal file
215
indefero/src/IDF/Form/Admin/UserCreate.php
Normal file
@@ -0,0 +1,215 @@
|
||||
<?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-2011 Céondo Ltd and contributors.
|
||||
#
|
||||
# InDefero is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# InDefero is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# ***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
/**
|
||||
* Allow an admin to create a user.
|
||||
*/
|
||||
class IDF_Form_Admin_UserCreate extends Pluf_Form
|
||||
{
|
||||
public $request = null;
|
||||
|
||||
public function initFields($extra=array())
|
||||
{
|
||||
$this->request = $extra['request'];
|
||||
$this->fields['first_name'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
'label' => __('First name'),
|
||||
'initial' => '',
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 50,
|
||||
'size' => 15,
|
||||
),
|
||||
));
|
||||
$this->fields['last_name'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Last name'),
|
||||
'initial' => '',
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 50,
|
||||
'size' => 20,
|
||||
),
|
||||
));
|
||||
|
||||
$this->fields['login'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Login'),
|
||||
'max_length' => 15,
|
||||
'min_length' => 3,
|
||||
'initial' => '',
|
||||
'help_text' => __('The login must be between 3 and 15 characters long and contains only letters and digits.'),
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 15,
|
||||
'size' => 10,
|
||||
),
|
||||
));
|
||||
|
||||
$this->fields['email'] = new Pluf_Form_Field_Email(
|
||||
array('required' => true,
|
||||
'label' => __('Email'),
|
||||
'initial' => '',
|
||||
'help_text' => __('Double check the email address as the password is sent directly to the user.'),
|
||||
));
|
||||
|
||||
$this->fields['language'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Language'),
|
||||
'initial' => '',
|
||||
'widget' => 'Pluf_Form_Widget_SelectInput',
|
||||
'widget_attrs' => array(
|
||||
'choices' =>
|
||||
Pluf_L10n::getInstalledLanguages()
|
||||
),
|
||||
));
|
||||
|
||||
$this->fields['public_key'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
'label' => __('Add a public key'),
|
||||
'initial' => '',
|
||||
'widget_attrs' => array('rows' => 3,
|
||||
'cols' => 40),
|
||||
'widget' => 'Pluf_Form_Widget_TextareaInput',
|
||||
'help_text' => __('Paste a SSH or monotone public key. Be careful to not provide your private key here!')
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the model in the database.
|
||||
*
|
||||
* @param bool Commit in the database or not. If not, the object
|
||||
* is returned but not saved in the database.
|
||||
* @return Object Model with data set from the form.
|
||||
*/
|
||||
function save($commit=true)
|
||||
{
|
||||
if (!$this->isValid()) {
|
||||
throw new Exception(__('Cannot save the model from an invalid form.'));
|
||||
}
|
||||
$password = Pluf_Utils::getPassword();
|
||||
$user = new Pluf_User();
|
||||
$user->setFromFormData($this->cleaned_data);
|
||||
$user->active = true;
|
||||
$user->staff = false;
|
||||
$user->administrator = false;
|
||||
$user->setPassword(base64_encode(sha1($password,TRUE)));
|
||||
$user->create();
|
||||
/**
|
||||
* [signal]
|
||||
*
|
||||
* Pluf_User::passwordUpdated
|
||||
*
|
||||
* [sender]
|
||||
*
|
||||
* IDF_Form_Admin_UserCreate
|
||||
*
|
||||
* [description]
|
||||
*
|
||||
* This signal is sent when a user is created
|
||||
* by the staff.
|
||||
*
|
||||
* [parameters]
|
||||
*
|
||||
* array('user' => $user)
|
||||
*
|
||||
*/
|
||||
$params = array('user' => $user);
|
||||
Pluf_Signal::send('Pluf_User::passwordUpdated',
|
||||
'IDF_Form_Admin_UserCreate', $params);
|
||||
// Create the public key as needed
|
||||
if ('' !== $this->cleaned_data['public_key']) {
|
||||
$key = new IDF_Key();
|
||||
$key->user = $user;
|
||||
$key->content = $this->cleaned_data['public_key'];
|
||||
$key->create();
|
||||
}
|
||||
// Send an email to the user with the password
|
||||
Pluf::loadFunction('Pluf_HTTP_URL_urlForView');
|
||||
$url = Pluf::f('url_base').Pluf_HTTP_URL_urlForView('IDF_Views::login', array(), array(), false);
|
||||
$context = new Pluf_Template_Context(
|
||||
array('password' => Pluf_Template::markSafe($password),
|
||||
'user' => $user,
|
||||
'url' => Pluf_Template::markSafe($url),
|
||||
'admin' => $this->request->user,
|
||||
));
|
||||
$tmpl = new Pluf_Template('idf/gadmin/users/createuser-email.txt');
|
||||
$text_email = $tmpl->render($context);
|
||||
$email = new Pluf_Mail(Pluf::f('from_email'), $user->email,
|
||||
__('Your details to access your forge.'));
|
||||
$email->addTextMessage($text_email);
|
||||
$email->sendMail();
|
||||
return $user;
|
||||
}
|
||||
|
||||
function clean_last_name()
|
||||
{
|
||||
$last_name = trim($this->cleaned_data['last_name']);
|
||||
if ($last_name == mb_strtoupper($last_name)) {
|
||||
return mb_convert_case(mb_strtolower($last_name),
|
||||
MB_CASE_TITLE, 'UTF-8');
|
||||
}
|
||||
return $last_name;
|
||||
}
|
||||
|
||||
function clean_first_name()
|
||||
{
|
||||
$first_name = trim($this->cleaned_data['first_name']);
|
||||
if ($first_name == mb_strtoupper($first_name)) {
|
||||
return mb_convert_case(mb_strtolower($first_name),
|
||||
MB_CASE_TITLE, 'UTF-8');
|
||||
}
|
||||
return $first_name;
|
||||
}
|
||||
|
||||
function clean_email()
|
||||
{
|
||||
$this->cleaned_data['email'] = mb_strtolower(trim($this->cleaned_data['email']));
|
||||
$guser = new Pluf_User();
|
||||
$sql = new Pluf_SQL('email=%s', array($this->cleaned_data['email']));
|
||||
if ($guser->getCount(array('filter' => $sql->gen())) > 0) {
|
||||
throw new Pluf_Form_Invalid(sprintf(__('The email "%s" is already used.'), $this->cleaned_data['email']));
|
||||
}
|
||||
return $this->cleaned_data['email'];
|
||||
}
|
||||
|
||||
public function clean_login()
|
||||
{
|
||||
$this->cleaned_data['login'] = mb_strtolower(trim($this->cleaned_data['login']));
|
||||
if (preg_match('/[^a-z0-9]/', $this->cleaned_data['login'])) {
|
||||
throw new Pluf_Form_Invalid(sprintf(__('The login "%s" can only contain letters and digits.'), $this->cleaned_data['login']));
|
||||
}
|
||||
$guser = new Pluf_User();
|
||||
$sql = new Pluf_SQL('login=%s', $this->cleaned_data['login']);
|
||||
if ($guser->getCount(array('filter' => $sql->gen())) > 0) {
|
||||
throw new Pluf_Form_Invalid(sprintf(__('The login "%s" is already used, please find another one.'), $this->cleaned_data['login']));
|
||||
}
|
||||
return $this->cleaned_data['login'];
|
||||
}
|
||||
|
||||
public function clean_public_key()
|
||||
{
|
||||
$this->cleaned_data['public_key'] =
|
||||
IDF_Form_UserAccount::checkPublicKey($this->cleaned_data['public_key']);
|
||||
|
||||
return $this->cleaned_data['public_key'];
|
||||
}
|
||||
}
|
321
indefero/src/IDF/Form/Admin/UserUpdate.php
Normal file
321
indefero/src/IDF/Form/Admin/UserUpdate.php
Normal file
@@ -0,0 +1,321 @@
|
||||
<?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-2011 Céondo Ltd and contributors.
|
||||
#
|
||||
# InDefero is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# InDefero is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/**
|
||||
* Update user's details.
|
||||
*/
|
||||
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'),
|
||||
'initial' => $this->user->first_name,
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 50,
|
||||
'size' => 15,
|
||||
),
|
||||
));
|
||||
$this->fields['last_name'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Last name'),
|
||||
'initial' => $this->user->last_name,
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 50,
|
||||
'size' => 20,
|
||||
),
|
||||
));
|
||||
|
||||
$this->fields['email'] = new Pluf_Form_Field_Email(
|
||||
array('required' => true,
|
||||
'label' => __('Email'),
|
||||
'initial' => $this->user->email,
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 50,
|
||||
'size' => 20,
|
||||
),
|
||||
));
|
||||
|
||||
$this->fields['language'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Language'),
|
||||
'initial' => $this->user->language,
|
||||
'widget' => 'Pluf_Form_Widget_SelectInput',
|
||||
'widget_attrs' => array(
|
||||
'choices' =>
|
||||
Pluf_L10n::getInstalledLanguages()
|
||||
),
|
||||
));
|
||||
|
||||
$this->fields['password'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
'label' => __('Password'),
|
||||
'initial' => '',
|
||||
'widget' => 'Pluf_Form_Widget_PasswordInput',
|
||||
'help_text' => Pluf_Template::markSafe(__('Leave blank if you do not want to change the password.').'<br />'.__('The password must be hard for other people to guess, but easy for the user to remember.')),
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 50,
|
||||
'size' => 15,
|
||||
),
|
||||
));
|
||||
$this->fields['password2'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
'label' => __('Confirm password'),
|
||||
'initial' => '',
|
||||
'widget' => 'Pluf_Form_Widget_PasswordInput',
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 50,
|
||||
'size' => 15,
|
||||
),
|
||||
));
|
||||
|
||||
$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,
|
||||
'label' => __('Staff'),
|
||||
'initial' => $this->user->staff,
|
||||
'widget' => 'Pluf_Form_Widget_CheckboxInput',
|
||||
'help_text' => __('If you give staff rights to a user, you really need to trust him.'),
|
||||
));
|
||||
}
|
||||
|
||||
$attrs = ($extra['request']->user->id == $this->user->id) ?
|
||||
array('readonly' => 'readonly') : array();
|
||||
$this->fields['active'] = new Pluf_Form_Field_Boolean(
|
||||
array('required' => false,
|
||||
'label' => __('Active'),
|
||||
'initial' => $this->user->active,
|
||||
'widget' => 'Pluf_Form_Widget_CheckboxInput',
|
||||
'widget_attrs' => $attrs,
|
||||
'help_text' => __('If the user is not getting the confirmation email or is abusing the system, you can directly enable or disable their account here.'),
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Save the model in the database.
|
||||
*
|
||||
* @param bool Commit in the database or not. If not, the object
|
||||
* is returned but not saved in the database.
|
||||
* @return Object Model with data set from the form.
|
||||
*/
|
||||
function save($commit=true)
|
||||
{
|
||||
if (!$this->isValid()) {
|
||||
throw new Exception(__('Cannot save the model from an invalid form.'));
|
||||
}
|
||||
unset($this->cleaned_data['password2']);
|
||||
$update_pass = false;
|
||||
if (strlen($this->cleaned_data['password']) == 0) {
|
||||
unset($this->cleaned_data['password']);
|
||||
} else {
|
||||
$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]
|
||||
*
|
||||
* Pluf_User::passwordUpdated
|
||||
*
|
||||
* [sender]
|
||||
*
|
||||
* IDF_Form_UserAccount
|
||||
*
|
||||
* [description]
|
||||
*
|
||||
* This signal is sent when the user updated his
|
||||
* password from his account page.
|
||||
*
|
||||
* [parameters]
|
||||
*
|
||||
* array('user' => $user)
|
||||
*
|
||||
*/
|
||||
$params = array('user' => $this->user);
|
||||
Pluf_Signal::send('Pluf_User::passwordUpdated',
|
||||
'IDF_Form_Admin_UserUpdate', $params);
|
||||
}
|
||||
}
|
||||
return $this->user;
|
||||
}
|
||||
|
||||
function clean_last_name()
|
||||
{
|
||||
$last_name = trim($this->cleaned_data['last_name']);
|
||||
if ($last_name == mb_strtoupper($last_name)) {
|
||||
return mb_convert_case(mb_strtolower($last_name),
|
||||
MB_CASE_TITLE, 'UTF-8');
|
||||
}
|
||||
return $last_name;
|
||||
}
|
||||
|
||||
function clean_first_name()
|
||||
{
|
||||
$first_name = trim($this->cleaned_data['first_name']);
|
||||
if ($first_name == '---') {
|
||||
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),
|
||||
MB_CASE_TITLE, 'UTF-8');
|
||||
}
|
||||
return $first_name;
|
||||
}
|
||||
|
||||
function clean_email()
|
||||
{
|
||||
$email = mb_strtolower(trim($this->cleaned_data['email']));
|
||||
$sql = new Pluf_SQL('email=%s AND id!=%s',
|
||||
array($email, $this->user->id));
|
||||
$users = Pluf::factory('Pluf_User')->getList(array('filter'=>$sql->gen()));
|
||||
if ($users->count() > 0) {
|
||||
throw new Pluf_Form_Invalid(__('A user with this email already exists, please provide another email address.'));
|
||||
}
|
||||
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 two passwords are the same.
|
||||
*/
|
||||
public function clean()
|
||||
{
|
||||
if (!isset($this->errors['password'])
|
||||
&& !isset($this->errors['password2'])) {
|
||||
$password1 = $this->cleaned_data['password'];
|
||||
$password2 = $this->cleaned_data['password2'];
|
||||
if ($password1 != $password2) {
|
||||
throw new Pluf_Form_Invalid(__('The passwords do not match. Please give them again.'));
|
||||
}
|
||||
}
|
||||
return $this->cleaned_data;
|
||||
}
|
||||
}
|
51
indefero/src/IDF/Form/Field/EmailList.php
Normal file
51
indefero/src/IDF/Form/Field/EmailList.php
Normal 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) 2008-2011 Céondo Ltd and contributors.
|
||||
#
|
||||
# InDefero is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# InDefero is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
473
indefero/src/IDF/Form/IssueCreate.php
Normal file
473
indefero/src/IDF/Form/IssueCreate.php
Normal file
@@ -0,0 +1,473 @@
|
||||
<?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-2011 Céondo Ltd and contributors.
|
||||
#
|
||||
# InDefero is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# InDefero is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/**
|
||||
* Create a new issue.
|
||||
*
|
||||
* This create the issue entry and the first comment corresponding to
|
||||
* the description and the attached files.
|
||||
*
|
||||
* It is possible to tag the issue following some rules. For example
|
||||
* you cannot put several "status" or "priority" tags.
|
||||
*
|
||||
*/
|
||||
class IDF_Form_IssueCreate extends Pluf_Form
|
||||
{
|
||||
public $user = null;
|
||||
public $project = null;
|
||||
public $show_full = false;
|
||||
public $relation_types = null;
|
||||
|
||||
public function initFields($extra=array())
|
||||
{
|
||||
$this->user = $extra['user'];
|
||||
$this->project = $extra['project'];
|
||||
if ($this->user->hasPerm('IDF.project-owner', $this->project)
|
||||
or $this->user->hasPerm('IDF.project-member', $this->project)) {
|
||||
$this->show_full = true;
|
||||
}
|
||||
$this->relation_types = $this->project->getRelationsFromConfig();
|
||||
|
||||
$contentTemplate = $this->project->getConf()->getVal(
|
||||
'labels_issue_template', IDF_Form_IssueTrackingConf::init_template
|
||||
);
|
||||
|
||||
$this->fields['summary'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Summary'),
|
||||
'initial' => '',
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 200,
|
||||
'size' => 67,
|
||||
),
|
||||
));
|
||||
$this->fields['content'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Description'),
|
||||
'initial' => $contentTemplate,
|
||||
'widget' => 'Pluf_Form_Widget_TextareaInput',
|
||||
'widget_attrs' => array(
|
||||
'cols' => 58,
|
||||
'rows' => 13,
|
||||
),
|
||||
));
|
||||
$upload_path = Pluf::f('upload_issue_path', false);
|
||||
if (false === $upload_path) {
|
||||
throw new Pluf_Exception_SettingError(__('The "upload_issue_path" configuration variable was not set.'));
|
||||
}
|
||||
$md5 = md5(rand().microtime().Pluf_Utils::getRandomString());
|
||||
// We add .dummy to try to mitigate security issues in the
|
||||
// case of someone allowing the upload path to be accessible
|
||||
// to everybody.
|
||||
for ($i=1;$i<4;$i++) {
|
||||
$filename = substr($md5, 0, 2).'/'.substr($md5, 2, 2).'/'.substr($md5, 4).'/%s.dummy';
|
||||
$this->fields['attachment'.$i] = new Pluf_Form_Field_File(
|
||||
array('required' => false,
|
||||
'label' => __('Attach a file'),
|
||||
'move_function_params' =>
|
||||
array('upload_path' => $upload_path,
|
||||
'upload_path_create' => true,
|
||||
'file_name' => $filename,
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if ($this->show_full) {
|
||||
$this->fields['status'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Status'),
|
||||
'initial' => 'New',
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 20,
|
||||
'size' => 15,
|
||||
),
|
||||
));
|
||||
$this->fields['owner'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
'label' => __('Owner'),
|
||||
'initial' => '',
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 20,
|
||||
'size' => 15,
|
||||
),
|
||||
));
|
||||
|
||||
$this->fields['relation_type0'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
'label' => __('This issue'),
|
||||
'initial' => current($this->relation_types),
|
||||
'widget_attrs' => array('size' => 15),
|
||||
));
|
||||
|
||||
$this->fields['relation_issue0'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
'label' => null,
|
||||
'initial' => '',
|
||||
'widget_attrs' => array('size' => 10),
|
||||
));
|
||||
|
||||
/*
|
||||
* get predefined tags for issues from current project
|
||||
*
|
||||
* first Type:<...> and Priority:<...> will be used
|
||||
*
|
||||
*/
|
||||
$predefined = preg_split("/[\r\n]+/", $extra['project']->getConf()->getVal(
|
||||
'labels_issue_predefined'
|
||||
));
|
||||
$predefined_type = 'Type:Defect';
|
||||
foreach ($predefined as $tag) {
|
||||
if (strpos($tag, 'Type:') === 0) {
|
||||
$predefined_type = explode('=', $tag, 2);
|
||||
$predefined_type = trim($predefined_type[0]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
$predefined_priority = 'Priority:Medium';
|
||||
foreach ($predefined as $tag) {
|
||||
if (strpos($tag, 'Priority:') === 0) {
|
||||
$predefined_priority = explode('=', $tag, 2);
|
||||
$predefined_priority = trim($predefined_priority[0]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for ($i=1;$i<7;$i++) {
|
||||
$initial = '';
|
||||
switch ($i) {
|
||||
case 1:
|
||||
$initial = $predefined_type;
|
||||
break;
|
||||
case 2:
|
||||
$initial = $predefined_priority;
|
||||
break;
|
||||
}
|
||||
$this->fields['label'.$i] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
'label' => __('Labels'),
|
||||
'initial' => $initial,
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 50,
|
||||
'size' => 20,
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the interconnection in the form.
|
||||
*/
|
||||
public function clean()
|
||||
{
|
||||
// We need to check that no label with the 'Status' class is
|
||||
// given.
|
||||
if (!$this->show_full) {
|
||||
return $this->cleaned_data;
|
||||
}
|
||||
$conf = new IDF_Conf();
|
||||
$conf->setProject($this->project);
|
||||
$onemax = array();
|
||||
foreach (explode(',', $conf->getVal('labels_issue_one_max', IDF_Form_IssueTrackingConf::init_one_max)) as $class) {
|
||||
if (trim($class) != '') {
|
||||
$onemax[] = mb_strtolower(trim($class));
|
||||
}
|
||||
}
|
||||
$count = array();
|
||||
for ($i=1;$i<7;$i++) {
|
||||
$this->cleaned_data['label'.$i] = trim($this->cleaned_data['label'.$i]);
|
||||
if (strpos($this->cleaned_data['label'.$i], ':') !== false) {
|
||||
list($class, $name) = explode(':', $this->cleaned_data['label'.$i], 2);
|
||||
list($class, $name) = array(mb_strtolower(trim($class)),
|
||||
trim($name));
|
||||
} else {
|
||||
$class = 'other';
|
||||
$name = $this->cleaned_data['label'.$i];
|
||||
}
|
||||
if ($class == 'status') {
|
||||
if (!isset($this->errors['label'.$i])) $this->errors['label'.$i] = array();
|
||||
$this->errors['label'.$i][] = __('You cannot add a label with the "Status" prefix to an issue.');
|
||||
throw new Pluf_Form_Invalid(__('You provided an invalid label.'));
|
||||
}
|
||||
if (!isset($count[$class])) $count[$class] = 1;
|
||||
else $count[$class] += 1;
|
||||
if (in_array($class, $onemax) and $count[$class] > 1) {
|
||||
if (!isset($this->errors['label'.$i])) $this->errors['label'.$i] = array();
|
||||
$this->errors['label'.$i][] = sprintf(__('You cannot provide more than one label from the %s class to an issue.'), $class);
|
||||
throw new Pluf_Form_Invalid(__('You provided an invalid label.'));
|
||||
}
|
||||
}
|
||||
return $this->cleaned_data;
|
||||
}
|
||||
|
||||
function clean_content()
|
||||
{
|
||||
$content = trim($this->cleaned_data['content']);
|
||||
if (strlen($content) == 0) {
|
||||
throw new Pluf_Form_Invalid(__('You need to provide a description of the issue.'));
|
||||
}
|
||||
return $content;
|
||||
}
|
||||
|
||||
function clean_status()
|
||||
{
|
||||
// Check that the status is in the list of official status
|
||||
$tags = $this->project->getTagsFromConfig('labels_issue_open',
|
||||
IDF_Form_IssueTrackingConf::init_open,
|
||||
'Status');
|
||||
$tags = array_merge($this->project->getTagsFromConfig('labels_issue_closed',
|
||||
IDF_Form_IssueTrackingConf::init_closed,
|
||||
'Status')
|
||||
, $tags);
|
||||
$found = false;
|
||||
foreach ($tags as $tag) {
|
||||
if ($tag->name == trim($this->cleaned_data['status'])) {
|
||||
$found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!$found) {
|
||||
throw new Pluf_Form_Invalid(__('You provided an invalid status.'));
|
||||
}
|
||||
return $this->cleaned_data['status'];
|
||||
}
|
||||
|
||||
// this method is not called from Pluf_Form directly, but shared for
|
||||
// among all similar fields
|
||||
function clean_relation_type($value)
|
||||
{
|
||||
$relation_type = trim($value);
|
||||
if (empty($relation_type))
|
||||
return '';
|
||||
|
||||
$found = false;
|
||||
foreach ($this->relation_types as $type) {
|
||||
if ($type == $relation_type) {
|
||||
$found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!$found) {
|
||||
throw new Pluf_Form_Invalid(__('You provided an invalid relation type.'));
|
||||
}
|
||||
return $relation_type;
|
||||
}
|
||||
|
||||
function clean_relation_type0()
|
||||
{
|
||||
return $this->clean_relation_type($this->cleaned_data['relation_type0']);
|
||||
}
|
||||
|
||||
// this method is not called from Pluf_Form directly, but shared for
|
||||
// among all similar fields
|
||||
function clean_relation_issue($value)
|
||||
{
|
||||
$issues = trim($value);
|
||||
if (empty($issues))
|
||||
return '';
|
||||
|
||||
$issue_ids = preg_split('/\s*,\s*/', $issues, -1, PREG_SPLIT_NO_EMPTY);
|
||||
foreach ($issue_ids as $issue_id) {
|
||||
if (!ctype_digit($issue_id) || (int)$issue_id < 1) {
|
||||
throw new Pluf_Form_Invalid(sprintf(
|
||||
__('The value "%s" is not a valid issue id.'), $issue_id
|
||||
));
|
||||
}
|
||||
$issue = new IDF_Issue($issue_id);
|
||||
if ($issue->id != $issue_id || $issue->project != $this->project->id) {
|
||||
throw new Pluf_Form_Invalid(sprintf(
|
||||
__('The issue "%s" does not exist.'), $issue_id
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
return implode(', ', $issue_ids);
|
||||
}
|
||||
|
||||
function clean_relation_issue0()
|
||||
{
|
||||
return $this->clean_relation_issue($this->cleaned_data['relation_issue0']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean the attachments post failure.
|
||||
*/
|
||||
function failed()
|
||||
{
|
||||
$upload_path = Pluf::f('upload_issue_path', false);
|
||||
if ($upload_path == false) return;
|
||||
for ($i=1;$i<4;$i++) {
|
||||
if (!empty($this->cleaned_data['attachment'.$i]) and
|
||||
file_exists($upload_path.'/'.$this->cleaned_data['attachment'.$i])) {
|
||||
@unlink($upload_path.'/'.$this->cleaned_data['attachment'.$i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the model in the database.
|
||||
*
|
||||
* @param bool Commit in the database or not. If not, the object
|
||||
* is returned but not saved in the database.
|
||||
* @return Object Model with data set from the form.
|
||||
*/
|
||||
function save($commit=true)
|
||||
{
|
||||
if (!$this->isValid()) {
|
||||
throw new Exception(__('Cannot save the model from an invalid form.'));
|
||||
}
|
||||
// Add a tag for each label
|
||||
$tags = array();
|
||||
if ($this->show_full) {
|
||||
for ($i=1;$i<7;$i++) {
|
||||
if (strlen($this->cleaned_data['label'.$i]) > 0) {
|
||||
if (strpos($this->cleaned_data['label'.$i], ':') !== false) {
|
||||
list($class, $name) = explode(':', $this->cleaned_data['label'.$i], 2);
|
||||
list($class, $name) = array(trim($class), trim($name));
|
||||
} else {
|
||||
$class = 'Other';
|
||||
$name = trim($this->cleaned_data['label'.$i]);
|
||||
}
|
||||
$tags[] = IDF_Tag::add($name, $this->project, $class);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$tags[] = IDF_Tag::add('Medium', $this->project, 'Priority');
|
||||
$tags[] = IDF_Tag::add('Defect', $this->project, 'Type');
|
||||
}
|
||||
// Create the issue
|
||||
$issue = new IDF_Issue();
|
||||
$issue->project = $this->project;
|
||||
$issue->submitter = $this->user;
|
||||
if ($this->show_full) {
|
||||
$issue->status = IDF_Tag::add(trim($this->cleaned_data['status']), $this->project, 'Status');
|
||||
$issue->owner = self::findUser($this->cleaned_data['owner']);
|
||||
} else {
|
||||
$_t = $this->project->getTagIdsByStatus('open');
|
||||
$issue->status = new IDF_Tag($_t[0]); // first one is the default
|
||||
$issue->owner = null;
|
||||
}
|
||||
$issue->summary = trim($this->cleaned_data['summary']);
|
||||
$issue->create();
|
||||
foreach ($tags as $tag) {
|
||||
$issue->setAssoc($tag);
|
||||
}
|
||||
// add relations (if any)
|
||||
if (!empty($this->cleaned_data['relation_type0'])) {
|
||||
$verb = $this->cleaned_data['relation_type0'];
|
||||
$other_verb = $this->relation_types[$verb];
|
||||
$related_issues = preg_split('/\s*,\s*/', $this->cleaned_data['relation_issue0'], -1, PREG_SPLIT_NO_EMPTY);
|
||||
|
||||
foreach ($related_issues as $related_issue_id) {
|
||||
$related_issue = new IDF_Issue($related_issue_id);
|
||||
$rel = new IDF_IssueRelation();
|
||||
$rel->issue = $issue;
|
||||
$rel->verb = $verb;
|
||||
$rel->other_issue = $related_issue;
|
||||
$rel->submitter = $this->user;
|
||||
$rel->create();
|
||||
|
||||
$other_rel = new IDF_IssueRelation();
|
||||
$other_rel->issue = $related_issue;
|
||||
$other_rel->verb = $other_verb;
|
||||
$other_rel->other_issue = $issue;
|
||||
$other_rel->submitter = $this->user;
|
||||
$other_rel->create();
|
||||
}
|
||||
}
|
||||
|
||||
// add the first comment
|
||||
$comment = new IDF_IssueComment();
|
||||
$comment->issue = $issue;
|
||||
$comment->content = $this->cleaned_data['content'];
|
||||
$comment->submitter = $this->user;
|
||||
$comment->create();
|
||||
// If we have a file, create the IDF_IssueFile and attach
|
||||
// it to the comment.
|
||||
$created_files = array();
|
||||
for ($i=1;$i<4;$i++) {
|
||||
if ($this->cleaned_data['attachment'.$i]) {
|
||||
$file = new IDF_IssueFile();
|
||||
$file->attachment = $this->cleaned_data['attachment'.$i];
|
||||
$file->submitter = $this->user;
|
||||
$file->comment = $comment;
|
||||
$file->create();
|
||||
$created_files[] = $file;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* [signal]
|
||||
*
|
||||
* IDF_Issue::create
|
||||
*
|
||||
* [sender]
|
||||
*
|
||||
* IDF_Form_IssueCreate
|
||||
*
|
||||
* [description]
|
||||
*
|
||||
* This signal allows an application to perform a set of tasks
|
||||
* just after the creation of an issue. The comment contains
|
||||
* the description of the issue.
|
||||
*
|
||||
* [parameters]
|
||||
*
|
||||
* array('issue' => $issue,
|
||||
* 'comment' => $comment,
|
||||
* 'files' => $attached_files);
|
||||
*
|
||||
*/
|
||||
$params = array('issue' => $issue,
|
||||
'comment' => $comment,
|
||||
'files' => $created_files);
|
||||
Pluf_Signal::send('IDF_Issue::create', 'IDF_Form_IssueCreate',
|
||||
$params);
|
||||
return $issue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Based on the given string, try to find the matching user.
|
||||
*
|
||||
* Search order is: email, login, last_name.
|
||||
*
|
||||
* If no user found, simply returns null.
|
||||
*
|
||||
* @param string User
|
||||
* @return Pluf_User or null
|
||||
*/
|
||||
public static function findUser($string)
|
||||
{
|
||||
$string = trim($string);
|
||||
if (strlen($string) == 0) return null;
|
||||
$guser = new Pluf_User();
|
||||
foreach (array('email', 'login', 'last_name') as $what) {
|
||||
$sql = new Pluf_SQL($what.'=%s', $string);
|
||||
$users = $guser->getList(array('filter' => $sql->gen()));
|
||||
if ($users->count() > 0) {
|
||||
return $users[0];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
150
indefero/src/IDF/Form/IssueTrackingConf.php
Normal file
150
indefero/src/IDF/Form/IssueTrackingConf.php
Normal file
@@ -0,0 +1,150 @@
|
||||
<?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-2011 Céondo Ltd and contributors.
|
||||
#
|
||||
# InDefero is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# InDefero is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# ***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
/**
|
||||
* Configuration of the labels etc.
|
||||
*/
|
||||
class IDF_Form_IssueTrackingConf extends Pluf_Form
|
||||
{
|
||||
/**
|
||||
* Defined as constants to easily access the value in the
|
||||
* IssueUpdate/Create form in the case nothing is in the db yet.
|
||||
*/
|
||||
const init_template = 'Steps to reproduce the problem:
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
|
||||
Expected result:
|
||||
|
||||
Actual result:
|
||||
';
|
||||
const init_open = 'New = Issue has not had initial review yet
|
||||
Accepted = Problem reproduced / Need acknowledged
|
||||
Started = Work on this issue has begun';
|
||||
const init_closed = 'Fixed = Developer made requested changes, QA should verify
|
||||
Verified = QA has verified that the fix worked
|
||||
Invalid = This was not a valid issue report
|
||||
Duplicate = This report duplicates an existing issue
|
||||
WontFix = We decided to not take action on this issue';
|
||||
const init_predefined = 'Type:Defect = Report of a software defect
|
||||
Type:Enhancement = Request for enhancement
|
||||
Type:Task = Work item that doesn\'t change the code or docs
|
||||
Type:Patch = Source code patch for review
|
||||
Type:Other = Some other kind of issue
|
||||
Priority:Critical = Must resolve in the specified milestone
|
||||
Priority:High = Strongly want to resolve in the specified milestone
|
||||
Priority:Medium = Normal priority
|
||||
Priority:Low = Might slip to later milestone
|
||||
OpSys:All = Affects all operating systems
|
||||
OpSys:Windows = Affects Windows users
|
||||
OpSys:Linux = Affects Linux users
|
||||
OpSys:OSX = Affects Mac OS X users
|
||||
Milestone:Release1.0 = All essential functionality working
|
||||
Component:UI = Issue relates to program UI
|
||||
Component:Logic = Issue relates to application logic
|
||||
Component:Persistence = Issue relates to data storage components
|
||||
Component:Scripts = Utility and installation scripts
|
||||
Component:Docs = Issue relates to end-user documentation
|
||||
Security = Security risk to users
|
||||
Performance = Performance issue
|
||||
Usability = Affects program usability
|
||||
Maintainability = Hinders future changes';
|
||||
const init_one_max = 'Type, Priority, Milestone';
|
||||
// ATTENTION: if you change something here, change the values below as well!
|
||||
const init_relations = 'is related to
|
||||
blocks, is blocked by
|
||||
duplicates, is duplicated by';
|
||||
|
||||
// These are actually all noop's, but we have no other chance to
|
||||
// tell IDF's translation mechanism to mark the strings as translatable
|
||||
// FIXME: IDF should get a internal translation system for strings like
|
||||
// that, that can also be easily expanded by users
|
||||
private function noop()
|
||||
{
|
||||
__('is related to');
|
||||
__('blocks');
|
||||
__('is blocked by');
|
||||
__('duplicates');
|
||||
__('is duplicated by');
|
||||
}
|
||||
|
||||
public function initFields($extra=array())
|
||||
{
|
||||
$this->fields['labels_issue_template'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
'label' => __('Define an issue template to hint the reporter to provide certain information'),
|
||||
'initial' => self::init_template,
|
||||
'widget_attrs' => array('rows' => 7,
|
||||
'cols' => 75),
|
||||
'widget' => 'Pluf_Form_Widget_TextareaInput',
|
||||
));
|
||||
|
||||
$this->fields['labels_issue_open'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Open issue status values'),
|
||||
'initial' => self::init_open,
|
||||
'widget' => 'Pluf_Form_Widget_TextareaInput',
|
||||
'widget_attrs' => array('rows' => 5,
|
||||
'cols' => 75),
|
||||
));
|
||||
$this->fields['labels_issue_closed'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Closed issue status values'),
|
||||
'initial' => self::init_closed,
|
||||
'widget_attrs' => array('rows' => 7,
|
||||
'cols' => 75),
|
||||
'widget' => 'Pluf_Form_Widget_TextareaInput',
|
||||
));
|
||||
|
||||
$this->fields['labels_issue_predefined'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Predefined issue labels'),
|
||||
'initial' => self::init_predefined,
|
||||
'help_text' => __('The first "Type:" and "Priority:" entries found in this list are automatically chosen as defaults for new issues.'),
|
||||
'widget_attrs' => array('rows' => 7,
|
||||
'cols' => 75),
|
||||
'widget' => 'Pluf_Form_Widget_TextareaInput',
|
||||
));
|
||||
|
||||
$this->fields['labels_issue_one_max'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
'label' => __('Each issue may have at most one label with each of these classes.'),
|
||||
'initial' => self::init_one_max,
|
||||
'widget_attrs' => array('size' => 60),
|
||||
));
|
||||
|
||||
$this->fields['issue_relations'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Issue relations'),
|
||||
'initial' => self::init_relations,
|
||||
'help_text' => __('You can define bidirectional relations like "is related to" or "blocks, is blocked by". For standard relations pre-configured translations exist, new relations should however be defined in a language that is understood by all project members.'),
|
||||
'widget_attrs' => array('rows' => 7,
|
||||
'cols' => 75),
|
||||
'widget' => 'Pluf_Form_Widget_TextareaInput',
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
488
indefero/src/IDF/Form/IssueUpdate.php
Normal file
488
indefero/src/IDF/Form/IssueUpdate.php
Normal file
@@ -0,0 +1,488 @@
|
||||
<?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-2011 Céondo Ltd and contributors.
|
||||
#
|
||||
# InDefero is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# InDefero is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/**
|
||||
* Update an issue.
|
||||
*
|
||||
* We extend IDF_Form_IssueCreate to reuse the validation logic.
|
||||
*/
|
||||
class IDF_Form_IssueUpdate extends IDF_Form_IssueCreate
|
||||
{
|
||||
public $issue = null;
|
||||
|
||||
public function initFields($extra=array())
|
||||
{
|
||||
$this->user = $extra['user'];
|
||||
$this->project = $extra['project'];
|
||||
$this->issue = $extra['issue'];
|
||||
if ($this->user->hasPerm('IDF.project-owner', $this->project)
|
||||
or $this->user->hasPerm('IDF.project-member', $this->project)) {
|
||||
$this->show_full = true;
|
||||
}
|
||||
$this->relation_types = $this->project->getRelationsFromConfig();
|
||||
if ($this->show_full) {
|
||||
$this->fields['summary'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Summary'),
|
||||
'initial' => $this->issue->summary,
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 200,
|
||||
'size' => 67,
|
||||
),
|
||||
));
|
||||
}
|
||||
$this->fields['content'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
'label' => __('Comment'),
|
||||
'initial' => '',
|
||||
'widget' => 'Pluf_Form_Widget_TextareaInput',
|
||||
'widget_attrs' => array(
|
||||
'cols' => 58,
|
||||
'rows' => 9,
|
||||
),
|
||||
));
|
||||
$upload_path = Pluf::f('upload_issue_path', false);
|
||||
if (false === $upload_path) {
|
||||
throw new Pluf_Exception_SettingError(__('The "upload_issue_path" configuration variable was not set.'));
|
||||
}
|
||||
$md5 = md5(rand().microtime().Pluf_Utils::getRandomString());
|
||||
// We add .dummy to try to mitigate security issues in the
|
||||
// case of someone allowing the upload path to be accessible
|
||||
// to everybody.
|
||||
for ($i=1;$i<4;$i++) {
|
||||
$filename = substr($md5, 0, 2).'/'.substr($md5, 2, 2).'/'.substr($md5, 4).'/%s.dummy';
|
||||
$this->fields['attachment'.$i] = new Pluf_Form_Field_File(
|
||||
array('required' => false,
|
||||
'label' => __('Attach a file'),
|
||||
'move_function_params' =>
|
||||
array('upload_path' => $upload_path,
|
||||
'upload_path_create' => true,
|
||||
'file_name' => $filename,
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if ($this->show_full) {
|
||||
$this->fields['status'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Status'),
|
||||
'initial' => $this->issue->get_status()->name,
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 20,
|
||||
'size' => 15,
|
||||
),
|
||||
));
|
||||
$initial = ($this->issue->get_owner() == null) ? '' : $this->issue->get_owner()->login;
|
||||
$this->fields['owner'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
'label' => __('Owner'),
|
||||
'initial' => $initial,
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 20,
|
||||
'size' => 15,
|
||||
),
|
||||
));
|
||||
|
||||
$idx = 0;
|
||||
// note: clean_relation_type0 and clean_relation_issue0 already
|
||||
// exist in the base class
|
||||
$this->fields['relation_type'.$idx] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
'label' => __('This issue'),
|
||||
'initial' => current($this->relation_types),
|
||||
'widget_attrs' => array('size' => 15),
|
||||
));
|
||||
|
||||
$this->fields['relation_issue'.$idx] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
'label' => null,
|
||||
'initial' => '',
|
||||
'widget_attrs' => array('size' => 10),
|
||||
));
|
||||
|
||||
++$idx;
|
||||
$relatedIssues = $this->issue->getGroupedRelatedIssues(array(), true);
|
||||
foreach ($relatedIssues as $verb => $ids) {
|
||||
$this->fields['relation_type'.$idx] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
'label' => __('This issue'),
|
||||
'initial' => $verb,
|
||||
'widget_attrs' => array('size' => 15),
|
||||
));
|
||||
$m = 'clean_relation_type'.$idx;
|
||||
$this->$m = create_function('$form', '
|
||||
return $form->clean_relation_type($form->cleaned_data["relation_type'.$idx.'"]);
|
||||
');
|
||||
|
||||
$this->fields['relation_issue'.$idx] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
'label' => null,
|
||||
'initial' => implode(', ', $ids),
|
||||
'widget_attrs' => array('size' => 10),
|
||||
));
|
||||
$m = 'clean_relation_issue'.$idx;
|
||||
$this->$m = create_function('$form', '
|
||||
return $form->clean_relation_issue($form->cleaned_data["relation_issue'.$idx.'"]);
|
||||
');
|
||||
|
||||
++$idx;
|
||||
}
|
||||
|
||||
$tags = $this->issue->get_tags_list();
|
||||
for ($i=1;$i<7;$i++) {
|
||||
$initial = '';
|
||||
if (isset($tags[$i-1])) {
|
||||
if ($tags[$i-1]->class != 'Other') {
|
||||
$initial = (string) $tags[$i-1];
|
||||
} else {
|
||||
$initial = $tags[$i-1]->name;
|
||||
}
|
||||
}
|
||||
$this->fields['label'.$i] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
'label' => __('Labels'),
|
||||
'initial' => $initial,
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 50,
|
||||
'size' => 20,
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean the attachments post failure.
|
||||
*/
|
||||
function failed()
|
||||
{
|
||||
$upload_path = Pluf::f('upload_issue_path', false);
|
||||
if ($upload_path == false) return;
|
||||
for ($i=1;$i<4;$i++) {
|
||||
if (!empty($this->cleaned_data['attachment'.$i]) and
|
||||
file_exists($upload_path.'/'.$this->cleaned_data['attachment'.$i])) {
|
||||
@unlink($upload_path.'/'.$this->cleaned_data['attachment'.$i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function clean_content()
|
||||
{
|
||||
$content = trim($this->cleaned_data['content']);
|
||||
if (!$this->show_full and strlen($content) == 0) {
|
||||
throw new Pluf_Form_Invalid(__('You need to provide a description of the issue.'));
|
||||
}
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* We check that something is really changed.
|
||||
*/
|
||||
public function clean()
|
||||
{
|
||||
$this->cleaned_data = parent::clean();
|
||||
|
||||
// normalize the user's input by removing dublettes and by combining
|
||||
// ids from identical verbs in different input fields into one array
|
||||
$normRelatedIssues = array();
|
||||
for ($idx = 0; isset($this->cleaned_data['relation_type'.$idx]); ++$idx) {
|
||||
$verb = $this->cleaned_data['relation_type'.$idx];
|
||||
if (empty($verb))
|
||||
continue;
|
||||
|
||||
$ids = preg_split('/\s*,\s*/', $this->cleaned_data['relation_issue'.$idx],
|
||||
-1, PREG_SPLIT_NO_EMPTY);
|
||||
if (count($ids) == 0)
|
||||
continue;
|
||||
|
||||
if (!array_key_exists($verb, $normRelatedIssues))
|
||||
$normRelatedIssues[$verb] = array();
|
||||
foreach ($ids as $id) {
|
||||
if (!in_array($id, $normRelatedIssues[$verb]))
|
||||
$normRelatedIssues[$verb][] = $id;
|
||||
}
|
||||
}
|
||||
|
||||
// now look at any added / removed ids
|
||||
$added = $removed = array();
|
||||
$relatedIssues = $this->issue->getGroupedRelatedIssues(array(), true);
|
||||
$added = array_diff_key($normRelatedIssues, $relatedIssues);
|
||||
$removed = array_diff_key($relatedIssues, $normRelatedIssues);
|
||||
|
||||
$keysToLookAt = array_keys(
|
||||
array_intersect_key($relatedIssues, $normRelatedIssues)
|
||||
);
|
||||
foreach ($keysToLookAt as $key) {
|
||||
$a = array_diff($normRelatedIssues[$key], $relatedIssues[$key]);
|
||||
if (count($a) > 0)
|
||||
$added[$key] = $a;
|
||||
$r = array_diff($relatedIssues[$key], $normRelatedIssues[$key]);
|
||||
if (count($r) > 0)
|
||||
$removed[$key] = $r;
|
||||
}
|
||||
|
||||
// cache the added / removed data, so we do not have to
|
||||
// calculate that again
|
||||
$this->cleaned_data['_added_issue_relations'] = $added;
|
||||
$this->cleaned_data['_removed_issue_relations'] = $removed;
|
||||
|
||||
// As soon as we know that at least one change was done, we
|
||||
// return the cleaned data and do not go further.
|
||||
if (strlen(trim($this->cleaned_data['content']))) {
|
||||
return $this->cleaned_data;
|
||||
}
|
||||
if ($this->show_full) {
|
||||
$status = $this->issue->get_status();
|
||||
if (trim($this->cleaned_data['status']) != $status->name) {
|
||||
return $this->cleaned_data;
|
||||
}
|
||||
if (trim($this->issue->summary) != trim($this->cleaned_data['summary'])) {
|
||||
return $this->cleaned_data;
|
||||
}
|
||||
$owner = self::findUser($this->cleaned_data['owner']);
|
||||
if ((is_null($owner) and !is_null($this->issue->get_owner()))
|
||||
or (!is_null($owner) and is_null($this->issue->get_owner()))
|
||||
or ((!is_null($owner) and !is_null($this->issue->get_owner())) and $owner->id != $this->issue->get_owner()->id)) {
|
||||
return $this->cleaned_data;
|
||||
}
|
||||
$tags = array();
|
||||
for ($i=1;$i<7;$i++) {
|
||||
if (strlen($this->cleaned_data['label'.$i]) > 0) {
|
||||
if (strpos($this->cleaned_data['label'.$i], ':') !== false) {
|
||||
list($class, $name) = explode(':', $this->cleaned_data['label'.$i], 2);
|
||||
list($class, $name) = array(trim($class), trim($name));
|
||||
} else {
|
||||
$class = 'Other';
|
||||
$name = trim($this->cleaned_data['label'.$i]);
|
||||
}
|
||||
$tags[] = array($class, $name);
|
||||
}
|
||||
}
|
||||
$oldtags = $this->issue->get_tags_list();
|
||||
foreach ($tags as $tag) {
|
||||
$found = false;
|
||||
foreach ($oldtags as $otag) {
|
||||
if ($otag->class == $tag[0] and $otag->name == $tag[1]) {
|
||||
$found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!$found) {
|
||||
// new tag not found in the old tags
|
||||
return $this->cleaned_data;
|
||||
}
|
||||
}
|
||||
foreach ($oldtags as $otag) {
|
||||
$found = false;
|
||||
foreach ($tags as $tag) {
|
||||
if ($otag->class == $tag[0] and $otag->name == $tag[1]) {
|
||||
$found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!$found) {
|
||||
// old tag not found in the new tags
|
||||
return $this->cleaned_data;
|
||||
}
|
||||
}
|
||||
|
||||
if (count($this->cleaned_data['_added_issue_relations']) != 0 ||
|
||||
count($this->cleaned_data['_removed_issue_relations']) != 0) {
|
||||
return $this->cleaned_data;
|
||||
}
|
||||
}
|
||||
// no changes!
|
||||
throw new Pluf_Form_Invalid(__('No changes were entered.'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the model in the database.
|
||||
*
|
||||
* @param bool Commit in the database or not. If not, the object
|
||||
* is returned but not saved in the database.
|
||||
* @return Object Model with data set from the form.
|
||||
*/
|
||||
function save($commit=true)
|
||||
{
|
||||
if (!$this->isValid()) {
|
||||
throw new Exception(__('Cannot save the model from an invalid form.'));
|
||||
}
|
||||
if ($this->show_full) {
|
||||
// Add a tag for each label
|
||||
$tags = array();
|
||||
$tagids = array();
|
||||
for ($i=1;$i<7;$i++) {
|
||||
if (strlen($this->cleaned_data['label'.$i]) > 0) {
|
||||
if (strpos($this->cleaned_data['label'.$i], ':') !== false) {
|
||||
list($class, $name) = explode(':', $this->cleaned_data['label'.$i], 2);
|
||||
list($class, $name) = array(trim($class), trim($name));
|
||||
} else {
|
||||
$class = 'Other';
|
||||
$name = trim($this->cleaned_data['label'.$i]);
|
||||
}
|
||||
$tag = IDF_Tag::add($name, $this->project, $class);
|
||||
$tags[] = $tag;
|
||||
$tagids[] = $tag->id;
|
||||
}
|
||||
}
|
||||
// Compare between the old and the new data
|
||||
$changes = array();
|
||||
$oldtags = $this->issue->get_tags_list();
|
||||
foreach ($tags as $tag) {
|
||||
if (!Pluf_Model_InArray($tag, $oldtags)) {
|
||||
if (!isset($changes['lb'])) $changes['lb'] = array();
|
||||
if (!isset($changes['lb']['add'])) $changes['lb']['add'] = array();
|
||||
if ($tag->class != 'Other') {
|
||||
$changes['lb']['add'][] = (string) $tag; //new tag
|
||||
} else {
|
||||
$changes['lb']['add'][] = (string) $tag->name;
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach ($oldtags as $tag) {
|
||||
if (!Pluf_Model_InArray($tag, $tags)) {
|
||||
if (!isset($changes['lb'])) $changes['lb'] = array();
|
||||
if (!isset($changes['lb']['rem'])) $changes['lb']['rem'] = array();
|
||||
if ($tag->class != 'Other') {
|
||||
$changes['lb']['rem'][] = (string) $tag; //new tag
|
||||
} else {
|
||||
$changes['lb']['rem'][] = (string) $tag->name;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Status, summary and owner
|
||||
$status = IDF_Tag::add(trim($this->cleaned_data['status']), $this->project, 'Status');
|
||||
if ($status->id != $this->issue->status) {
|
||||
$changes['st'] = $status->name;
|
||||
}
|
||||
if (trim($this->issue->summary) != trim($this->cleaned_data['summary'])) {
|
||||
$changes['su'] = trim($this->cleaned_data['summary']);
|
||||
}
|
||||
$owner = self::findUser($this->cleaned_data['owner']);
|
||||
if ((is_null($owner) and !is_null($this->issue->get_owner()))
|
||||
or (!is_null($owner) and is_null($this->issue->get_owner()))
|
||||
or ((!is_null($owner) and !is_null($this->issue->get_owner())) and $owner->id != $this->issue->get_owner()->id)) {
|
||||
$changes['ow'] = (is_null($owner)) ? '---' : $owner->login;
|
||||
}
|
||||
// Issue relations - additions
|
||||
foreach ($this->cleaned_data['_added_issue_relations'] as $verb => $ids) {
|
||||
$other_verb = $this->relation_types[$verb];
|
||||
foreach ($ids as $id) {
|
||||
$related_issue = new IDF_Issue($id);
|
||||
$rel = new IDF_IssueRelation();
|
||||
$rel->issue = $this->issue;
|
||||
$rel->verb = $verb;
|
||||
$rel->other_issue = $related_issue;
|
||||
$rel->submitter = $this->user;
|
||||
$rel->create();
|
||||
|
||||
$other_rel = new IDF_IssueRelation();
|
||||
$other_rel->issue = $related_issue;
|
||||
$other_rel->verb = $other_verb;
|
||||
$other_rel->other_issue = $this->issue;
|
||||
$other_rel->submitter = $this->user;
|
||||
$other_rel->create();
|
||||
}
|
||||
if (!isset($changes['rel'])) $changes['rel'] = array();
|
||||
if (!isset($changes['rel']['add'])) $changes['rel']['add'] = array();
|
||||
$changes['rel']['add'][] = $verb.' '.implode(', ', $ids);
|
||||
}
|
||||
// Issue relations - removals
|
||||
foreach ($this->cleaned_data['_removed_issue_relations'] as $verb => $ids) {
|
||||
foreach ($ids as $id) {
|
||||
$db = &Pluf::db();
|
||||
$table = Pluf::factory('IDF_IssueRelation')->getSqlTable();
|
||||
$sql = new Pluf_SQL('verb=%s AND (
|
||||
(issue=%s AND other_issue=%s) OR
|
||||
(other_issue=%s AND issue=%s))',
|
||||
array($verb,
|
||||
$this->issue->id, $id,
|
||||
$this->issue->id, $id));
|
||||
$db->execute('DELETE FROM '.$table.' WHERE '.$sql->gen());
|
||||
}
|
||||
|
||||
if (!isset($changes['rel'])) $changes['rel'] = array();
|
||||
if (!isset($changes['rel']['rem'])) $changes['rel']['rem'] = array();
|
||||
$changes['rel']['rem'][] = $verb.' '.implode(', ', $ids);
|
||||
}
|
||||
// Update the issue
|
||||
$this->issue->batchAssoc('IDF_Tag', $tagids);
|
||||
$this->issue->summary = trim($this->cleaned_data['summary']);
|
||||
$this->issue->status = $status;
|
||||
$this->issue->owner = $owner;
|
||||
}
|
||||
// Create the comment
|
||||
$comment = new IDF_IssueComment();
|
||||
$comment->issue = $this->issue;
|
||||
$comment->content = $this->cleaned_data['content'];
|
||||
$comment->submitter = $this->user;
|
||||
if (!$this->show_full) $changes = array();
|
||||
$comment->changes = $changes;
|
||||
$comment->create();
|
||||
$this->issue->update();
|
||||
if ($this->issue->owner != $this->user->id and
|
||||
$this->issue->submitter != $this->user->id) {
|
||||
$this->issue->setAssoc($this->user); // interested user.
|
||||
}
|
||||
$attached_files = array();
|
||||
for ($i=1;$i<4;$i++) {
|
||||
if ($this->cleaned_data['attachment'.$i]) {
|
||||
$file = new IDF_IssueFile();
|
||||
$file->attachment = $this->cleaned_data['attachment'.$i];
|
||||
$file->submitter = $this->user;
|
||||
$file->comment = $comment;
|
||||
$file->create();
|
||||
$attached_files[] = $file;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* [signal]
|
||||
*
|
||||
* IDF_Issue::update
|
||||
*
|
||||
* [sender]
|
||||
*
|
||||
* IDF_Form_IssueUpdate
|
||||
*
|
||||
* [description]
|
||||
*
|
||||
* This signal allows an application to perform a set of tasks
|
||||
* just after the update of an issue.
|
||||
*
|
||||
* [parameters]
|
||||
*
|
||||
* array('issue' => $issue,
|
||||
* 'comment' => $comment,
|
||||
* 'files' => $attached_files);
|
||||
*
|
||||
*/
|
||||
$params = array('issue' => $this->issue,
|
||||
'comment' => $comment,
|
||||
'files' => $attached_files);
|
||||
Pluf_Signal::send('IDF_Issue::update', 'IDF_Form_IssueUpdate',
|
||||
$params);
|
||||
|
||||
return $this->issue;
|
||||
}
|
||||
}
|
138
indefero/src/IDF/Form/MembersConf.php
Normal file
138
indefero/src/IDF/Form/MembersConf.php
Normal file
@@ -0,0 +1,138 @@
|
||||
<?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-2011 Céondo Ltd and contributors.
|
||||
#
|
||||
# InDefero is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# InDefero is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# ***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
/**
|
||||
* Configuration of the members.
|
||||
*
|
||||
* To simplify the management. Instead of being obliged to go through
|
||||
* a list of people and then select the rights member/owner, I am
|
||||
* using the same approach as googlecode, that is, asking for the
|
||||
* login. This makes the interface simpler and simplicity is king.
|
||||
*
|
||||
* In background, the row permission framework is used to give the
|
||||
* member/owner permission to the given project to the users.
|
||||
*/
|
||||
class IDF_Form_MembersConf extends Pluf_Form
|
||||
{
|
||||
public $project = null;
|
||||
|
||||
public function initFields($extra=array())
|
||||
{
|
||||
$this->project = $extra['project'];
|
||||
|
||||
$this->fields['owners'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
'label' => __('Project owners'),
|
||||
'initial' => '',
|
||||
'widget' => 'Pluf_Form_Widget_TextareaInput',
|
||||
'widget_attrs' => array('rows' => 5,
|
||||
'cols' => 40),
|
||||
));
|
||||
$this->fields['members'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
'label' => __('Project members'),
|
||||
'widget_attrs' => array('rows' => 7,
|
||||
'cols' => 40),
|
||||
'widget' => 'Pluf_Form_Widget_TextareaInput',
|
||||
));
|
||||
}
|
||||
|
||||
public function save($commit=true)
|
||||
{
|
||||
if (!$this->isValid()) {
|
||||
throw new Exception(__('Cannot save the model from an invalid form.'));
|
||||
}
|
||||
self::updateMemberships($this->project, $this->cleaned_data);
|
||||
$this->project->membershipsUpdated();
|
||||
}
|
||||
|
||||
public function clean_owners()
|
||||
{
|
||||
return self::checkBadLogins($this->cleaned_data['owners']);
|
||||
}
|
||||
|
||||
public function clean_members()
|
||||
{
|
||||
return self::checkBadLogins($this->cleaned_data['members']);
|
||||
}
|
||||
|
||||
/**
|
||||
* From the input, find the bad logins.
|
||||
*
|
||||
* @throws Pluf_Form_Invalid exception when bad logins are found
|
||||
* @param string Comma, new line delimited list of logins
|
||||
* @return string Comma, new line delimited list of logins
|
||||
*/
|
||||
public static function checkBadLogins($logins)
|
||||
{
|
||||
$bad = array();
|
||||
foreach (preg_split("/\015\012|\015|\012|\,/", $logins, -1, PREG_SPLIT_NO_EMPTY) as $login) {
|
||||
$sql = new Pluf_SQL('login=%s', array(trim($login)));
|
||||
try {
|
||||
$user = Pluf::factory('Pluf_User')->getOne(array('filter'=>$sql->gen()));
|
||||
if (null == $user) {
|
||||
$bad[] = $login;
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$bad[] = $login;
|
||||
}
|
||||
}
|
||||
$n = count($bad);
|
||||
if ($n) {
|
||||
$badlogins = Pluf_esc(implode(', ', $bad));
|
||||
throw new Pluf_Form_Invalid(sprintf(_n('The following login is invalid: %s.', 'The following logins are invalid: %s.', $n), $badlogins));
|
||||
}
|
||||
return $logins;
|
||||
}
|
||||
|
||||
/**
|
||||
* The update of the memberships is done in different places. This
|
||||
* avoids duplicating code.
|
||||
*
|
||||
* @param IDF_Project The project
|
||||
* @param array The new memberships data in 'owners' and 'members' keys
|
||||
*/
|
||||
public static function updateMemberships($project, $cleaned_data)
|
||||
{
|
||||
// remove all the permissions
|
||||
$cm = $project->getMembershipData();
|
||||
$def = array('owners' => Pluf_Permission::getFromString('IDF.project-owner'),
|
||||
'members' => Pluf_Permission::getFromString('IDF.project-member'));
|
||||
$guser = new Pluf_User();
|
||||
foreach ($def as $key=>$perm) {
|
||||
foreach ($cm[$key] as $user) {
|
||||
Pluf_RowPermission::remove($user, $project, $perm);
|
||||
}
|
||||
foreach (preg_split("/\015\012|\015|\012|\,/", $cleaned_data[$key], -1, PREG_SPLIT_NO_EMPTY) as $login) {
|
||||
$sql = new Pluf_SQL('login=%s', array(trim($login)));
|
||||
$users = $guser->getList(array('filter'=>$sql->gen()));
|
||||
if ($users->count() == 1) {
|
||||
Pluf_RowPermission::add($users[0], $project, $perm);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
112
indefero/src/IDF/Form/Password.php
Normal file
112
indefero/src/IDF/Form/Password.php
Normal file
@@ -0,0 +1,112 @@
|
||||
<?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-2011 Céondo Ltd and contributors.
|
||||
#
|
||||
# InDefero is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# InDefero is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/**
|
||||
* Ask a password recovery.
|
||||
*
|
||||
*/
|
||||
class IDF_Form_Password extends Pluf_Form
|
||||
{
|
||||
public function initFields($extra=array())
|
||||
{
|
||||
$this->fields['account'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Your login or email'),
|
||||
'help_text' => __('Provide either your login or your email to recover your password.'),
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that a user with this login or email exists.
|
||||
*/
|
||||
public function clean_account()
|
||||
{
|
||||
$account = mb_strtolower(trim($this->cleaned_data['account']));
|
||||
$sql = new Pluf_SQL('email=%s OR login=%s',
|
||||
array($account, $account));
|
||||
$users = Pluf::factory('Pluf_User')->getList(array('filter'=>$sql->gen()));
|
||||
if ($users->count() == 0) {
|
||||
throw new Pluf_Form_Invalid(__('Sorry, we cannot find a user with this email address or login. Feel free to try again.'));
|
||||
}
|
||||
$ok = false;
|
||||
foreach ($users as $user) {
|
||||
if ($user->active) {
|
||||
$ok = true;
|
||||
continue;
|
||||
}
|
||||
if (!$user->active and $user->first_name == '---') {
|
||||
$ok = true;
|
||||
continue;
|
||||
}
|
||||
$ok = false; // This ensures an all or nothing ok.
|
||||
}
|
||||
if (!$ok) {
|
||||
throw new Pluf_Form_Invalid(__('Sorry, we cannot find a user with this email address or login. Feel free to try again.'));
|
||||
}
|
||||
return $account;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the reminder email.
|
||||
*
|
||||
*/
|
||||
function save($commit=true)
|
||||
{
|
||||
if (!$this->isValid()) {
|
||||
throw new Exception(__('Cannot save the model from an invalid form.'));
|
||||
}
|
||||
$account = $this->cleaned_data['account'];
|
||||
$sql = new Pluf_SQL('email=%s OR login=%s',
|
||||
array($account, $account));
|
||||
$users = Pluf::factory('Pluf_User')->getList(array('filter'=>$sql->gen()));
|
||||
|
||||
$return_url = '';
|
||||
foreach ($users as $user) {
|
||||
if ($user->active) {
|
||||
$return_url = Pluf_HTTP_URL_urlForView('IDF_Views::passwordRecoveryInputCode');
|
||||
$tmpl = new Pluf_Template('idf/user/passrecovery-email.txt');
|
||||
$cr = new Pluf_Crypt(md5(Pluf::f('secret_key')));
|
||||
$code = trim($cr->encrypt($user->email.':'.$user->id.':'.time().':primary'),
|
||||
'~');
|
||||
$code = substr(md5(Pluf::f('secret_key').$code), 0, 2).$code;
|
||||
$url = Pluf::f('url_base').Pluf_HTTP_URL_urlForView('IDF_Views::passwordRecovery', array($code), array(), false);
|
||||
$urlic = Pluf::f('url_base').Pluf_HTTP_URL_urlForView('IDF_Views::passwordRecoveryInputCode', array(), array(), false);
|
||||
$context = new Pluf_Template_Context(
|
||||
array('url' => Pluf_Template::markSafe($url),
|
||||
'urlik' => Pluf_Template::markSafe($urlic),
|
||||
'user' => Pluf_Template::markSafe($user),
|
||||
'key' => Pluf_Template::markSafe($code)));
|
||||
$email = new Pluf_Mail(Pluf::f('from_email'), $user->email,
|
||||
__('Password Recovery - InDefero'));
|
||||
$email->setReturnPath(Pluf::f('bounce_email', Pluf::f('from_email')));
|
||||
$email->addTextMessage($tmpl->render($context));
|
||||
$email->sendMail();
|
||||
}
|
||||
if (!$user->active and $user->first_name == '---') {
|
||||
$return_url = Pluf_HTTP_URL_urlForView('IDF_Views::registerInputKey');
|
||||
IDF_Form_Register::sendVerificationEmail($user);
|
||||
}
|
||||
}
|
||||
return $return_url;
|
||||
}
|
||||
}
|
104
indefero/src/IDF/Form/PasswordInputKey.php
Normal file
104
indefero/src/IDF/Form/PasswordInputKey.php
Normal file
@@ -0,0 +1,104 @@
|
||||
<?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-2011 Céondo Ltd and contributors.
|
||||
#
|
||||
# InDefero is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# InDefero is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# ***** END LICENSE BLOCK ***** */
|
||||
|
||||
Pluf::loadFunction('Pluf_HTTP_URL_urlForView');
|
||||
|
||||
/**
|
||||
* Check the validity of a confirmation key to reset a password.
|
||||
*
|
||||
*/
|
||||
class IDF_Form_PasswordInputKey extends Pluf_Form
|
||||
{
|
||||
public function initFields($extra=array())
|
||||
{
|
||||
$this->fields['key'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Your verification key'),
|
||||
'initial' => '',
|
||||
'widget_attrs' => array(
|
||||
'size' => 50,
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the key.
|
||||
*/
|
||||
public function clean_key()
|
||||
{
|
||||
$this->cleaned_data['key'] = trim($this->cleaned_data['key']);
|
||||
$error = __('We are sorry but this validation key is not valid. Maybe you should directly copy/paste it from your validation email.');
|
||||
if (false === ($cres=self::checkKeyHash($this->cleaned_data['key']))) {
|
||||
throw new Pluf_Form_Invalid($error);
|
||||
}
|
||||
$guser = new Pluf_User();
|
||||
$sql = new Pluf_SQL('email=%s AND id=%s',
|
||||
array($cres[0], $cres[1]));
|
||||
if ($guser->getCount(array('filter' => $sql->gen())) != 1) {
|
||||
throw new Pluf_Form_Invalid($error);
|
||||
}
|
||||
if ((time() - $cres[2]) > 86400) {
|
||||
throw new Pluf_Form_Invalid(__('Sorry, but this verification key has expired, please restart the password recovery sequence. For security reasons, the verification key is only valid 24h.'));
|
||||
}
|
||||
return $this->cleaned_data['key'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the model in the database.
|
||||
*
|
||||
* @param bool Commit in the database or not. If not, the object
|
||||
* is returned but not saved in the database.
|
||||
* @return string Url to redirect to the form.
|
||||
*/
|
||||
function save($commit=true)
|
||||
{
|
||||
if (!$this->isValid()) {
|
||||
throw new Exception(__('Cannot save an invalid form.'));
|
||||
}
|
||||
return Pluf_HTTP_URL_urlForView('IDF_Views::passwordRecovery',
|
||||
array($this->cleaned_data['key']));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return false or an array with the email, id and timestamp.
|
||||
*
|
||||
* This is a static function to be reused by other forms.
|
||||
*
|
||||
* @param string Confirmation key
|
||||
* @return mixed Either false or array(email, id, timestamp)
|
||||
*/
|
||||
public static function checkKeyHash($key)
|
||||
{
|
||||
$hash = substr($key, 0, 2);
|
||||
$encrypted = substr($key, 2);
|
||||
if ($hash != substr(md5(Pluf::f('secret_key').$encrypted), 0, 2)) {
|
||||
return false;
|
||||
}
|
||||
$cr = new Pluf_Crypt(md5(Pluf::f('secret_key')));
|
||||
$f = explode(':', $cr->decrypt($encrypted), 3);
|
||||
if (count($f) != 3) {
|
||||
return false;
|
||||
}
|
||||
return $f;
|
||||
}
|
||||
}
|
138
indefero/src/IDF/Form/PasswordReset.php
Normal file
138
indefero/src/IDF/Form/PasswordReset.php
Normal file
@@ -0,0 +1,138 @@
|
||||
<?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-2011 Céondo Ltd and contributors.
|
||||
#
|
||||
# InDefero is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# InDefero is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# ***** END LICENSE BLOCK ***** */
|
||||
|
||||
Pluf::loadFunction('Pluf_HTTP_URL_urlForView');
|
||||
|
||||
/**
|
||||
* Reset the password of a user.
|
||||
*
|
||||
*/
|
||||
class IDF_Form_PasswordReset extends Pluf_Form
|
||||
{
|
||||
protected $user = null;
|
||||
|
||||
public function initFields($extra=array())
|
||||
{
|
||||
$this->user = $extra['user'];
|
||||
$this->fields['key'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Your verification key'),
|
||||
'initial' => $extra['key'],
|
||||
'widget' => 'Pluf_Form_Widget_HiddenInput',
|
||||
));
|
||||
$this->fields['password'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Your password'),
|
||||
'initial' => '',
|
||||
'widget' => 'Pluf_Form_Widget_PasswordInput',
|
||||
'help_text' => __('Your password must be hard for other people to find it, but easy for you to remember.'),
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 50,
|
||||
'size' => 15,
|
||||
),
|
||||
));
|
||||
$this->fields['password2'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Confirm your password'),
|
||||
'initial' => '',
|
||||
'widget' => 'Pluf_Form_Widget_PasswordInput',
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 50,
|
||||
'size' => 15,
|
||||
),
|
||||
));
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the passwords.
|
||||
*/
|
||||
public function clean()
|
||||
{
|
||||
if ($this->cleaned_data['password'] != $this->cleaned_data['password2']) {
|
||||
throw new Pluf_Form_Invalid(__('The two passwords must be the same.'));
|
||||
}
|
||||
if (!$this->user->active) {
|
||||
throw new Pluf_Form_Invalid(__('This account is not active. Please contact the forge administrator to activate it.'));
|
||||
}
|
||||
return $this->cleaned_data;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Validate the key.
|
||||
*/
|
||||
public function clean_key()
|
||||
{
|
||||
$this->cleaned_data['key'] = trim($this->cleaned_data['key']);
|
||||
$error = __('We are sorry but this validation key is not valid. Maybe you should directly copy/paste it from your validation email.');
|
||||
if (false === ($cres=IDF_Form_PasswordInputKey::checkKeyHash($this->cleaned_data['key']))) {
|
||||
throw new Pluf_Form_Invalid($error);
|
||||
}
|
||||
$guser = new Pluf_User();
|
||||
$sql = new Pluf_SQL('email=%s AND id=%s',
|
||||
array($cres[0], $cres[1]));
|
||||
if ($guser->getCount(array('filter' => $sql->gen())) != 1) {
|
||||
throw new Pluf_Form_Invalid($error);
|
||||
}
|
||||
if ((time() - $cres[2]) > 86400) {
|
||||
throw new Pluf_Form_Invalid(__('Sorry, but this verification key has expired, please restart the password recovery sequence. For security reasons, the verification key is only valid 24h.'));
|
||||
}
|
||||
return $this->cleaned_data['key'];
|
||||
}
|
||||
|
||||
function save($commit=true)
|
||||
{
|
||||
if (!$this->isValid()) {
|
||||
throw new Exception(__('Cannot save an invalid form.'));
|
||||
}
|
||||
$this->user->setFromFormData($this->cleaned_data);
|
||||
if ($commit) {
|
||||
$this->user->update();
|
||||
/**
|
||||
* [signal]
|
||||
*
|
||||
* Pluf_User::passwordUpdated
|
||||
*
|
||||
* [sender]
|
||||
*
|
||||
* IDF_Form_PasswordReset
|
||||
*
|
||||
* [description]
|
||||
*
|
||||
* This signal is sent when the user reset his
|
||||
* password from the password recovery page.
|
||||
*
|
||||
* [parameters]
|
||||
*
|
||||
* array('user' => $user)
|
||||
*
|
||||
*/
|
||||
$params = array('user' => $this->user);
|
||||
Pluf_Signal::send('Pluf_User::passwordUpdated',
|
||||
'IDF_Form_PasswordReset', $params);
|
||||
}
|
||||
return $this->user;
|
||||
}
|
||||
}
|
231
indefero/src/IDF/Form/ProjectConf.php
Normal file
231
indefero/src/IDF/Form/ProjectConf.php
Normal file
@@ -0,0 +1,231 @@
|
||||
<?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-2011 Céondo Ltd and contributors.
|
||||
#
|
||||
# InDefero is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
#(at your option) any later version.
|
||||
#
|
||||
# InDefero is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# ***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
/**
|
||||
* Configuration of the project.
|
||||
*/
|
||||
class IDF_Form_ProjectConf extends Pluf_Form
|
||||
{
|
||||
public $project = null;
|
||||
|
||||
public function initFields($extra=array())
|
||||
{
|
||||
$this->project = $extra['project'];
|
||||
$this->user = $extra["user"];
|
||||
$conf = $this->project->getConf();
|
||||
|
||||
// Basic part
|
||||
$this->fields['name'] = new Pluf_Form_Field_Varchar(array('required' => true,
|
||||
'label' => __('Name'),
|
||||
'initial' => $this->project->name,
|
||||
));
|
||||
$this->fields['shortdesc'] = new Pluf_Form_Field_Varchar(array('required' => true,
|
||||
'label' => __('Short Description'),
|
||||
'initial' => $this->project->shortdesc,
|
||||
'widget_attrs' => array('size' => '68'),
|
||||
));
|
||||
$this->fields['description'] = new Pluf_Form_Field_Varchar(array('required' => true,
|
||||
'label' => __('Description'),
|
||||
'initial' => $this->project->description,
|
||||
'widget_attrs' => array('cols' => 68,
|
||||
'rows' => 26,
|
||||
),
|
||||
'widget' => 'Pluf_Form_Widget_TextareaInput',
|
||||
));
|
||||
$this->fields['external_project_url'] = new Pluf_Form_Field_Varchar(array('required' => false,
|
||||
'label' => __('External URL'),
|
||||
'widget_attrs' => array('size' => '68'),
|
||||
'initial' => $conf->getVal('external_project_url'),
|
||||
|
||||
));
|
||||
if ($this->user->administrator)
|
||||
{
|
||||
$this->fields['enableads'] = new Pluf_Form_Field_Boolean(
|
||||
array('required' => false,
|
||||
'label' => __('Enable advertising'),
|
||||
'initial' => $this->project->enableads,
|
||||
'widget' => 'Pluf_Form_Widget_CheckboxInput',
|
||||
));
|
||||
} else {
|
||||
$this->fields['enableads'] = new Pluf_Form_Field_Boolean(
|
||||
array('required' => false,
|
||||
'label' => __('Enable advertising'),
|
||||
'initial' => $this->project->enableads,
|
||||
'widget' => 'Pluf_Form_Widget_CheckboxInput',
|
||||
'widget_attrs' => array('disabled' => 'disabled')
|
||||
));
|
||||
}
|
||||
$tags = $this->project->get_tags_list();
|
||||
for ($i=1;$i<7;$i++) {
|
||||
$initial = '';
|
||||
if (isset($tags[$i-1])) {
|
||||
if ($tags[$i-1]->class != 'Other') {
|
||||
$initial = (string) $tags[$i-1];
|
||||
} else {
|
||||
$initial = $tags[$i-1]->name;
|
||||
}
|
||||
}
|
||||
$this->fields['label'.$i] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
'label' => __('Labels'),
|
||||
'initial' => $initial,
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 50,
|
||||
'size' => 20,
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
// Logo part
|
||||
$upload_path = Pluf::f('upload_path', false);
|
||||
if (false === $upload_path) {
|
||||
throw new Pluf_Exception_SettingError(__('The "upload_path" configuration variable was not set.'));
|
||||
}
|
||||
$upload_path .= '/' . $this->project->shortname;
|
||||
$filename = '/%s';
|
||||
$this->fields['logo'] = new Pluf_Form_Field_File(array('required' => false,
|
||||
'label' => __('Update the logo'),
|
||||
'initial' => '',
|
||||
'help_text' => __('The logo must be a picture with a size of 32 by 32.'),
|
||||
'max_size' => Pluf::f('max_upload_size', 5 * 1024),
|
||||
'move_function_params' =>
|
||||
array('upload_path' => $upload_path,
|
||||
'upload_path_create' => true,
|
||||
'upload_overwrite' => true,
|
||||
'file_name' => $filename,
|
||||
)
|
||||
));
|
||||
|
||||
$this->fields['logo_remove'] = new Pluf_Form_Field_Boolean(array('required' => false,
|
||||
'label' => __('Remove the current logo'),
|
||||
'initial' => false,
|
||||
'widget' => 'Pluf_Form_Widget_CheckboxInput',
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* If we have uploaded a file, but the form failed remove it.
|
||||
*
|
||||
*/
|
||||
function failed()
|
||||
{
|
||||
if (!empty($this->cleaned_data['logo'])
|
||||
&& file_exists(Pluf::f('upload_path').'/'.$this->cleaned_data['logo'])) {
|
||||
unlink(Pluf::f('upload_path').'/'.$this->cleaned_data['logo']);
|
||||
}
|
||||
}
|
||||
|
||||
public function clean()
|
||||
{
|
||||
if (!isset($this->cleaned_data['logo_remove'])) {
|
||||
$this->cleaned_data['logo_remove'] = false;
|
||||
}
|
||||
|
||||
return $this->cleaned_data;
|
||||
}
|
||||
|
||||
public function clean_logo()
|
||||
{
|
||||
if (empty($this->cleaned_data['logo'])) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$meta = getimagesize(Pluf::f('upload_path') . '/' . $this->project->shortname . $this->cleaned_data['logo']);
|
||||
|
||||
if ($meta === false) {
|
||||
throw new Pluf_Form_Invalid(__('Could not determine the size of the uploaded picture.'));
|
||||
}
|
||||
|
||||
if ($meta[0] !== 32 || $meta[1] !== 32) {
|
||||
throw new Pluf_Form_Invalid(__('The picture must have a size of 32 by 32.'));
|
||||
}
|
||||
|
||||
return $this->cleaned_data['logo'];
|
||||
}
|
||||
|
||||
public function clean_external_project_url()
|
||||
{
|
||||
return self::checkWebURL($this->cleaned_data['external_project_url']);
|
||||
}
|
||||
|
||||
public static function checkWebURL($url)
|
||||
{
|
||||
$url = trim($url);
|
||||
if (empty($url)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$parsed = parse_url($url);
|
||||
if ($parsed === false || !array_key_exists('scheme', $parsed) ||
|
||||
($parsed['scheme'] != 'http' && $parsed['scheme'] != 'https')) {
|
||||
throw new Pluf_Form_Invalid(__('The entered URL is invalid. Only http and https URLs are allowed.'));
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
public function save($commit=true)
|
||||
{
|
||||
// Add a tag for each label
|
||||
$tagids = array();
|
||||
for ($i=1;$i<7;$i++) {
|
||||
if (strlen($this->cleaned_data['label'.$i]) > 0) {
|
||||
if (strpos($this->cleaned_data['label'.$i], ':') !== false) {
|
||||
list($class, $name) = explode(':', $this->cleaned_data['label'.$i], 2);
|
||||
list($class, $name) = array(trim($class), trim($name));
|
||||
} else {
|
||||
$class = 'Other';
|
||||
$name = trim($this->cleaned_data['label'.$i]);
|
||||
}
|
||||
$tag = IDF_Tag::addGlobal($name, $class);
|
||||
$tagids[] = $tag->id;
|
||||
}
|
||||
}
|
||||
|
||||
// Basic part
|
||||
$this->project->name = $this->cleaned_data['name'];
|
||||
$this->project->shortdesc = $this->cleaned_data['shortdesc'];
|
||||
$this->project->description = $this->cleaned_data['description'];
|
||||
$this->project->batchAssoc('IDF_Tag', $tagids);
|
||||
if ($this->user->administrator)
|
||||
$this->project->enableads = $this->cleaned_data['enableads'];
|
||||
$this->project->update();
|
||||
|
||||
$conf = $this->project->getConf();
|
||||
if (!empty($this->cleaned_data['logo'])) {
|
||||
$conf->setVal('logo', $this->cleaned_data['logo']);
|
||||
}
|
||||
if (!empty($this->cleaned_data['external_project_url'])) {
|
||||
$conf->setVal('external_project_url', $this->cleaned_data['external_project_url']);
|
||||
}
|
||||
else {
|
||||
$conf->delVal('external_project_url');
|
||||
}
|
||||
|
||||
if ($this->cleaned_data['logo_remove'] === true) {
|
||||
@unlink(Pluf::f('upload_path') . '/' . $this->project->shortname . $conf->getVal('logo'));
|
||||
$conf->delVal('logo');
|
||||
}
|
||||
}
|
||||
}
|
165
indefero/src/IDF/Form/Register.php
Normal file
165
indefero/src/IDF/Form/Register.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) 2008-2011 Céondo Ltd and contributors.
|
||||
#
|
||||
# InDefero is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# InDefero is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/**
|
||||
* Create a new user account.
|
||||
*
|
||||
*/
|
||||
class IDF_Form_Register extends Pluf_Form
|
||||
{
|
||||
protected $request;
|
||||
|
||||
public function initFields($extra=array())
|
||||
{
|
||||
$this->request = $extra['request'];
|
||||
$login = '';
|
||||
if (isset($extra['initial']['login'])) {
|
||||
$login = $extra['initial']['login'];
|
||||
}
|
||||
$this->fields['login'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Your login'),
|
||||
'max_length' => 15,
|
||||
'min_length' => 3,
|
||||
'initial' => $login,
|
||||
'help_text' => __('The login must be between 3 and 15 characters long and contain only letters and digits.'),
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 15,
|
||||
'size' => 10,
|
||||
),
|
||||
));
|
||||
$this->fields['email'] = new Pluf_Form_Field_Email(
|
||||
array('required' => true,
|
||||
'label' => __('Your email'),
|
||||
'initial' => '',
|
||||
'help_text' => __('We will never send you any unsolicited emails. We hate spam too!'),
|
||||
));
|
||||
|
||||
$this->fields['regkey'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Registration Key'),
|
||||
'initial' => '',
|
||||
'help_text' => __('Please enter the key given to you by adamsna[at]datanethost.net'),
|
||||
));
|
||||
|
||||
$this->fields['terms'] = new Pluf_Form_Field_Boolean(
|
||||
array('required' => true,
|
||||
'label' => __('I agree to the terms and conditions.'),
|
||||
'initial' => '',
|
||||
));
|
||||
}
|
||||
|
||||
public function clean_regkey()
|
||||
{
|
||||
if ($this->cleaned_data['regkey'] != "2rv9o4nb5")
|
||||
throw new Pluf_Form_Invalid("The regkey was incorrect - please contact Nathan for the key!");
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the interconnection in the form.
|
||||
*/
|
||||
public function clean_login()
|
||||
{
|
||||
$this->cleaned_data['login'] = mb_strtolower(trim($this->cleaned_data['login']));
|
||||
if (preg_match('/[^A-Za-z0-9]/', $this->cleaned_data['login'])) {
|
||||
throw new Pluf_Form_Invalid(sprintf(__('The login "%s" can only contain letters and digits.'), $this->cleaned_data['login']));
|
||||
}
|
||||
$guser = new Pluf_User();
|
||||
$sql = new Pluf_SQL('login=%s', $this->cleaned_data['login']);
|
||||
if ($guser->getCount(array('filter' => $sql->gen())) > 0) {
|
||||
throw new Pluf_Form_Invalid(sprintf(__('The login "%s" is already used, please find another one.'), $this->cleaned_data['login']));
|
||||
}
|
||||
return $this->cleaned_data['login'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the terms.
|
||||
*/
|
||||
public function clean_terms()
|
||||
{
|
||||
if (!$this->cleaned_data['terms']) {
|
||||
throw new Pluf_Form_Invalid(__('We know, this is boring, but you need to agree with the terms and conditions.'));
|
||||
}
|
||||
return $this->cleaned_data['terms'];
|
||||
}
|
||||
|
||||
function clean_email()
|
||||
{
|
||||
$this->cleaned_data['email'] = mb_strtolower(trim($this->cleaned_data['email']));
|
||||
if (Pluf::factory('IDF_EmailAddress')->get_user_for_email_address($this->cleaned_data['email']) != null) {
|
||||
throw new Pluf_Form_Invalid(sprintf(__('The email "%1$s" is already used. If you need to, you can <a href="%2$s">recover your password</a>.'), $this->cleaned_data['email'], Pluf_HTTP_URL_urlForView('IDF_Views::passwordRecoveryAsk')));
|
||||
}
|
||||
return $this->cleaned_data['email'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the model in the database.
|
||||
*
|
||||
* @param bool Commit in the database or not. If not, the object
|
||||
* is returned but not saved in the database.
|
||||
* @return Object Model with data set from the form.
|
||||
*/
|
||||
function save($commit=true)
|
||||
{
|
||||
if (!$this->isValid()) {
|
||||
throw new Exception(__('Cannot save the model from an invalid form.'));
|
||||
}
|
||||
$user = new Pluf_User();
|
||||
$user->first_name = '---'; // with both this set and
|
||||
// active==false we can find later
|
||||
// on, all the unconfirmed accounts
|
||||
// that could be purged.
|
||||
$user->last_name = $this->cleaned_data['login'];
|
||||
$user->login = $this->cleaned_data['login'];
|
||||
$user->email = $this->cleaned_data['email'];
|
||||
$user->language = $this->request->language_code;
|
||||
$user->active = false;
|
||||
$user->create();
|
||||
self::sendVerificationEmail($user);
|
||||
return $user;
|
||||
}
|
||||
|
||||
public static function sendVerificationEmail($user)
|
||||
{
|
||||
Pluf::loadFunction('Pluf_HTTP_URL_urlForView');
|
||||
$from_email = Pluf::f('from_email');
|
||||
$cr = new Pluf_Crypt(md5(Pluf::f('secret_key')));
|
||||
$encrypted = trim($cr->encrypt($user->email.':'.$user->id), '~');
|
||||
$key = substr(md5(Pluf::f('secret_key').$encrypted), 0, 2).$encrypted;
|
||||
$url = Pluf::f('url_base').Pluf_HTTP_URL_urlForView('IDF_Views::registerConfirmation', array($key), array(), false);
|
||||
$urlik = Pluf::f('url_base').Pluf_HTTP_URL_urlForView('IDF_Views::registerInputKey', array(), array(), false);
|
||||
$context = new Pluf_Template_Context(
|
||||
array('key' => $key,
|
||||
'url' => $url,
|
||||
'urlik' => $urlik,
|
||||
'user'=> $user,
|
||||
)
|
||||
);
|
||||
$tmpl = new Pluf_Template('idf/register/confirmation-email.txt');
|
||||
$text_email = $tmpl->render($context);
|
||||
$email = new Pluf_Mail($from_email, $user->email,
|
||||
__('Confirm the creation of your account.'));
|
||||
$email->addTextMessage($text_email);
|
||||
$email->sendMail();
|
||||
}
|
||||
}
|
170
indefero/src/IDF/Form/RegisterConfirmation.php
Normal file
170
indefero/src/IDF/Form/RegisterConfirmation.php
Normal file
@@ -0,0 +1,170 @@
|
||||
<?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-2011 Céondo Ltd and contributors.
|
||||
#
|
||||
# InDefero is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# InDefero is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# ***** END LICENSE BLOCK ***** */
|
||||
|
||||
Pluf::loadFunction('Pluf_HTTP_URL_urlForView');
|
||||
|
||||
/**
|
||||
* Confirmation of the form.
|
||||
*
|
||||
*/
|
||||
class IDF_Form_RegisterConfirmation extends Pluf_Form
|
||||
{
|
||||
public $_user = null;
|
||||
|
||||
public function initFields($extra=array())
|
||||
{
|
||||
$this->_user = $extra['user'];
|
||||
|
||||
$this->fields['key'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Your confirmation key'),
|
||||
'initial' => $extra['key'],
|
||||
'widget' => 'Pluf_Form_Widget_HiddenInput',
|
||||
'widget_attrs' => array(
|
||||
'readonly' => 'readonly',
|
||||
),
|
||||
|
||||
));
|
||||
$this->fields['first_name'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
'label' => __('First name'),
|
||||
'initial' => '',
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 50,
|
||||
'size' => 15,
|
||||
),
|
||||
));
|
||||
$this->fields['last_name'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Last name'),
|
||||
'initial' => '',
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 50,
|
||||
'size' => 15,
|
||||
),
|
||||
));
|
||||
|
||||
$this->fields['password'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Your password'),
|
||||
'initial' => '',
|
||||
'widget' => 'Pluf_Form_Widget_PasswordInput',
|
||||
'help_text' => __('Your password must be hard for other people to guess, but easy for you to remember.'),
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 50,
|
||||
'size' => 15,
|
||||
),
|
||||
));
|
||||
$this->fields['password2'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Confirm your password'),
|
||||
'initial' => '',
|
||||
'widget' => 'Pluf_Form_Widget_PasswordInput',
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 50,
|
||||
'size' => 15,
|
||||
),
|
||||
));
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Just a simple control.
|
||||
*/
|
||||
public function clean_key()
|
||||
{
|
||||
$this->cleaned_data['key'] = trim($this->cleaned_data['key']);
|
||||
$error = __('We are sorry but this confirmation key is not valid. Maybe you should directly copy/paste it from your confirmation email.');
|
||||
if (false === ($email_id=IDF_Form_RegisterInputKey::checkKeyHash($this->cleaned_data['key']))) {
|
||||
throw new Pluf_Form_Invalid($error);
|
||||
}
|
||||
$guser = new Pluf_User();
|
||||
$sql = new Pluf_SQL('email=%s AND id=%s', $email_id);
|
||||
$users = $guser->getList(array('filter' => $sql->gen()));
|
||||
if ($users->count() != 1) {
|
||||
throw new Pluf_Form_Invalid($error);
|
||||
}
|
||||
if ($users[0]->active) {
|
||||
throw new Pluf_Form_Invalid(sprintf(__('This account has already been confirmed. Maybe should you try to <a href="%s">recover your password</a>.'), Pluf_HTTP_URL_urlForView('IDF_Views::passwordRecoveryAsk')));
|
||||
}
|
||||
$this->_user_id = $email_id[1];
|
||||
return $this->cleaned_data['key'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the passwords.
|
||||
*/
|
||||
public function clean()
|
||||
{
|
||||
if ($this->cleaned_data['password'] != $this->cleaned_data['password2']) {
|
||||
throw new Pluf_Form_Invalid(__('The two passwords must be the same.'));
|
||||
}
|
||||
return $this->cleaned_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the model in the database.
|
||||
*
|
||||
* @param bool Commit in the database or not. If not, the object
|
||||
* is returned but not saved in the database.
|
||||
* @return Object Model with data set from the form.
|
||||
*/
|
||||
function save($commit=true)
|
||||
{
|
||||
if (!$this->isValid()) {
|
||||
throw new Exception(__('Cannot save an invalid form.'));
|
||||
}
|
||||
$this->_user->setFromFormData($this->cleaned_data);
|
||||
$this->_user->active = true;
|
||||
$this->_user->administrator = false;
|
||||
$this->_user->staff = false;
|
||||
if ($commit) {
|
||||
$this->_user->update();
|
||||
/**
|
||||
* [signal]
|
||||
*
|
||||
* Pluf_User::passwordUpdated
|
||||
*
|
||||
* [sender]
|
||||
*
|
||||
* IDF_Form_RegisterConfirmation
|
||||
*
|
||||
* [description]
|
||||
*
|
||||
* This signal is sent when the user updated his
|
||||
* password from his account page.
|
||||
*
|
||||
* [parameters]
|
||||
*
|
||||
* array('user' => $user)
|
||||
*
|
||||
*/
|
||||
$params = array('user' => $this->_user);
|
||||
Pluf_Signal::send('Pluf_User::passwordUpdated',
|
||||
'IDF_Form_RegisterConfirmation', $params);
|
||||
}
|
||||
return $this->_user;
|
||||
}
|
||||
}
|
96
indefero/src/IDF/Form/RegisterInputKey.php
Normal file
96
indefero/src/IDF/Form/RegisterInputKey.php
Normal file
@@ -0,0 +1,96 @@
|
||||
<?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-2011 Céondo Ltd and contributors.
|
||||
#
|
||||
# InDefero is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# InDefero is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# ***** END LICENSE BLOCK ***** */
|
||||
|
||||
Pluf::loadFunction('Pluf_HTTP_URL_urlForView');
|
||||
|
||||
/**
|
||||
* Check the validity of a confirmation key.
|
||||
*
|
||||
*/
|
||||
class IDF_Form_RegisterInputKey extends Pluf_Form
|
||||
{
|
||||
public function initFields($extra=array())
|
||||
{
|
||||
$this->fields['key'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Your confirmation key'),
|
||||
'initial' => '',
|
||||
'widget_attrs' => array(
|
||||
'size' => 50,
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the key.
|
||||
*/
|
||||
public function clean_key()
|
||||
{
|
||||
$this->cleaned_data['key'] = trim($this->cleaned_data['key']);
|
||||
$error = __('We are sorry but this confirmation key is not valid. Maybe you should directly copy/paste it from your confirmation email.');
|
||||
if (false === ($email_id=self::checkKeyHash($this->cleaned_data['key']))) {
|
||||
throw new Pluf_Form_Invalid($error);
|
||||
}
|
||||
$guser = new Pluf_User();
|
||||
$sql = new Pluf_SQL('email=%s AND id=%s', $email_id);
|
||||
if ($guser->getCount(array('filter' => $sql->gen())) != 1) {
|
||||
throw new Pluf_Form_Invalid($error);
|
||||
}
|
||||
return $this->cleaned_data['key'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the model in the database.
|
||||
*
|
||||
* @param bool Commit in the database or not. If not, the object
|
||||
* is returned but not saved in the database.
|
||||
* @return string Url to redirect to the form.
|
||||
*/
|
||||
function save($commit=true)
|
||||
{
|
||||
if (!$this->isValid()) {
|
||||
throw new Exception(__('Cannot save an invalid form.'));
|
||||
}
|
||||
return Pluf_HTTP_URL_urlForView('IDF_Views::registerConfirmation',
|
||||
array($this->cleaned_data['key']));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return false or an array with the email and id.
|
||||
*
|
||||
* This is a static function to be reused by other forms.
|
||||
*
|
||||
* @param string Confirmation key
|
||||
* @return mixed Either false or array(email, id)
|
||||
*/
|
||||
public static function checkKeyHash($key)
|
||||
{
|
||||
$hash = substr($key, 0, 2);
|
||||
$encrypted = substr($key, 2);
|
||||
if ($hash != substr(md5(Pluf::f('secret_key').$encrypted), 0, 2)) {
|
||||
return false;
|
||||
}
|
||||
$cr = new Pluf_Crypt(md5(Pluf::f('secret_key')));
|
||||
return explode(':', $cr->decrypt($encrypted), 2);
|
||||
}
|
||||
}
|
255
indefero/src/IDF/Form/ReviewCreate.php
Normal file
255
indefero/src/IDF/Form/ReviewCreate.php
Normal file
@@ -0,0 +1,255 @@
|
||||
<?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-2011 Céondo Ltd and contributors.
|
||||
#
|
||||
# InDefero is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# InDefero is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/**
|
||||
* Create a new code review.
|
||||
*
|
||||
* This creates an IDF_Review and the corresponding IDF_Review_Patch.
|
||||
*/
|
||||
class IDF_Form_ReviewCreate extends Pluf_Form
|
||||
{
|
||||
public $user = null;
|
||||
public $project = null;
|
||||
public $show_full = false;
|
||||
|
||||
public function initFields($extra=array())
|
||||
{
|
||||
$this->user = $extra['user'];
|
||||
$this->project = $extra['project'];
|
||||
if ($this->user->hasPerm('IDF.project-owner', $this->project)
|
||||
or $this->user->hasPerm('IDF.project-member', $this->project)) {
|
||||
$this->show_full = true;
|
||||
}
|
||||
$this->fields['summary'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Summary'),
|
||||
'initial' => '',
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 200,
|
||||
'size' => 67,
|
||||
),
|
||||
));
|
||||
$this->fields['description'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Description'),
|
||||
'initial' => '',
|
||||
'widget' => 'Pluf_Form_Widget_TextareaInput',
|
||||
'widget_attrs' => array(
|
||||
'cols' => 58,
|
||||
'rows' => 7,
|
||||
),
|
||||
));
|
||||
$sql = new Pluf_SQL('project=%s', array($this->project->id));
|
||||
$commits = Pluf::factory('IDF_Commit')->getList(array('order' => 'creation_dtime DESC',
|
||||
'nb' => 10,
|
||||
'filter' => $sql->gen()));
|
||||
$choices = array();
|
||||
foreach ($commits as $c) {
|
||||
$id = (strlen($c->scm_id) > 10) ? substr($c->scm_id, 0, 10) : $c->scm_id;
|
||||
$ext = (mb_strlen($c->summary) > 50) ? mb_substr($c->summary, 0, 47).'...' : $c->summary;
|
||||
$choices[$id.' - '.$ext] = $c->scm_id;
|
||||
}
|
||||
$this->fields['commit'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Commit'),
|
||||
'initial' => '',
|
||||
'widget' => 'Pluf_Form_Widget_SelectInput',
|
||||
'widget_attrs' => array(
|
||||
'choices' => $choices,
|
||||
),
|
||||
));
|
||||
$upload_path = Pluf::f('upload_issue_path', false);
|
||||
if (false === $upload_path) {
|
||||
throw new Pluf_Exception_SettingError(__('The "upload_issue_path" configuration variable was not set.'));
|
||||
}
|
||||
$md5 = md5(rand().microtime().Pluf_Utils::getRandomString());
|
||||
// We add .dummy to try to mitigate security issues in the
|
||||
// case of someone allowing the upload path to be accessible
|
||||
// to everybody.
|
||||
$filename = substr($md5, 0, 2).'/'.substr($md5, 2, 2).'/'.substr($md5, 4).'/%s.dummy';
|
||||
$this->fields['patch'] = new Pluf_Form_Field_File(
|
||||
array('required' => true,
|
||||
'label' => __('Patch'),
|
||||
'move_function_params' =>
|
||||
array('upload_path' => $upload_path,
|
||||
'upload_path_create' => true,
|
||||
'file_name' => $filename,
|
||||
)
|
||||
)
|
||||
);
|
||||
if ($this->show_full) {
|
||||
$this->fields['status'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Status'),
|
||||
'initial' => 'New',
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 20,
|
||||
'size' => 15,
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
public function clean_patch()
|
||||
{
|
||||
$diff = new IDF_Diff(file_get_contents(Pluf::f('upload_issue_path').'/'
|
||||
.$this->cleaned_data['patch']));
|
||||
$diff->parse();
|
||||
if (count($diff->files) == 0) {
|
||||
throw new Pluf_Form_Invalid(__('We were not able to parse your patch. Please provide a valid patch.'));
|
||||
}
|
||||
return $this->cleaned_data['patch'];
|
||||
}
|
||||
|
||||
public function clean_commit()
|
||||
{
|
||||
$commit = self::findCommit($this->cleaned_data['commit']);
|
||||
if (null == $commit) {
|
||||
throw new Pluf_Form_Invalid(__('You provided an invalid commit.'));
|
||||
}
|
||||
return $this->cleaned_data['commit'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the interconnection in the form.
|
||||
*/
|
||||
public function clean()
|
||||
{
|
||||
return $this->cleaned_data;
|
||||
}
|
||||
|
||||
function clean_status()
|
||||
{
|
||||
// Check that the status is in the list of official status
|
||||
$tags = $this->project->getTagsFromConfig('labels_issue_open',
|
||||
IDF_Form_IssueTrackingConf::init_open,
|
||||
'Status');
|
||||
$tags = array_merge($this->project->getTagsFromConfig('labels_issue_closed',
|
||||
IDF_Form_IssueTrackingConf::init_closed,
|
||||
'Status')
|
||||
, $tags);
|
||||
$found = false;
|
||||
foreach ($tags as $tag) {
|
||||
if ($tag->name == trim($this->cleaned_data['status'])) {
|
||||
$found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!$found) {
|
||||
throw new Pluf_Form_Invalid(__('You provided an invalid status.'));
|
||||
}
|
||||
return $this->cleaned_data['status'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean the attachments post failure.
|
||||
*/
|
||||
function failed()
|
||||
{
|
||||
$upload_path = Pluf::f('upload_issue_path', false);
|
||||
if ($upload_path == false) return;
|
||||
if (!empty($this->cleaned_data['patch']) and
|
||||
file_exists($upload_path.'/'.$this->cleaned_data['patch'])) {
|
||||
@unlink($upload_path.'/'.$this->cleaned_data['patch']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the model in the database.
|
||||
*
|
||||
* @param bool Commit in the database or not. If not, the object
|
||||
* is returned but not saved in the database.
|
||||
* @return Object Model with data set from the form.
|
||||
*/
|
||||
function save($commit=true)
|
||||
{
|
||||
if (!$this->isValid()) {
|
||||
throw new Exception(__('Cannot save the model from an invalid form.'));
|
||||
}
|
||||
// Create the review
|
||||
$review = new IDF_Review();
|
||||
$review->project = $this->project;
|
||||
$review->summary = $this->cleaned_data['summary'];
|
||||
$review->submitter = $this->user;
|
||||
if (!isset($this->cleaned_data['status'])) {
|
||||
$this->cleaned_data['status'] = 'New';
|
||||
}
|
||||
$review->status = IDF_Tag::add(trim($this->cleaned_data['status']), $this->project, 'Status');
|
||||
$review->create();
|
||||
// add the first patch
|
||||
$patch = new IDF_Review_Patch();
|
||||
$patch->review = $review;
|
||||
$patch->summary = __('Initial patch to be reviewed.');
|
||||
$patch->description = $this->cleaned_data['description'];
|
||||
$patch->commit = self::findCommit($this->cleaned_data['commit']);
|
||||
$patch->patch = $this->cleaned_data['patch'];
|
||||
$patch->create();
|
||||
$patch->notify($this->project->getConf());
|
||||
/**
|
||||
* [signal]
|
||||
*
|
||||
* IDF_Review::create
|
||||
*
|
||||
* [sender]
|
||||
*
|
||||
* IDF_Form_ReviewCreate
|
||||
*
|
||||
* [description]
|
||||
*
|
||||
* This signal allows an application to perform a set of tasks
|
||||
* just after the creation of a review and the notification.
|
||||
*
|
||||
* [parameters]
|
||||
*
|
||||
* array('review' => $review,
|
||||
* 'patch' => $patch);
|
||||
*
|
||||
*/
|
||||
$params = array('review' => $review,
|
||||
'patch' => $patch);
|
||||
Pluf_Signal::send('IDF_Review::create', 'IDF_Form_ReviewCreate',
|
||||
$params);
|
||||
return $review;
|
||||
}
|
||||
|
||||
/**
|
||||
* Based on the given string, try to find the matching commit.
|
||||
*
|
||||
* If no user found, simply returns null.
|
||||
*
|
||||
* @param string Commit
|
||||
* @return IDF_Commit or null
|
||||
*/
|
||||
public static function findCommit($string)
|
||||
{
|
||||
$string = trim($string);
|
||||
if (strlen($string) == 0) return null;
|
||||
$gc = new IDF_Commit();
|
||||
$sql = new Pluf_SQL('scm_id=%s', array($string));
|
||||
$gcs = $gc->getList(array('filter' => $sql->gen()));
|
||||
if ($gcs->count() > 0) {
|
||||
return $gcs[0];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
181
indefero/src/IDF/Form/ReviewFileComment.php
Normal file
181
indefero/src/IDF/Form/ReviewFileComment.php
Normal file
@@ -0,0 +1,181 @@
|
||||
<?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-2011 Céondo Ltd and contributors.
|
||||
#
|
||||
# InDefero is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# InDefero is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/**
|
||||
* Add comments to files in a review.
|
||||
*
|
||||
*/
|
||||
class IDF_Form_ReviewFileComment extends Pluf_Form
|
||||
{
|
||||
public $files = null;
|
||||
public $patch = null;
|
||||
public $user = null;
|
||||
public $project = null;
|
||||
|
||||
public function initFields($extra=array())
|
||||
{
|
||||
$this->files = $extra['files'];
|
||||
$this->patch = $extra['patch'];
|
||||
$this->user = $extra['user'];
|
||||
$this->project = $extra['project'];
|
||||
|
||||
foreach ($this->files as $filename => $def) {
|
||||
$this->fields[md5($filename)] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
'label' => __('Comment'),
|
||||
'initial' => '',
|
||||
'widget' => 'Pluf_Form_Widget_TextareaInput',
|
||||
'widget_attrs' => array(
|
||||
'cols' => 58,
|
||||
'rows' => 9,
|
||||
),
|
||||
));
|
||||
}
|
||||
$this->fields['content'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
'label' => __('General comment'),
|
||||
'initial' => '',
|
||||
'widget' => 'Pluf_Form_Widget_TextareaInput',
|
||||
'widget_attrs' => array(
|
||||
'cols' => 58,
|
||||
'rows' => 9,
|
||||
),
|
||||
));
|
||||
if ($this->user->hasPerm('IDF.project-owner', $this->project)
|
||||
or $this->user->hasPerm('IDF.project-member', $this->project)) {
|
||||
$this->show_full = true;
|
||||
} else {
|
||||
$this->show_full = false;
|
||||
}
|
||||
if ($this->show_full) {
|
||||
$this->fields['summary'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Summary'),
|
||||
'initial' => $this->patch->get_review()->summary,
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 200,
|
||||
'size' => 67,
|
||||
),
|
||||
));
|
||||
|
||||
$this->fields['status'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Status'),
|
||||
'initial' => $this->patch->get_review()->get_status()->name,
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 20,
|
||||
'size' => 15,
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Validate the interconnection in the form.
|
||||
*/
|
||||
public function clean()
|
||||
{
|
||||
$isOk = false;
|
||||
|
||||
foreach($this->files as $filename => $def) {
|
||||
$this->cleaned_data[md5($filename)] = trim($this->cleaned_data[md5($filename)]);
|
||||
if(!empty($this->cleaned_data[md5($filename)])) {
|
||||
$isOk = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(!empty($this->cleaned_data['content'])) {
|
||||
$isOk = true;
|
||||
}
|
||||
|
||||
if (!$isOk) {
|
||||
throw new Pluf_Form_Invalid(__('You need to provide your general comment about the proposal, or comments on at least one file.'));
|
||||
}
|
||||
|
||||
return $this->cleaned_data;
|
||||
}
|
||||
|
||||
function clean_content()
|
||||
{
|
||||
$content = trim($this->cleaned_data['content']);
|
||||
if(empty($content)) {
|
||||
if ($this->fields['status']->initial != $this->fields['status']->value) {
|
||||
return __('The status have been updated.');
|
||||
}
|
||||
} else {
|
||||
return $content;
|
||||
}
|
||||
|
||||
throw new Pluf_Form_Invalid(__('This field is required.'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the model in the database.
|
||||
*
|
||||
* @param bool Commit in the database or not. If not, the object
|
||||
* is returned but not saved in the database.
|
||||
* @return Object Model with data set from the form.
|
||||
*/
|
||||
function save($commit=true)
|
||||
{
|
||||
if (!$this->isValid()) {
|
||||
throw new Exception(__('Cannot save the model from an invalid form.'));
|
||||
}
|
||||
// create a base comment
|
||||
$bc = new IDF_Review_Comment();
|
||||
$bc->patch = $this->patch;
|
||||
$bc->submitter = $this->user;
|
||||
$bc->content = $this->cleaned_data['content'];
|
||||
$review = $this->patch->get_review();
|
||||
if ($this->show_full) {
|
||||
// Compare between the old and the new data
|
||||
// Status, summary
|
||||
$changes = array();
|
||||
$status = IDF_Tag::add(trim($this->cleaned_data['status']), $this->project, 'Status');
|
||||
if ($status->id != $this->patch->get_review()->status) {
|
||||
$changes['st'] = $status->name;
|
||||
}
|
||||
if (trim($this->patch->get_review()->summary) != trim($this->cleaned_data['summary'])) {
|
||||
$changes['su'] = trim($this->cleaned_data['summary']);
|
||||
}
|
||||
// Update the review
|
||||
$review->summary = trim($this->cleaned_data['summary']);
|
||||
$review->status = $status;
|
||||
$bc->changes = $changes;
|
||||
}
|
||||
$bc->create();
|
||||
foreach ($this->files as $filename => $def) {
|
||||
if (!empty($this->cleaned_data[md5($filename)])) {
|
||||
// Add a comment.
|
||||
$c = new IDF_Review_FileComment();
|
||||
$c->comment = $bc;
|
||||
$c->cfile = $filename;
|
||||
$c->content = $this->cleaned_data[md5($filename)];
|
||||
$c->create();
|
||||
}
|
||||
}
|
||||
$review->update(); // reindex and put up in the list.
|
||||
return $bc;
|
||||
}
|
||||
}
|
62
indefero/src/IDF/Form/SourceConf.php
Normal file
62
indefero/src/IDF/Form/SourceConf.php
Normal file
@@ -0,0 +1,62 @@
|
||||
<?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-2011 Céondo Ltd and contributors.
|
||||
#
|
||||
# InDefero is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# InDefero is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# ***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
/**
|
||||
* Configuration of the source.
|
||||
*
|
||||
* Only the modification of the login/password for subversion is
|
||||
* authorized.
|
||||
*/
|
||||
class IDF_Form_SourceConf extends Pluf_Form
|
||||
{
|
||||
public $conf = null;
|
||||
public function initFields($extra=array())
|
||||
{
|
||||
$this->conf = $extra['conf'];
|
||||
if ($extra['remote_svn']) {
|
||||
$this->fields['svn_username'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
'label' => __('Repository username'),
|
||||
'initial' => $this->conf->getVal('svn_username', ''),
|
||||
'widget_attrs' => array('size' => '15'),
|
||||
));
|
||||
|
||||
$this->fields['svn_password'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
'label' => __('Repository password'),
|
||||
'initial' => $this->conf->getVal('svn_password', ''),
|
||||
'widget' => 'Pluf_Form_Widget_PasswordInput',
|
||||
));
|
||||
}
|
||||
$this->fields['webhook_url'] = new Pluf_Form_Field_Url(
|
||||
array('required' => false,
|
||||
'label' => __('Webhook URL'),
|
||||
'initial' => $this->conf->getVal('webhook_url', ''),
|
||||
'widget_attrs' => array('size' => 35),
|
||||
));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
149
indefero/src/IDF/Form/TabsConf.php
Normal file
149
indefero/src/IDF/Form/TabsConf.php
Normal file
@@ -0,0 +1,149 @@
|
||||
<?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-2011 Céondo Ltd and contributors.
|
||||
#
|
||||
# InDefero is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# InDefero is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# ***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
/**
|
||||
* Configuration of the tabs access.
|
||||
*/
|
||||
class IDF_Form_TabsConf extends Pluf_Form
|
||||
{
|
||||
public $conf = null;
|
||||
public $project = null;
|
||||
|
||||
public function initFields($extra=array())
|
||||
{
|
||||
$this->conf = $extra['conf'];
|
||||
$this->project = $extra['project'];
|
||||
|
||||
$ak = array('downloads_access_rights' => __('Downloads'),
|
||||
'review_access_rights' => __('Code Review'),
|
||||
'wiki_access_rights' => __('Documentation'),
|
||||
'source_access_rights' => __('Source'),
|
||||
'issues_access_rights' => __('Issues'),);
|
||||
foreach ($ak as $key=>$label) {
|
||||
$this->fields[$key] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => $label,
|
||||
'initial' => $this->conf->getVal($key, 'all'),
|
||||
'widget_attrs' => array('choices' =>
|
||||
array(
|
||||
__('Open to all') => 'all',
|
||||
__('Signed in users') => 'login',
|
||||
__('Project members') => 'members',
|
||||
__('Project owners') => 'owners',
|
||||
__('Closed') => 'none',
|
||||
)
|
||||
),
|
||||
'widget' => 'Pluf_Form_Widget_SelectInput',
|
||||
));
|
||||
}
|
||||
|
||||
$sections = array(
|
||||
'downloads_notification',
|
||||
'review_notification',
|
||||
'wiki_notification',
|
||||
'source_notification',
|
||||
'issues_notification',
|
||||
);
|
||||
|
||||
foreach ($sections as $section) {
|
||||
$this->fields[$section.'_owners_enabled'] = new Pluf_Form_Field_Boolean(
|
||||
array('required' => false,
|
||||
'label' => __('Project owners'),
|
||||
'initial' => $this->conf->getVal($section.'_owners_enabled', false),
|
||||
'widget' => 'Pluf_Form_Widget_CheckboxInput',
|
||||
));
|
||||
$this->fields[$section.'_members_enabled'] = new Pluf_Form_Field_Boolean(
|
||||
array('required' => false,
|
||||
'label' => __('Project members'),
|
||||
'initial' => $this->conf->getVal($section.'_members_enabled', false),
|
||||
'widget' => 'Pluf_Form_Widget_CheckboxInput',
|
||||
));
|
||||
$this->fields[$section.'_email_enabled'] = new Pluf_Form_Field_Boolean(
|
||||
array('required' => false,
|
||||
'label' => __('Others'),
|
||||
'initial' => $this->conf->getVal($section.'_email_enabled', false),
|
||||
'widget' => 'Pluf_Form_Widget_CheckboxInput',
|
||||
));
|
||||
if ($this->conf->getVal($section.'_email_enabled', false)) {
|
||||
$attrs['readonly'] = 'readonly';
|
||||
}
|
||||
$this->fields[$section.'_email'] = new IDF_Form_Field_EmailList(
|
||||
array('required' => false,
|
||||
'label' => null,
|
||||
'initial' => $this->conf->getVal($section.'_email', ''),
|
||||
'widget_attrs' => array('size' => 20),
|
||||
));
|
||||
}
|
||||
|
||||
$this->fields['private_project'] = new Pluf_Form_Field_Boolean(
|
||||
array('required' => false,
|
||||
'label' => __('Private project'),
|
||||
'initial' => $this->project->private,
|
||||
'widget' => 'Pluf_Form_Widget_CheckboxInput',
|
||||
));
|
||||
$this->fields['authorized_users'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
'label' => __('Extra authorized users'),
|
||||
'widget_attrs' => array('rows' => 7,
|
||||
'cols' => 40),
|
||||
'widget' => 'Pluf_Form_Widget_TextareaInput',
|
||||
));
|
||||
}
|
||||
|
||||
public function clean_authorized_users()
|
||||
{
|
||||
return IDF_Form_MembersConf::checkBadLogins($this->cleaned_data['authorized_users']);
|
||||
}
|
||||
|
||||
public function save($commit=true)
|
||||
{
|
||||
if (!$this->isValid()) {
|
||||
throw new Exception(__('Cannot save the model from an invalid form.'));
|
||||
}
|
||||
// remove all the permissions
|
||||
$perm = Pluf_Permission::getFromString('IDF.project-authorized-user');
|
||||
$cm = $this->project->getMembershipData();
|
||||
$guser = new Pluf_User();
|
||||
foreach ($cm['authorized'] as $user) {
|
||||
Pluf_RowPermission::remove($user, $this->project, $perm);
|
||||
}
|
||||
if ($this->cleaned_data['private_project']) {
|
||||
foreach (preg_split("/\015\012|\015|\012|\,/", $this->cleaned_data['authorized_users'], -1, PREG_SPLIT_NO_EMPTY) as $login) {
|
||||
$sql = new Pluf_SQL('login=%s', array(trim($login)));
|
||||
$users = $guser->getList(array('filter'=>$sql->gen()));
|
||||
if ($users->count() == 1) {
|
||||
Pluf_RowPermission::add($users[0], $this->project, $perm);
|
||||
}
|
||||
}
|
||||
$this->project->private = 1;
|
||||
} else {
|
||||
$this->project->private = 0;
|
||||
}
|
||||
$this->project->update();
|
||||
$this->project->membershipsUpdated();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
177
indefero/src/IDF/Form/UpdateUpload.php
Normal file
177
indefero/src/IDF/Form/UpdateUpload.php
Normal file
@@ -0,0 +1,177 @@
|
||||
<?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-2011 Céondo Ltd and contributors.
|
||||
#
|
||||
# InDefero is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# InDefero is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/**
|
||||
* Update a file for download.
|
||||
*
|
||||
*/
|
||||
class IDF_Form_UpdateUpload extends Pluf_Form
|
||||
{
|
||||
public $user = null;
|
||||
public $project = null;
|
||||
public $upload = null;
|
||||
|
||||
public function initFields($extra=array())
|
||||
{
|
||||
$this->user = $extra['user'];
|
||||
$this->project = $extra['project'];
|
||||
$this->upload = $extra['upload'];
|
||||
|
||||
$this->fields['summary'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Summary'),
|
||||
'initial' => $this->upload->summary,
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 200,
|
||||
'size' => 67,
|
||||
),
|
||||
));
|
||||
$this->fields['changelog'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
'label' => __('Description'),
|
||||
'initial' => $this->upload->changelog,
|
||||
'widget' => 'Pluf_Form_Widget_TextareaInput',
|
||||
'widget_attrs' => array(
|
||||
'cols' => 58,
|
||||
'rows' => 13,
|
||||
),
|
||||
));
|
||||
$tags = $this->upload->get_tags_list();
|
||||
for ($i=1;$i<7;$i++) {
|
||||
$initial = '';
|
||||
if (isset($tags[$i-1])) {
|
||||
if ($tags[$i-1]->class != 'Other') {
|
||||
$initial = (string) $tags[$i-1];
|
||||
} else {
|
||||
$initial = $tags[$i-1]->name;
|
||||
}
|
||||
}
|
||||
$this->fields['label'.$i] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
'label' => __('Labels'),
|
||||
'initial' => $initial,
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 50,
|
||||
'size' => 20,
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the interconnection in the form.
|
||||
*/
|
||||
public function clean()
|
||||
{
|
||||
$conf = new IDF_Conf();
|
||||
$conf->setProject($this->project);
|
||||
$onemax = array();
|
||||
foreach (explode(',', $conf->getVal('labels_download_one_max', IDF_Form_UploadConf::init_one_max)) as $class) {
|
||||
if (trim($class) != '') {
|
||||
$onemax[] = mb_strtolower(trim($class));
|
||||
}
|
||||
}
|
||||
$count = array();
|
||||
for ($i=1;$i<7;$i++) {
|
||||
$this->cleaned_data['label'.$i] = trim($this->cleaned_data['label'.$i]);
|
||||
if (strpos($this->cleaned_data['label'.$i], ':') !== false) {
|
||||
list($class, $name) = explode(':', $this->cleaned_data['label'.$i], 2);
|
||||
list($class, $name) = array(mb_strtolower(trim($class)),
|
||||
trim($name));
|
||||
} else {
|
||||
$class = 'other';
|
||||
$name = $this->cleaned_data['label'.$i];
|
||||
}
|
||||
if (!isset($count[$class])) $count[$class] = 1;
|
||||
else $count[$class] += 1;
|
||||
if (in_array($class, $onemax) and $count[$class] > 1) {
|
||||
if (!isset($this->errors['label'.$i])) $this->errors['label'.$i] = array();
|
||||
$this->errors['label'.$i][] = sprintf(__('You cannot provide more than one label from the %s class to an issue.'), $class);
|
||||
throw new Pluf_Form_Invalid(__('You provided an invalid label.'));
|
||||
}
|
||||
}
|
||||
return $this->cleaned_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the model in the database.
|
||||
*
|
||||
* @param bool Commit in the database or not. If not, the object
|
||||
* is returned but not saved in the database.
|
||||
* @return Object Model with data set from the form.
|
||||
*/
|
||||
function save($commit=true)
|
||||
{
|
||||
if (!$this->isValid()) {
|
||||
throw new Exception(__('Cannot save the model from an invalid form.'));
|
||||
}
|
||||
// Add a tag for each label
|
||||
$tags = array();
|
||||
for ($i=1;$i<7;$i++) {
|
||||
if (strlen($this->cleaned_data['label'.$i]) > 0) {
|
||||
if (strpos($this->cleaned_data['label'.$i], ':') !== false) {
|
||||
list($class, $name) = explode(':', $this->cleaned_data['label'.$i], 2);
|
||||
list($class, $name) = array(trim($class), trim($name));
|
||||
} else {
|
||||
$class = 'Other';
|
||||
$name = trim($this->cleaned_data['label'.$i]);
|
||||
}
|
||||
$tag = IDF_Tag::add($name, $this->project, $class);
|
||||
$tags[] = $tag->id;
|
||||
}
|
||||
}
|
||||
// Create the upload
|
||||
$this->upload->summary = trim($this->cleaned_data['summary']);
|
||||
$this->upload->changelog = trim($this->cleaned_data['changelog']);
|
||||
$this->upload->modif_dtime = gmdate('Y-m-d H:i:s');
|
||||
$this->upload->update();
|
||||
$this->upload->batchAssoc('IDF_Tag', $tags);
|
||||
|
||||
// Send the notification
|
||||
$this->upload->notify($this->project->getConf(), false);
|
||||
/**
|
||||
* [signal]
|
||||
*
|
||||
* IDF_Upload::update
|
||||
*
|
||||
* [sender]
|
||||
*
|
||||
* IDF_Form_UpdateUpload
|
||||
*
|
||||
* [description]
|
||||
*
|
||||
* This signal allows an application to perform a set of tasks
|
||||
* just after the update of an uploaded file.
|
||||
*
|
||||
* [parameters]
|
||||
*
|
||||
* array('upload' => $upload);
|
||||
*
|
||||
*/
|
||||
$params = array('upload' => $this->upload);
|
||||
Pluf_Signal::send('IDF_Upload::update',
|
||||
'IDF_Form_UpdateUpload', $params);
|
||||
return $this->upload;
|
||||
}
|
||||
}
|
||||
|
205
indefero/src/IDF/Form/Upload.php
Normal file
205
indefero/src/IDF/Form/Upload.php
Normal file
@@ -0,0 +1,205 @@
|
||||
<?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-2011 Céondo Ltd and contributors.
|
||||
#
|
||||
# InDefero is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# InDefero is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/**
|
||||
* Upload a file for download.
|
||||
*
|
||||
*/
|
||||
class IDF_Form_Upload extends Pluf_Form
|
||||
{
|
||||
public $user = null;
|
||||
public $project = null;
|
||||
|
||||
public function initFields($extra=array())
|
||||
{
|
||||
$this->user = $extra['user'];
|
||||
$this->project = $extra['project'];
|
||||
|
||||
$this->fields['summary'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Summary'),
|
||||
'initial' => '',
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 200,
|
||||
'size' => 67,
|
||||
),
|
||||
));
|
||||
$this->fields['changelog'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
'label' => __('Description'),
|
||||
'initial' => '',
|
||||
'widget' => 'Pluf_Form_Widget_TextareaInput',
|
||||
'widget_attrs' => array(
|
||||
'cols' => 58,
|
||||
'rows' => 13,
|
||||
),
|
||||
));
|
||||
$this->fields['file'] = new Pluf_Form_Field_File(
|
||||
array('required' => true,
|
||||
'label' => __('File'),
|
||||
'initial' => '',
|
||||
'max_size' => Pluf::f('max_upload_size', 2097152),
|
||||
'move_function_params' => array('upload_path' => Pluf::f('upload_path').'/'.$this->project->shortname.'/files',
|
||||
'upload_path_create' => true,
|
||||
'upload_overwrite' => false),
|
||||
|
||||
));
|
||||
for ($i=1;$i<7;$i++) {
|
||||
$this->fields['label'.$i] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
'label' => __('Labels'),
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 50,
|
||||
'size' => 20,
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function clean_file()
|
||||
{
|
||||
// FIXME: we do the same in IDF_Form_WikiResourceCreate and a couple of other places as well
|
||||
$extra = strtolower(implode('|', explode(' ', Pluf::f('idf_extra_upload_ext'))));
|
||||
if (strlen($extra)) $extra .= '|';
|
||||
if (!preg_match('/\.('.$extra.'png|jpg|jpeg|gif|bmp|psd|tif|aiff|asf|avi|bz2|css|doc|eps|gz|jar|mdtext|mid|mov|mp3|mpg|ogg|pdf|ppt|ps|qt|ra|ram|rm|rtf|sdd|sdw|sit|sxi|sxw|swf|tgz|txt|wav|xls|xml|war|wmv|zip)$/i', $this->cleaned_data['file'])) {
|
||||
@unlink(Pluf::f('upload_path').'/'.$this->project->shortname.'/files/'.$this->cleaned_data['file']);
|
||||
throw new Pluf_Form_Invalid(__('For security reasons, you cannot upload a file with this extension.'));
|
||||
}
|
||||
return $this->cleaned_data['file'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the interconnection in the form.
|
||||
*/
|
||||
public function clean()
|
||||
{
|
||||
$conf = new IDF_Conf();
|
||||
$conf->setProject($this->project);
|
||||
$onemax = array();
|
||||
foreach (explode(',', $conf->getVal('labels_download_one_max', IDF_Form_UploadConf::init_one_max)) as $class) {
|
||||
if (trim($class) != '') {
|
||||
$onemax[] = mb_strtolower(trim($class));
|
||||
}
|
||||
}
|
||||
$count = array();
|
||||
for ($i=1;$i<7;$i++) {
|
||||
$this->cleaned_data['label'.$i] = trim($this->cleaned_data['label'.$i]);
|
||||
if (strpos($this->cleaned_data['label'.$i], ':') !== false) {
|
||||
list($class, $name) = explode(':', $this->cleaned_data['label'.$i], 2);
|
||||
list($class, $name) = array(mb_strtolower(trim($class)),
|
||||
trim($name));
|
||||
} else {
|
||||
$class = 'other';
|
||||
$name = $this->cleaned_data['label'.$i];
|
||||
}
|
||||
if (!isset($count[$class])) $count[$class] = 1;
|
||||
else $count[$class] += 1;
|
||||
if (in_array($class, $onemax) and $count[$class] > 1) {
|
||||
if (!isset($this->errors['label'.$i])) $this->errors['label'.$i] = array();
|
||||
$this->errors['label'.$i][] = sprintf(__('You cannot provide more than one label from the %s class to a download.'), $class);
|
||||
throw new Pluf_Form_Invalid(__('You provided an invalid label.'));
|
||||
}
|
||||
}
|
||||
return $this->cleaned_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* If we have uploaded a file, but the form failed remove it.
|
||||
*
|
||||
*/
|
||||
function failed()
|
||||
{
|
||||
if (!empty($this->cleaned_data['file'])
|
||||
and file_exists(Pluf::f('upload_path').'/'.$this->project->shortname.'/files/'.$this->cleaned_data['file'])) {
|
||||
@unlink(Pluf::f('upload_path').'/'.$this->project->shortname.'/files/'.$this->cleaned_data['file']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the model in the database.
|
||||
*
|
||||
* @param bool Commit in the database or not. If not, the object
|
||||
* is returned but not saved in the database.
|
||||
* @return Object Model with data set from the form.
|
||||
*/
|
||||
function save($commit=true)
|
||||
{
|
||||
if (!$this->isValid()) {
|
||||
throw new Exception(__('Cannot save the model from an invalid form.'));
|
||||
}
|
||||
// Add a tag for each label
|
||||
$tags = array();
|
||||
for ($i=1;$i<7;$i++) {
|
||||
if (strlen($this->cleaned_data['label'.$i]) > 0) {
|
||||
if (strpos($this->cleaned_data['label'.$i], ':') !== false) {
|
||||
list($class, $name) = explode(':', $this->cleaned_data['label'.$i], 2);
|
||||
list($class, $name) = array(trim($class), trim($name));
|
||||
} else {
|
||||
$class = 'Other';
|
||||
$name = trim($this->cleaned_data['label'.$i]);
|
||||
}
|
||||
$tags[] = IDF_Tag::add($name, $this->project, $class);
|
||||
}
|
||||
}
|
||||
// Create the upload
|
||||
$upload = new IDF_Upload();
|
||||
$upload->project = $this->project;
|
||||
$upload->submitter = $this->user;
|
||||
$upload->summary = trim($this->cleaned_data['summary']);
|
||||
$upload->changelog = trim($this->cleaned_data['changelog']);
|
||||
$upload->file = $this->cleaned_data['file'];
|
||||
$upload->filesize = filesize(Pluf::f('upload_path').'/'.$this->project->shortname.'/files/'.$this->cleaned_data['file']);
|
||||
$upload->downloads = 0;
|
||||
$upload->create();
|
||||
foreach ($tags as $tag) {
|
||||
$upload->setAssoc($tag);
|
||||
}
|
||||
// Send the notification
|
||||
$upload->notify($this->project->getConf());
|
||||
/**
|
||||
* [signal]
|
||||
*
|
||||
* IDF_Upload::create
|
||||
*
|
||||
* [sender]
|
||||
*
|
||||
* IDF_Form_Upload
|
||||
*
|
||||
* [description]
|
||||
*
|
||||
* This signal allows an application to perform a set of tasks
|
||||
* just after the upload of a file and after the notification run.
|
||||
*
|
||||
* [parameters]
|
||||
*
|
||||
* array('upload' => $upload);
|
||||
*
|
||||
*/
|
||||
$params = array('upload' => $upload);
|
||||
Pluf_Signal::send('IDF_Upload::create', 'IDF_Form_Upload',
|
||||
$params);
|
||||
return $upload;
|
||||
}
|
||||
}
|
||||
|
227
indefero/src/IDF/Form/UploadArchive.php
Normal file
227
indefero/src/IDF/Form/UploadArchive.php
Normal file
@@ -0,0 +1,227 @@
|
||||
<?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-2011 Céondo Ltd and contributors.
|
||||
#
|
||||
# InDefero is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# InDefero is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/**
|
||||
* Upload and process an archive file.
|
||||
*
|
||||
*/
|
||||
class IDF_Form_UploadArchive extends Pluf_Form
|
||||
{
|
||||
public $user = null;
|
||||
public $project = null;
|
||||
private $archiveHelper = null;
|
||||
|
||||
public function initFields($extra=array())
|
||||
{
|
||||
$this->user = $extra['user'];
|
||||
$this->project = $extra['project'];
|
||||
|
||||
$this->fields['archive'] = new Pluf_Form_Field_File(
|
||||
array('required' => true,
|
||||
'label' => __('Archive file'),
|
||||
'initial' => '',
|
||||
'max_size' => Pluf::f('max_upload_archive_size', 20971520),
|
||||
'move_function_params' => array(
|
||||
'upload_path' => Pluf::f('upload_path').'/'.$this->project->shortname.'/archives',
|
||||
'upload_path_create' => true,
|
||||
'upload_overwrite' => true,
|
||||
)));
|
||||
}
|
||||
|
||||
|
||||
public function clean_archive()
|
||||
{
|
||||
$this->archiveHelper = new IDF_Form_UploadArchiveHelper(
|
||||
Pluf::f('upload_path').'/'.$this->project->shortname.'/archives/'.$this->cleaned_data['archive']);
|
||||
|
||||
// basic archive validation
|
||||
$this->archiveHelper->validate();
|
||||
|
||||
// extension validation
|
||||
$fileNames = $this->archiveHelper->getEntryNames();
|
||||
foreach ($fileNames as $fileName) {
|
||||
$extra = strtolower(implode('|', explode(' ', Pluf::f('idf_extra_upload_ext'))));
|
||||
if (strlen($extra)) $extra .= '|';
|
||||
if (!preg_match('/\.('.$extra.'png|jpg|jpeg|gif|bmp|psd|tif|aiff|asf|avi|bz2|css|doc|eps|gz|jar|mdtext|mid|mov|mp3|mpg|ogg|pdf|ppt|ps|qt|ra|ram|rm|rtf|sdd|sdw|sit|sxi|sxw|swf|tgz|txt|wav|xls|xml|war|wmv|zip)$/i', $fileName)) {
|
||||
@unlink(Pluf::f('upload_path').'/'.$this->project->shortname.'/files/'.$this->cleaned_data['archive']);
|
||||
throw new Pluf_Form_Invalid(sprintf(__('For security reasons, you cannot upload a file (%s) with this extension.'), $fileName));
|
||||
}
|
||||
}
|
||||
|
||||
// label and file name validation
|
||||
$conf = new IDF_Conf();
|
||||
$conf->setProject($this->project);
|
||||
$onemax = array();
|
||||
foreach (explode(',', $conf->getVal('labels_download_one_max', IDF_Form_UploadConf::init_one_max)) as $class) {
|
||||
if (trim($class) != '') {
|
||||
$onemax[] = mb_strtolower(trim($class));
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($fileNames as $fileName) {
|
||||
$meta = $this->archiveHelper->getMetaData($fileName);
|
||||
$count = array();
|
||||
foreach ($meta['labels'] as $label) {
|
||||
$label = trim($label);
|
||||
if (strpos($label, ':') !== false) {
|
||||
list($class, $name) = explode(':', $label, 2);
|
||||
list($class, $name) = array(mb_strtolower(trim($class)),
|
||||
trim($name));
|
||||
} else {
|
||||
$class = 'other';
|
||||
$name = $label;
|
||||
}
|
||||
if (!isset($count[$class])) $count[$class] = 1;
|
||||
else $count[$class] += 1;
|
||||
if (in_array($class, $onemax) and $count[$class] > 1) {
|
||||
throw new Pluf_Form_Invalid(
|
||||
sprintf(__('You cannot provide more than label from the %1$s class to a download (%2$s).'), $class, $name)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$sql = new Pluf_SQL('file=%s AND project=%s', array($fileName, $this->project->id));
|
||||
$upload = Pluf::factory('IDF_Upload')->getOne(array('filter' => $sql->gen()));
|
||||
|
||||
$meta = $this->archiveHelper->getMetaData($fileName);
|
||||
if ($upload != null && $meta['replaces'] !== $fileName) {
|
||||
throw new Pluf_Form_Invalid(
|
||||
sprintf(__('A file with the name "%s" has already been uploaded and is not marked to be replaced.'), $fileName));
|
||||
}
|
||||
}
|
||||
|
||||
return $this->cleaned_data['archive'];
|
||||
}
|
||||
|
||||
/**
|
||||
* If we have uploaded a file, but the form failed remove it.
|
||||
*
|
||||
*/
|
||||
function failed()
|
||||
{
|
||||
if (!empty($this->cleaned_data['archive'])
|
||||
and file_exists(Pluf::f('upload_path').'/'.$this->project->shortname.'/archives/'.$this->cleaned_data['archive'])) {
|
||||
@unlink(Pluf::f('upload_path').'/'.$this->project->shortname.'/archives/'.$this->cleaned_data['archive']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the model in the database.
|
||||
*
|
||||
* @param bool Commit in the database or not. If not, the object
|
||||
* is returned but not saved in the database.
|
||||
*/
|
||||
function save($commit=true)
|
||||
{
|
||||
if (!$this->isValid()) {
|
||||
throw new Exception(__('Cannot save the model from an invalid form.'));
|
||||
}
|
||||
|
||||
$uploadDir = Pluf::f('upload_path').'/'.$this->project->shortname.'/files/';
|
||||
$fileNames = $this->archiveHelper->getEntryNames();
|
||||
|
||||
foreach ($fileNames as $fileName) {
|
||||
$meta = $this->archiveHelper->getMetaData($fileName);
|
||||
|
||||
// add a tag for each label
|
||||
$tags = array();
|
||||
foreach ($meta['labels'] as $label) {
|
||||
$label = trim($label);
|
||||
if (strlen($label) > 0) {
|
||||
if (strpos($label, ':') !== false) {
|
||||
list($class, $name) = explode(':', $label, 2);
|
||||
list($class, $name) = array(trim($class), trim($name));
|
||||
} else {
|
||||
$class = 'Other';
|
||||
$name = $label;
|
||||
}
|
||||
$tags[] = IDF_Tag::add($name, $this->project, $class);
|
||||
}
|
||||
}
|
||||
|
||||
// process a possible replacement
|
||||
if (!empty($meta['replaces'])) {
|
||||
$sql = new Pluf_SQL('file=%s AND project=%s', array($meta['replaces'], $this->project->id));
|
||||
$oldUpload = Pluf::factory('IDF_Upload')->getOne(array('filter' => $sql->gen()));
|
||||
|
||||
if ($oldUpload) {
|
||||
if ($meta['replaces'] === $fileName) {
|
||||
$oldUpload->delete();
|
||||
} else {
|
||||
$tags = $this->project->getTagsFromConfig('labels_download_predefined',
|
||||
IDF_Form_UploadConf::init_predefined);
|
||||
// the deprecate tag is - by definition - always the last one
|
||||
$deprecatedTag = array_pop($tags);
|
||||
$oldUpload->setAssoc($deprecatedTag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// extract the file
|
||||
$this->archiveHelper->extract($fileName, $uploadDir);
|
||||
|
||||
// create the upload
|
||||
$upload = new IDF_Upload();
|
||||
$upload->project = $this->project;
|
||||
$upload->submitter = $this->user;
|
||||
$upload->summary = trim($meta['summary']);
|
||||
$upload->changelog = trim($meta['description']);
|
||||
$upload->file = $fileName;
|
||||
$upload->filesize = filesize($uploadDir.$fileName);
|
||||
$upload->downloads = 0;
|
||||
$upload->create();
|
||||
foreach ($tags as $tag) {
|
||||
$upload->setAssoc($tag);
|
||||
}
|
||||
|
||||
// send the notification
|
||||
$upload->notify($this->project->getConf());
|
||||
/**
|
||||
* [signal]
|
||||
*
|
||||
* IDF_Upload::create
|
||||
*
|
||||
* [sender]
|
||||
*
|
||||
* IDF_Form_Upload
|
||||
*
|
||||
* [description]
|
||||
*
|
||||
* This signal allows an application to perform a set of tasks
|
||||
* just after the upload of a file and after the notification run.
|
||||
*
|
||||
* [parameters]
|
||||
*
|
||||
* array('upload' => $upload);
|
||||
*
|
||||
*/
|
||||
$params = array('upload' => $upload);
|
||||
Pluf_Signal::send('IDF_Upload::create', 'IDF_Form_Upload',
|
||||
$params);
|
||||
}
|
||||
|
||||
// finally unlink the uploaded archive
|
||||
@unlink(Pluf::f('upload_path').'/'.$this->project->shortname.'/archives/'.$this->cleaned_data['archive']);
|
||||
}
|
||||
}
|
||||
|
158
indefero/src/IDF/Form/UploadArchiveHelper.php
Normal file
158
indefero/src/IDF/Form/UploadArchiveHelper.php
Normal file
@@ -0,0 +1,158 @@
|
||||
<?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-2011 Céondo Ltd and contributors.
|
||||
#
|
||||
# InDefero is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# InDefero is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# ***** END LICENSE BLOCK ***** */
|
||||
|
||||
class IDF_Form_UploadArchiveHelper
|
||||
{
|
||||
private $file = null;
|
||||
private $entries = array();
|
||||
|
||||
public function __construct($file)
|
||||
{
|
||||
$this->file = $file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the archive; throws a invalid form exception in case the
|
||||
* archive contains invalid data or cannot be read.
|
||||
*/
|
||||
public function validate()
|
||||
{
|
||||
if (!file_exists($this->file)) {
|
||||
throw new Pluf_Form_Invalid(__('The archive does not exist.'));
|
||||
}
|
||||
|
||||
$za = new ZipArchive();
|
||||
$res = $za->open($this->file);
|
||||
if ($res !== true) {
|
||||
throw new Pluf_Form_Invalid(
|
||||
sprintf(__('The archive could not be read (code %d).'), $res));
|
||||
}
|
||||
|
||||
$manifest = $za->getFromName('manifest.xml');
|
||||
if ($manifest === false) {
|
||||
throw new Pluf_Form_Invalid(__('The archive does not contain a manifest.xml.'));
|
||||
}
|
||||
|
||||
libxml_use_internal_errors(true);
|
||||
$xml = @simplexml_load_string($manifest);
|
||||
if ($xml === false) {
|
||||
$error = libxml_get_last_error();
|
||||
throw new Pluf_Form_Invalid(
|
||||
sprintf(__('The archive\'s manifest is invalid: %s'), $error->message));
|
||||
}
|
||||
|
||||
foreach (@$xml->file as $idx => $file)
|
||||
{
|
||||
$entry = array(
|
||||
'name' => (string)@$file->name,
|
||||
'summary' => (string)@$file->summary,
|
||||
'description' => (string)@$file->description,
|
||||
'replaces' => (string)@$file->replaces,
|
||||
'labels' => array(),
|
||||
'stream' => null
|
||||
);
|
||||
|
||||
if (empty($entry['name'])) {
|
||||
throw new Pluf_Form_Invalid(
|
||||
sprintf(__('The entry %d in the manifest is missing a file name.'), $idx));
|
||||
}
|
||||
|
||||
if (empty($entry['summary'])) {
|
||||
throw new Pluf_Form_Invalid(
|
||||
sprintf(__('The entry %d in the manifest is missing a summary.'), $idx));
|
||||
}
|
||||
|
||||
if ($entry['name'] === 'manifest.xml') {
|
||||
throw new Pluf_Form_Invalid(__('The manifest must not reference itself.'));
|
||||
}
|
||||
|
||||
if ($za->locateName($entry['name']) === false) {
|
||||
throw new Pluf_Form_Invalid(
|
||||
sprintf(__('The entry %s in the manifest does not exist in the archive.'), $entry['name']));
|
||||
}
|
||||
|
||||
if (in_array($entry['name'], $this->entries)) {
|
||||
throw new Pluf_Form_Invalid(
|
||||
sprintf(__('The entry %s in the manifest is referenced more than once.'), $entry['name']));
|
||||
}
|
||||
|
||||
if ($file->labels) {
|
||||
foreach (@$file->labels->label as $label) {
|
||||
$entry['labels'][] = (string)$label;
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: remove this once we allow more than six labels everywhere
|
||||
if (count($entry['labels']) > 6) {
|
||||
throw new Pluf_Form_Invalid(
|
||||
sprintf(__('The entry %s in the manifest has more than the six allowed labels set.'), $entry['name']));
|
||||
}
|
||||
|
||||
$this->entries[$entry['name']] = $entry;
|
||||
}
|
||||
|
||||
$za->close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all entry names
|
||||
*
|
||||
* @return array of string
|
||||
*/
|
||||
public function getEntryNames()
|
||||
{
|
||||
return array_keys($this->entries);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns meta data for the given entry
|
||||
*
|
||||
* @param string $name
|
||||
* @throws Exception
|
||||
*/
|
||||
public function getMetaData($name)
|
||||
{
|
||||
if (!array_key_exists($name, $this->entries)) {
|
||||
throw new Exception('unknown file ' . $name);
|
||||
}
|
||||
return $this->entries[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the file entry $name at $path
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $path
|
||||
* @throws Exception
|
||||
*/
|
||||
public function extract($name, $path)
|
||||
{
|
||||
if (!array_key_exists($name, $this->entries)) {
|
||||
throw new Exception('unknown file ' . $name);
|
||||
}
|
||||
$za = new ZipArchive();
|
||||
$za->open($this->file);
|
||||
$za->extractTo($path, $name);
|
||||
$za->close();
|
||||
}
|
||||
}
|
78
indefero/src/IDF/Form/UploadConf.php
Normal file
78
indefero/src/IDF/Form/UploadConf.php
Normal file
@@ -0,0 +1,78 @@
|
||||
<?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-2011 Céondo Ltd and contributors.
|
||||
#
|
||||
# InDefero is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# InDefero is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# ***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
/**
|
||||
* Configuration of the labels etc. for the uploaded files.
|
||||
*/
|
||||
class IDF_Form_UploadConf extends Pluf_Form
|
||||
{
|
||||
/**
|
||||
* Defined as constants to easily access the value in the
|
||||
* form in the case nothing is in the db yet.
|
||||
*/
|
||||
const init_predefined = 'Featured = Listed on project home page
|
||||
Type:Executable = Executable application
|
||||
Type:Installer = Download and run to install application
|
||||
Type:Package = Your OS package manager installs this
|
||||
Type:Archive = Download, unarchive, then follow directions
|
||||
Type:Source = Source code archive
|
||||
Type:Docs = This file contains documentation
|
||||
OpSys:All = Works with all operating systems
|
||||
OpSys:Windows = Works with Windows
|
||||
OpSys:Linux = Works with Linux
|
||||
OpSys:OSX = Works with Mac OS X
|
||||
Deprecated = Most users should NOT download this';
|
||||
|
||||
const init_one_max = 'Type';
|
||||
|
||||
public function initFields($extra=array())
|
||||
{
|
||||
$this->fields['labels_download_predefined'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Predefined download labels'),
|
||||
'initial' => self::init_predefined,
|
||||
'widget_attrs' => array('rows' => 13,
|
||||
'cols' => 75),
|
||||
'widget' => 'Pluf_Form_Widget_TextareaInput',
|
||||
));
|
||||
|
||||
$this->fields['labels_download_one_max'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
'label' => __('Each download may have at most one label with each of these classes'),
|
||||
'initial' => self::init_one_max,
|
||||
'widget_attrs' => array('size' => 60),
|
||||
));
|
||||
|
||||
$this->conf = $extra['conf'];
|
||||
$this->fields['upload_webhook_url'] = new Pluf_Form_Field_Url(
|
||||
array('required' => false,
|
||||
'label' => __('Webhook URL'),
|
||||
'initial' => $this->conf->getVal('upload_webhook_url', ''),
|
||||
'widget_attrs' => array('size' => 60),
|
||||
));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
469
indefero/src/IDF/Form/UserAccount.php
Normal file
469
indefero/src/IDF/Form/UserAccount.php
Normal file
@@ -0,0 +1,469 @@
|
||||
<?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-2011 Céondo Ltd and contributors.
|
||||
#
|
||||
# InDefero is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# InDefero is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# ***** END LICENSE BLOCK ***** */
|
||||
|
||||
Pluf::loadFunction('Pluf_HTTP_URL_urlForView');
|
||||
|
||||
/**
|
||||
* Allow a user to update its details.
|
||||
*/
|
||||
class IDF_Form_UserAccount 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'),
|
||||
'initial' => $this->user->first_name,
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 50,
|
||||
'size' => 15,
|
||||
),
|
||||
));
|
||||
$this->fields['last_name'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Last name'),
|
||||
'initial' => $this->user->last_name,
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 50,
|
||||
'size' => 20,
|
||||
),
|
||||
));
|
||||
|
||||
$this->fields['email'] = new Pluf_Form_Field_Email(
|
||||
array('required' => true,
|
||||
'label' => __('Your email'),
|
||||
'initial' => $this->user->email,
|
||||
'help_text' => __('If you change your email address, an email will be sent to the new address to confirm it.'),
|
||||
));
|
||||
|
||||
$this->fields['language'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Language'),
|
||||
'initial' => $this->user->language,
|
||||
'widget' => 'Pluf_Form_Widget_SelectInput',
|
||||
'widget_attrs' => array(
|
||||
'choices' =>
|
||||
Pluf_L10n::getInstalledLanguages()
|
||||
),
|
||||
));
|
||||
|
||||
$this->fields['password'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
'label' => __('Your password'),
|
||||
'initial' => '',
|
||||
'widget' => 'Pluf_Form_Widget_PasswordInput',
|
||||
'help_text' => Pluf_Template::markSafe(__('Leave blank if you do not want to change your password.').'<br />'.__('Your password must be hard for other people to find it, but easy for you to remember.')),
|
||||
'widget_attrs' => array(
|
||||
'autocomplete' => 'off',
|
||||
'maxlength' => 50,
|
||||
'size' => 15,
|
||||
),
|
||||
));
|
||||
$this->fields['password2'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
'label' => __('Confirm your password'),
|
||||
'initial' => '',
|
||||
'widget' => 'Pluf_Form_Widget_PasswordInput',
|
||||
'widget_attrs' => array(
|
||||
'autocomplete' => 'off',
|
||||
'maxlength' => 50,
|
||||
'size' => 15,
|
||||
),
|
||||
));
|
||||
|
||||
$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'),
|
||||
'initial' => '',
|
||||
'widget_attrs' => array('rows' => 3,
|
||||
'cols' => 40),
|
||||
'widget' => 'Pluf_Form_Widget_TextareaInput',
|
||||
'help_text' => __('Paste an SSH or monotone public key. Be careful to not provide your private key here!')
|
||||
));
|
||||
|
||||
$this->fields['secondary_mail'] = new Pluf_Form_Field_Email(
|
||||
array('required' => false,
|
||||
'label' => __('Add a secondary email address'),
|
||||
'initial' => '',
|
||||
'help_text' => __('You will get an email to confirm that you own the address you specify.'),
|
||||
));
|
||||
}
|
||||
|
||||
private function send_validation_mail($new_email, $secondary_mail=false)
|
||||
{
|
||||
if ($secondary_mail) {
|
||||
$type = "secondary";
|
||||
} else {
|
||||
$type = "primary";
|
||||
}
|
||||
$cr = new Pluf_Crypt(md5(Pluf::f('secret_key')));
|
||||
$encrypted = trim($cr->encrypt($new_email.':'.$this->user->id.':'.time().':'.$type), '~');
|
||||
$key = substr(md5(Pluf::f('secret_key').$encrypted), 0, 2).$encrypted;
|
||||
$url = Pluf::f('url_base').Pluf_HTTP_URL_urlForView('IDF_Views_User::changeEmailDo', array($key), array(), false);
|
||||
$urlik = Pluf::f('url_base').Pluf_HTTP_URL_urlForView('IDF_Views_User::changeEmailInputKey', array(), array(), false);
|
||||
$context = new Pluf_Template_Context(
|
||||
array('key' => Pluf_Template::markSafe($key),
|
||||
'url' => Pluf_Template::markSafe($url),
|
||||
'urlik' => Pluf_Template::markSafe($urlik),
|
||||
'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,
|
||||
__('Confirm your new email address.'));
|
||||
$email->addTextMessage($text_email);
|
||||
$email->sendMail();
|
||||
$this->user->setMessage(sprintf(__('A validation email has been sent to "%s" to validate the email address change.'), Pluf_esc($new_email)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the model in the database.
|
||||
*
|
||||
* @param bool Commit in the database or not. If not, the object
|
||||
* is returned but not saved in the database.
|
||||
* @return Object Model with data set from the form.
|
||||
*/
|
||||
function save($commit=true)
|
||||
{
|
||||
if (!$this->isValid()) {
|
||||
throw new Exception(__('Cannot save the model from an invalid form.'));
|
||||
}
|
||||
unset($this->cleaned_data['password2']);
|
||||
$update_pass = false;
|
||||
if (strlen($this->cleaned_data['password']) == 0) {
|
||||
unset($this->cleaned_data['password']);
|
||||
} else {
|
||||
$update_pass = true;
|
||||
}
|
||||
$old_email = $this->user->email;
|
||||
$new_email = $this->cleaned_data['email'];
|
||||
unset($this->cleaned_data['email']);
|
||||
if ($old_email != $new_email) {
|
||||
$this->send_validation_mail($new_email);
|
||||
}
|
||||
$this->user->setFromFormData($this->cleaned_data);
|
||||
// Add key as needed.
|
||||
if ('' !== $this->cleaned_data['public_key']) {
|
||||
$key = new IDF_Key();
|
||||
$key->user = $this->user;
|
||||
$key->content = $this->cleaned_data['public_key'];
|
||||
if ($commit) {
|
||||
$key->create();
|
||||
}
|
||||
}
|
||||
if ('' !== $this->cleaned_data['secondary_mail']) {
|
||||
$this->send_validation_mail($this->cleaned_data['secondary_mail'], true);
|
||||
}
|
||||
|
||||
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]
|
||||
*
|
||||
* Pluf_User::passwordUpdated
|
||||
*
|
||||
* [sender]
|
||||
*
|
||||
* IDF_Form_UserAccount
|
||||
*
|
||||
* [description]
|
||||
*
|
||||
* This signal is sent when the user updated his
|
||||
* password from his account page.
|
||||
*
|
||||
* [parameters]
|
||||
*
|
||||
* array('user' => $user)
|
||||
*
|
||||
*/
|
||||
$params = array('user' => $this->user);
|
||||
Pluf_Signal::send('Pluf_User::passwordUpdated',
|
||||
'IDF_Form_UserAccount', $params);
|
||||
}
|
||||
}
|
||||
return $this->user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check arbitrary public keys.
|
||||
*
|
||||
* It will throw a Pluf_Form_Invalid exception if it cannot
|
||||
* validate the key.
|
||||
*
|
||||
* @param $key string The key
|
||||
* @param $user int The user id of the user of the key (0)
|
||||
* @return string The clean key
|
||||
*/
|
||||
public static function checkPublicKey($key, $user=0)
|
||||
{
|
||||
$key = trim($key);
|
||||
if (strlen($key) == 0) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$keysearch = '';
|
||||
if (preg_match('#^(ssh\-(?:dss|rsa)\s+\S+)(.*)#', $key, $m)) {
|
||||
$basekey = preg_replace('/\s+/', ' ', $m[1]);
|
||||
$comment = trim(preg_replace('/[\r\n]/', ' ', $m[2]));
|
||||
|
||||
$keysearch = $basekey.'%';
|
||||
$key = $basekey;
|
||||
if (!empty($comment))
|
||||
$key .= ' '.$comment;
|
||||
|
||||
if (Pluf::f('idf_strong_key_check', false)) {
|
||||
|
||||
$tmpfile = Pluf::f('tmp_folder', '/tmp').'/'.$user.'-key';
|
||||
file_put_contents($tmpfile, $key, LOCK_EX);
|
||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').
|
||||
'ssh-keygen -l -f '.escapeshellarg($tmpfile).' > /dev/null 2>&1';
|
||||
exec($cmd, $out, $return);
|
||||
unlink($tmpfile);
|
||||
|
||||
if ($return != 0) {
|
||||
throw new Pluf_Form_Invalid(
|
||||
__('Please check the key as it does not appear '.
|
||||
'to be a valid SSH public key.')
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (preg_match('#^\[pubkey [^\]]+\]\s*(\S+)\s*\[end\]$#', $key, $m)) {
|
||||
$keysearch = '%'.$m[1].'%';
|
||||
|
||||
if (Pluf::f('idf_strong_key_check', false)) {
|
||||
|
||||
// if monotone can read it, it should be valid
|
||||
$mtn_opts = implode(' ', Pluf::f('mtn_opts', array()));
|
||||
$cmd = Pluf::f('idf_exec_cmd_prefix', '').
|
||||
sprintf('%s %s -d :memory: read >/tmp/php-out 2>&1',
|
||||
Pluf::f('mtn_path', 'mtn'), $mtn_opts);
|
||||
$fp = popen($cmd, 'w');
|
||||
fwrite($fp, $key);
|
||||
$return = pclose($fp);
|
||||
|
||||
if ($return != 0) {
|
||||
throw new Pluf_Form_Invalid(
|
||||
__('Please check the key as it does not appear '.
|
||||
'to be a valid monotone public key.')
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new Pluf_Form_Invalid(
|
||||
__('Public key looks like neither an SSH '.
|
||||
'nor monotone public key.'));
|
||||
}
|
||||
|
||||
// If $user, then check if not the same key stored
|
||||
if ($user) {
|
||||
$ruser = Pluf::factory('Pluf_User', $user);
|
||||
if ($ruser->id > 0) {
|
||||
$sql = new Pluf_SQL('content LIKE %s AND user=%s', array($keysearch, $ruser->id));
|
||||
$keys = Pluf::factory('IDF_Key')->getList(array('filter' => $sql->gen()));
|
||||
if (count($keys) > 0) {
|
||||
throw new Pluf_Form_Invalid(
|
||||
__('You already have uploaded this key.')
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
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']);
|
||||
if ($last_name == mb_strtoupper($last_name)) {
|
||||
return mb_convert_case(mb_strtolower($last_name),
|
||||
MB_CASE_TITLE, 'UTF-8');
|
||||
}
|
||||
return $last_name;
|
||||
}
|
||||
|
||||
function clean_first_name()
|
||||
{
|
||||
$first_name = trim($this->cleaned_data['first_name']);
|
||||
if ($first_name == mb_strtoupper($first_name)) {
|
||||
return mb_convert_case(mb_strtolower($first_name),
|
||||
MB_CASE_TITLE, 'UTF-8');
|
||||
}
|
||||
return $first_name;
|
||||
}
|
||||
|
||||
function clean_email()
|
||||
{
|
||||
$this->cleaned_data['email'] = mb_strtolower(trim($this->cleaned_data['email']));
|
||||
$user = Pluf::factory('IDF_EmailAddress')->get_user_for_email_address($this->cleaned_data['email']);
|
||||
if ($user != null and $user->id != $this->user->id) {
|
||||
throw new Pluf_Form_Invalid(sprintf(__('The email "%s" is already used.'), $this->cleaned_data['email']));
|
||||
}
|
||||
return $this->cleaned_data['email'];
|
||||
}
|
||||
|
||||
function clean_secondary_mail()
|
||||
{
|
||||
$this->cleaned_data['secondary_mail'] = mb_strtolower(trim($this->cleaned_data['secondary_mail']));
|
||||
if (Pluf::factory('IDF_EmailAddress')->get_user_for_email_address($this->cleaned_data['secondary_mail']) != null) {
|
||||
throw new Pluf_Form_Invalid(sprintf(__('The email "%s" is already used.'), $this->cleaned_data['secondary_mail']));
|
||||
}
|
||||
return $this->cleaned_data['secondary_mail'];
|
||||
}
|
||||
|
||||
function clean_public_key()
|
||||
{
|
||||
$this->cleaned_data['public_key'] =
|
||||
self::checkPublicKey($this->cleaned_data['public_key'],
|
||||
$this->user->id);
|
||||
return $this->cleaned_data['public_key'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if the 2 passwords are the same
|
||||
*/
|
||||
public function clean()
|
||||
{
|
||||
if (!isset($this->errors['password'])
|
||||
&& !isset($this->errors['password2'])) {
|
||||
$password1 = $this->cleaned_data['password'];
|
||||
$password2 = $this->cleaned_data['password2'];
|
||||
if ($password1 != $password2) {
|
||||
throw new Pluf_Form_Invalid(__('The passwords do not match. Please give them again.'));
|
||||
}
|
||||
}
|
||||
|
||||
return $this->cleaned_data;
|
||||
}
|
||||
|
||||
|
||||
}
|
84
indefero/src/IDF/Form/UserChangeEmail.php
Normal file
84
indefero/src/IDF/Form/UserChangeEmail.php
Normal file
@@ -0,0 +1,84 @@
|
||||
<?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-2011 Céondo Ltd and contributors.
|
||||
#
|
||||
# InDefero is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# InDefero is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/**
|
||||
* Change the email address of a user.
|
||||
*
|
||||
*/
|
||||
class IDF_Form_UserChangeEmail extends Pluf_Form
|
||||
{
|
||||
protected $user;
|
||||
|
||||
public function initFields($extra=array())
|
||||
{
|
||||
$this->fields['key'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Your verification key'),
|
||||
'initial' => '',
|
||||
'widget_attrs' => array(
|
||||
'size' => 50,
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
function clean_key()
|
||||
{
|
||||
self::validateKey($this->cleaned_data['key']);
|
||||
return $this->cleaned_data['key'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the key.
|
||||
*
|
||||
* Throw a Pluf_Form_Invalid exception if the key is not valid.
|
||||
*
|
||||
* @param string Key
|
||||
* @return array array($new_email, $user_id, time(), [primary|secondary])
|
||||
*/
|
||||
public static function validateKey($key)
|
||||
{
|
||||
$hash = substr($key, 0, 2);
|
||||
$encrypted = substr($key, 2);
|
||||
if ($hash != substr(md5(Pluf::f('secret_key').$encrypted), 0, 2)) {
|
||||
throw new Pluf_Form_Invalid(__('The validation key is not valid. Please copy/paste it from your confirmation email.'));
|
||||
}
|
||||
$cr = new Pluf_Crypt(md5(Pluf::f('secret_key')));
|
||||
return explode(':', $cr->decrypt($encrypted), 4);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the model in the database.
|
||||
*
|
||||
* @param bool Commit in the database or not. If not, the object
|
||||
* is returned but not saved in the database.
|
||||
* @return Object Model with data set from the form.
|
||||
*/
|
||||
function save($commit=true)
|
||||
{
|
||||
if (!$this->isValid()) {
|
||||
throw new Exception(__('Cannot save the model from an invalid form.'));
|
||||
}
|
||||
return Pluf::f('url_base').Pluf_HTTP_URL_urlForView('IDF_Views_User::changeEmailDo', array($this->cleaned_data['key']));
|
||||
}
|
||||
}
|
66
indefero/src/IDF/Form/WikiConf.php
Normal file
66
indefero/src/IDF/Form/WikiConf.php
Normal file
@@ -0,0 +1,66 @@
|
||||
<?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-2011 Céondo Ltd and contributors.
|
||||
#
|
||||
# InDefero is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# InDefero is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# ***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
/**
|
||||
* Configuration of the labels etc. for the wiki pages.
|
||||
*/
|
||||
class IDF_Form_WikiConf extends Pluf_Form
|
||||
{
|
||||
/**
|
||||
* Defined as constants to easily access the value in the
|
||||
* form in the case nothing is in the db yet.
|
||||
*/
|
||||
const init_predefined = 'Featured = Listed on project home page
|
||||
Phase:Requirements = Project vision and requirements
|
||||
Phase:Design = Project design and key concerns
|
||||
Phase:Implementation = Developers\' guide
|
||||
Phase:QA = Testing plans and QA strategies
|
||||
Phase:Deploy = How to install and configure the program
|
||||
Phase:Support = Plans for user support and advocacy
|
||||
Deprecated = Most users should NOT reference this';
|
||||
|
||||
const init_one_max = '';
|
||||
|
||||
public function initFields($extra=array())
|
||||
{
|
||||
$this->fields['labels_wiki_predefined'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Predefined documentation page labels'),
|
||||
'initial' => self::init_predefined,
|
||||
'widget_attrs' => array('rows' => 13,
|
||||
'cols' => 75),
|
||||
'widget' => 'Pluf_Form_Widget_TextareaInput',
|
||||
));
|
||||
|
||||
$this->fields['labels_wiki_one_max'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
'label' => __('Each documentation page may have at most one label with each of these classes'),
|
||||
'initial' => self::init_one_max,
|
||||
'widget_attrs' => array('size' => 60),
|
||||
));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
205
indefero/src/IDF/Form/WikiPageCreate.php
Normal file
205
indefero/src/IDF/Form/WikiPageCreate.php
Normal file
@@ -0,0 +1,205 @@
|
||||
<?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-2011 Céondo Ltd and contributors.
|
||||
#
|
||||
# InDefero is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# InDefero is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/**
|
||||
* Create a new documentation page.
|
||||
*
|
||||
* This create a new page and the corresponding revision.
|
||||
*
|
||||
*/
|
||||
class IDF_Form_WikiPageCreate extends Pluf_Form
|
||||
{
|
||||
public $user = null;
|
||||
public $project = null;
|
||||
public $show_full = false;
|
||||
|
||||
public function initFields($extra=array())
|
||||
{
|
||||
$initial = __('# Introduction
|
||||
|
||||
Add your content here.
|
||||
|
||||
|
||||
# Details
|
||||
|
||||
Add your content here. Format your content with:
|
||||
|
||||
* Text in **bold** or *italic*.
|
||||
* Headings, paragraphs, and lists.
|
||||
* Links to other [[WikiPage]].
|
||||
');
|
||||
$this->user = $extra['user'];
|
||||
$this->project = $extra['project'];
|
||||
if ($this->user->hasPerm('IDF.project-owner', $this->project)
|
||||
or $this->user->hasPerm('IDF.project-member', $this->project)) {
|
||||
$this->show_full = true;
|
||||
}
|
||||
$initname = (!empty($extra['name'])) ? $extra['name'] : __('PageName');
|
||||
$this->fields['title'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Page title'),
|
||||
'initial' => $initname,
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 200,
|
||||
'size' => 67,
|
||||
),
|
||||
'help_text' => __('The page name must contains only letters, digits and the dash (-) character.'),
|
||||
));
|
||||
$this->fields['summary'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Description'),
|
||||
'help_text' => __('This one line description is displayed in the list of pages.'),
|
||||
'initial' => '',
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 200,
|
||||
'size' => 67,
|
||||
),
|
||||
));
|
||||
$this->fields['content'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Content'),
|
||||
'initial' => $initial,
|
||||
'widget' => 'Pluf_Form_Widget_TextareaInput',
|
||||
'widget_attrs' => array(
|
||||
'cols' => 68,
|
||||
'rows' => 26,
|
||||
),
|
||||
));
|
||||
|
||||
if ($this->show_full) {
|
||||
for ($i=1;$i<4;$i++) {
|
||||
$this->fields['label'.$i] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
'label' => __('Labels'),
|
||||
'initial' => '',
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 50,
|
||||
'size' => 20,
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function clean_title()
|
||||
{
|
||||
$title = $this->cleaned_data['title'];
|
||||
if (preg_match('/[^a-zA-Z0-9\-]/', $title)) {
|
||||
throw new Pluf_Form_Invalid(__('The title contains invalid characters.'));
|
||||
}
|
||||
$sql = new Pluf_SQL('project=%s AND title=%s',
|
||||
array($this->project->id, $title));
|
||||
$pages = Pluf::factory('IDF_Wiki_Page')->getList(array('filter'=>$sql->gen()));
|
||||
if ($pages->count() > 0) {
|
||||
throw new Pluf_Form_Invalid(__('A page with this title already exists.'));
|
||||
}
|
||||
return $title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the interconnection in the form.
|
||||
*/
|
||||
public function clean()
|
||||
{
|
||||
if (!$this->show_full) {
|
||||
return $this->cleaned_data;
|
||||
}
|
||||
$conf = new IDF_Conf();
|
||||
$conf->setProject($this->project);
|
||||
$onemax = array();
|
||||
foreach (explode(',', $conf->getVal('labels_wiki_one_max', IDF_Form_WikiConf::init_one_max)) as $class) {
|
||||
if (trim($class) != '') {
|
||||
$onemax[] = mb_strtolower(trim($class));
|
||||
}
|
||||
}
|
||||
$count = array();
|
||||
for ($i=1;$i<4;$i++) {
|
||||
$this->cleaned_data['label'.$i] = trim($this->cleaned_data['label'.$i]);
|
||||
if (strpos($this->cleaned_data['label'.$i], ':') !== false) {
|
||||
list($class, $name) = explode(':', $this->cleaned_data['label'.$i], 2);
|
||||
list($class, $name) = array(mb_strtolower(trim($class)),
|
||||
trim($name));
|
||||
} else {
|
||||
$class = 'other';
|
||||
$name = $this->cleaned_data['label'.$i];
|
||||
}
|
||||
if (!isset($count[$class])) $count[$class] = 1;
|
||||
else $count[$class] += 1;
|
||||
if (in_array($class, $onemax) and $count[$class] > 1) {
|
||||
if (!isset($this->errors['label'.$i])) $this->errors['label'.$i] = array();
|
||||
$this->errors['label'.$i][] = sprintf(__('You cannot provide more than one label from the %s class to a page.'), $class);
|
||||
throw new Pluf_Form_Invalid(__('You provided an invalid label.'));
|
||||
}
|
||||
}
|
||||
return $this->cleaned_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the model in the database.
|
||||
*
|
||||
* @param bool Commit in the database or not. If not, the object
|
||||
* is returned but not saved in the database.
|
||||
* @return Object Model with data set from the form.
|
||||
*/
|
||||
function save($commit=true)
|
||||
{
|
||||
if (!$this->isValid()) {
|
||||
throw new Exception(__('Cannot save the model from an invalid form.'));
|
||||
}
|
||||
// Add a tag for each label
|
||||
$tags = array();
|
||||
if ($this->show_full) {
|
||||
for ($i=1;$i<4;$i++) {
|
||||
if (strlen($this->cleaned_data['label'.$i]) > 0) {
|
||||
if (strpos($this->cleaned_data['label'.$i], ':') !== false) {
|
||||
list($class, $name) = explode(':', $this->cleaned_data['label'.$i], 2);
|
||||
list($class, $name) = array(trim($class), trim($name));
|
||||
} else {
|
||||
$class = 'Other';
|
||||
$name = trim($this->cleaned_data['label'.$i]);
|
||||
}
|
||||
$tags[] = IDF_Tag::add($name, $this->project, $class);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Create the page
|
||||
$page = new IDF_Wiki_Page();
|
||||
$page->project = $this->project;
|
||||
$page->submitter = $this->user;
|
||||
$page->summary = trim($this->cleaned_data['summary']);
|
||||
$page->title = trim($this->cleaned_data['title']);
|
||||
$page->create();
|
||||
foreach ($tags as $tag) {
|
||||
$page->setAssoc($tag);
|
||||
}
|
||||
// add the first revision
|
||||
$rev = new IDF_Wiki_PageRevision();
|
||||
$rev->wikipage = $page;
|
||||
$rev->content = $this->cleaned_data['content'];
|
||||
$rev->submitter = $this->user;
|
||||
$rev->summary = __('Initial page creation');
|
||||
$rev->create();
|
||||
$rev->notify($this->project->getConf());
|
||||
return $page;
|
||||
}
|
||||
}
|
64
indefero/src/IDF/Form/WikiPageDelete.php
Normal file
64
indefero/src/IDF/Form/WikiPageDelete.php
Normal file
@@ -0,0 +1,64 @@
|
||||
<?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-2011 Céondo Ltd and contributors.
|
||||
#
|
||||
# InDefero is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# InDefero is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/**
|
||||
* Delete a documentation page.
|
||||
*
|
||||
* This is a hard delete of the page and the revisions.
|
||||
*
|
||||
*/
|
||||
class IDF_Form_WikiPageDelete extends Pluf_Form
|
||||
{
|
||||
protected $page = null;
|
||||
|
||||
public function initFields($extra=array())
|
||||
{
|
||||
$this->page = $extra['page'];
|
||||
$this->fields['confirm'] = new Pluf_Form_Field_Boolean(
|
||||
array('required' => true,
|
||||
'label' => __('Yes, I understand that the page and all its revisions will be deleted.'),
|
||||
'initial' => '',
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the confirmation.
|
||||
*/
|
||||
public function clean_confirm()
|
||||
{
|
||||
if (!$this->cleaned_data['confirm']) {
|
||||
throw new Pluf_Form_Invalid(__('You need to confirm the deletion.'));
|
||||
}
|
||||
return $this->cleaned_data['confirm'];
|
||||
}
|
||||
|
||||
|
||||
function save($commit=true)
|
||||
{
|
||||
if (!$this->isValid()) {
|
||||
throw new Exception(__('Cannot save the model from an invalid form.'));
|
||||
}
|
||||
$this->page->delete();
|
||||
return true;
|
||||
}
|
||||
}
|
242
indefero/src/IDF/Form/WikiPageUpdate.php
Normal file
242
indefero/src/IDF/Form/WikiPageUpdate.php
Normal file
@@ -0,0 +1,242 @@
|
||||
<?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-2011 Céondo Ltd and contributors.
|
||||
#
|
||||
# InDefero is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# InDefero is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/**
|
||||
* Update a documentation page.
|
||||
*
|
||||
* This add a corresponding revision.
|
||||
*
|
||||
*/
|
||||
class IDF_Form_WikiPageUpdate extends Pluf_Form
|
||||
{
|
||||
public $user = null;
|
||||
public $project = null;
|
||||
public $page = null;
|
||||
public $show_full = false;
|
||||
|
||||
|
||||
public function initFields($extra=array())
|
||||
{
|
||||
$this->page = $extra['page'];
|
||||
$this->user = $extra['user'];
|
||||
$this->project = $extra['project'];
|
||||
if ($this->user->hasPerm('IDF.project-owner', $this->project)
|
||||
or $this->user->hasPerm('IDF.project-member', $this->project)) {
|
||||
$this->show_full = true;
|
||||
}
|
||||
if ($this->show_full) {
|
||||
$this->fields['title'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Page title'),
|
||||
'initial' => $this->page->title,
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 200,
|
||||
'size' => 67,
|
||||
),
|
||||
'help_text' => __('The page name must contains only letters, digits and the dash (-) character.'),
|
||||
));
|
||||
$this->fields['summary'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Description'),
|
||||
'help_text' => __('This one line description is displayed in the list of pages.'),
|
||||
'initial' => $this->page->summary,
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 200,
|
||||
'size' => 67,
|
||||
),
|
||||
));
|
||||
}
|
||||
$rev = $this->page->get_current_revision();
|
||||
$this->fields['content'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Content'),
|
||||
'initial' => $rev->content,
|
||||
'widget' => 'Pluf_Form_Widget_TextareaInput',
|
||||
'widget_attrs' => array(
|
||||
'cols' => 68,
|
||||
'rows' => 26,
|
||||
),
|
||||
));
|
||||
$this->fields['comment'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Comment'),
|
||||
'help_text' => __('One line to describe the changes you made.'),
|
||||
'initial' => '',
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 200,
|
||||
'size' => 67,
|
||||
),
|
||||
));
|
||||
|
||||
if ($this->show_full) {
|
||||
$tags = $this->page->get_tags_list();
|
||||
for ($i=1;$i<4;$i++) {
|
||||
$initial = '';
|
||||
if (isset($tags[$i-1])) {
|
||||
if ($tags[$i-1]->class != 'Other') {
|
||||
$initial = (string) $tags[$i-1];
|
||||
} else {
|
||||
$initial = $tags[$i-1]->name;
|
||||
}
|
||||
}
|
||||
$this->fields['label'.$i] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => false,
|
||||
'label' => __('Labels'),
|
||||
'initial' => $initial,
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 50,
|
||||
'size' => 20,
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function clean_title()
|
||||
{
|
||||
$title = $this->cleaned_data['title'];
|
||||
if (preg_match('/[^a-zA-Z0-9\-]/', $title)) {
|
||||
throw new Pluf_Form_Invalid(__('The title contains invalid characters.'));
|
||||
}
|
||||
$sql = new Pluf_SQL('project=%s AND title=%s',
|
||||
array($this->project->id, $title));
|
||||
$pages = Pluf::factory('IDF_Wiki_Page')->getList(array('filter'=>$sql->gen()));
|
||||
if ($pages->count() > 0 and $pages[0]->id != $this->page->id) {
|
||||
throw new Pluf_Form_Invalid(__('A page with this title already exists.'));
|
||||
}
|
||||
return $title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the interconnection in the form.
|
||||
*/
|
||||
public function clean()
|
||||
{
|
||||
if (!$this->show_full) {
|
||||
return $this->cleaned_data;
|
||||
}
|
||||
$conf = new IDF_Conf();
|
||||
$conf->setProject($this->project);
|
||||
$onemax = array();
|
||||
foreach (explode(',', $conf->getVal('labels_wiki_one_max', IDF_Form_WikiConf::init_one_max)) as $class) {
|
||||
if (trim($class) != '') {
|
||||
$onemax[] = mb_strtolower(trim($class));
|
||||
}
|
||||
}
|
||||
$count = array();
|
||||
for ($i=1;$i<4;$i++) {
|
||||
$this->cleaned_data['label'.$i] = trim($this->cleaned_data['label'.$i]);
|
||||
if (strpos($this->cleaned_data['label'.$i], ':') !== false) {
|
||||
list($class, $name) = explode(':', $this->cleaned_data['label'.$i], 2);
|
||||
list($class, $name) = array(mb_strtolower(trim($class)),
|
||||
trim($name));
|
||||
} else {
|
||||
$class = 'other';
|
||||
$name = $this->cleaned_data['label'.$i];
|
||||
}
|
||||
if (!isset($count[$class])) $count[$class] = 1;
|
||||
else $count[$class] += 1;
|
||||
if (in_array($class, $onemax) and $count[$class] > 1) {
|
||||
if (!isset($this->errors['label'.$i])) $this->errors['label'.$i] = array();
|
||||
$this->errors['label'.$i][] = sprintf(__('You cannot provide more than one label from the %s class to a page.'), $class);
|
||||
throw new Pluf_Form_Invalid(__('You provided an invalid label.'));
|
||||
}
|
||||
}
|
||||
return $this->cleaned_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the model in the database.
|
||||
*
|
||||
* @param bool Commit in the database or not. If not, the object
|
||||
* is returned but not saved in the database.
|
||||
* @return Object Model with data set from the form.
|
||||
*/
|
||||
function save($commit=true)
|
||||
{
|
||||
if (!$this->isValid()) {
|
||||
throw new Exception(__('Cannot save the model from an invalid form.'));
|
||||
}
|
||||
if ($this->show_full) {
|
||||
$tagids = array();
|
||||
$tags = array();
|
||||
for ($i=1;$i<4;$i++) {
|
||||
if (strlen($this->cleaned_data['label'.$i]) > 0) {
|
||||
if (strpos($this->cleaned_data['label'.$i], ':') !== false) {
|
||||
list($class, $name) = explode(':', $this->cleaned_data['label'.$i], 2);
|
||||
list($class, $name) = array(trim($class), trim($name));
|
||||
} else {
|
||||
$class = 'Other';
|
||||
$name = trim($this->cleaned_data['label'.$i]);
|
||||
}
|
||||
$tag = IDF_Tag::add($name, $this->project, $class);
|
||||
$tags[] = $tag;
|
||||
$tagids[] = $tag->id;
|
||||
}
|
||||
}
|
||||
// Compare between the old and the new data
|
||||
$changes = array();
|
||||
$oldtags = $this->page->get_tags_list();
|
||||
foreach ($tags as $tag) {
|
||||
if (!Pluf_Model_InArray($tag, $oldtags)) {
|
||||
if (!isset($changes['lb'])) $changes['lb'] = array();
|
||||
if ($tag->class != 'Other') {
|
||||
$changes['lb'][] = (string) $tag; //new tag
|
||||
} else {
|
||||
$changes['lb'][] = (string) $tag->name;
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach ($oldtags as $tag) {
|
||||
if (!Pluf_Model_InArray($tag, $tags)) {
|
||||
if (!isset($changes['lb'])) $changes['lb'] = array();
|
||||
if ($tag->class != 'Other') {
|
||||
$changes['lb'][] = '-'.(string) $tag; //new tag
|
||||
} else {
|
||||
$changes['lb'][] = '-'.(string) $tag->name;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (trim($this->page->summary) != trim($this->cleaned_data['summary'])) {
|
||||
$changes['su'] = trim($this->cleaned_data['summary']);
|
||||
}
|
||||
// Update the page
|
||||
$this->page->batchAssoc('IDF_Tag', $tagids);
|
||||
$this->page->summary = trim($this->cleaned_data['summary']);
|
||||
$this->page->title = trim($this->cleaned_data['title']);
|
||||
} else {
|
||||
$changes = array();
|
||||
}
|
||||
$this->page->update();
|
||||
// add the new revision
|
||||
$rev = new IDF_Wiki_PageRevision();
|
||||
$rev->wikipage = $this->page;
|
||||
$rev->content = $this->cleaned_data['content'];
|
||||
$rev->submitter = $this->user;
|
||||
$rev->summary = $this->cleaned_data['comment'];
|
||||
$rev->changes = $changes;
|
||||
$rev->create();
|
||||
$rev->notify($this->project->getConf(), false);
|
||||
return $this->page;
|
||||
}
|
||||
}
|
169
indefero/src/IDF/Form/WikiResourceCreate.php
Normal file
169
indefero/src/IDF/Form/WikiResourceCreate.php
Normal file
@@ -0,0 +1,169 @@
|
||||
<?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-2011 Céondo Ltd and contributors.
|
||||
#
|
||||
# InDefero is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# InDefero is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/**
|
||||
* Create a new resource.
|
||||
*
|
||||
* This create a new resource and the corresponding revision.
|
||||
*
|
||||
*/
|
||||
class IDF_Form_WikiResourceCreate extends Pluf_Form
|
||||
{
|
||||
public $user = null;
|
||||
public $project = null;
|
||||
public $show_full = false;
|
||||
|
||||
public function initFields($extra=array())
|
||||
{
|
||||
$this->project = $extra['project'];
|
||||
$this->user = $extra['user'];
|
||||
$initname = (!empty($extra['name'])) ? $extra['name'] : __('ResourceName');
|
||||
|
||||
$this->fields['title'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Resource title'),
|
||||
'initial' => $initname,
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 200,
|
||||
'size' => 67,
|
||||
),
|
||||
'help_text' => __('The resource name must contains only letters, digits and the dash (-) character.'),
|
||||
));
|
||||
$this->fields['summary'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Description'),
|
||||
'help_text' => __('This one line description is displayed in the list of resources.'),
|
||||
'initial' => '',
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 200,
|
||||
'size' => 67,
|
||||
),
|
||||
));
|
||||
|
||||
$this->fields['file'] = new Pluf_Form_Field_File(
|
||||
array('required' => true,
|
||||
'label' => __('File'),
|
||||
'initial' => '',
|
||||
'max_size' => Pluf::f('max_upload_size', 2097152),
|
||||
'move_function_params' => array('upload_path' => $this->getTempUploadPath(),
|
||||
'upload_path_create' => true,
|
||||
'upload_overwrite' => true),
|
||||
));
|
||||
}
|
||||
|
||||
public function clean_title()
|
||||
{
|
||||
$title = $this->cleaned_data['title'];
|
||||
if (preg_match('/[^a-zA-Z0-9\-]/', $title)) {
|
||||
throw new Pluf_Form_Invalid(__('The title contains invalid characters.'));
|
||||
}
|
||||
$sql = new Pluf_SQL('project=%s AND title=%s',
|
||||
array($this->project->id, $title));
|
||||
$resources = Pluf::factory('IDF_Wiki_Resource')->getList(array('filter'=>$sql->gen()));
|
||||
if ($resources->count() > 0) {
|
||||
throw new Pluf_Form_Invalid(__('A resource with this title already exists.'));
|
||||
}
|
||||
return $title;
|
||||
}
|
||||
|
||||
public function clean_file()
|
||||
{
|
||||
// FIXME: we do the same in IDF_Form_Upload and a couple of other places as well
|
||||
$extra = strtolower(implode('|', explode(' ', Pluf::f('idf_extra_upload_ext'))));
|
||||
if (strlen($extra)) $extra .= '|';
|
||||
if (!preg_match('/\.('.$extra.'png|jpg|jpeg|gif|bmp|psd|tif|aiff|asf|avi|bz2|css|doc|eps|gz|jar|mdtext|mid|mov|mp3|mpg|ogg|pdf|ppt|ps|qt|ra|ram|rm|rtf|sdd|sdw|sit|sxi|sxw|swf|tgz|txt|wav|xls|xml|war|wmv|zip)$/i', $this->cleaned_data['file'])) {
|
||||
@unlink($this->getTempUploadPath().$this->cleaned_data['file']);
|
||||
throw new Pluf_Form_Invalid(__('For security reasons, you cannot upload a file with this extension.'));
|
||||
}
|
||||
return $this->cleaned_data['file'];
|
||||
}
|
||||
|
||||
/**
|
||||
* If we have uploaded a file, but the form failed remove it.
|
||||
*
|
||||
*/
|
||||
function failed()
|
||||
{
|
||||
if (!empty($this->cleaned_data['file'])
|
||||
and file_exists($this->getTempUploadPath().$this->cleaned_data['file'])) {
|
||||
@unlink($this->getTempUploadPath().$this->cleaned_data['file']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the model in the database.
|
||||
*
|
||||
* @param bool Commit in the database or not. If not, the object
|
||||
* is returned but not saved in the database.
|
||||
* @return Object Model with data set from the form.
|
||||
*/
|
||||
function save($commit=true)
|
||||
{
|
||||
if (!$this->isValid()) {
|
||||
throw new Exception(__('Cannot save the model from an invalid form.'));
|
||||
}
|
||||
|
||||
$tempFile = $this->getTempUploadPath().$this->cleaned_data['file'];
|
||||
list($mimeType, , $extension) = IDF_FileUtil::getMimeType($tempFile);
|
||||
|
||||
// create the resource
|
||||
$resource = new IDF_Wiki_Resource();
|
||||
$resource->project = $this->project;
|
||||
$resource->submitter = $this->user;
|
||||
$resource->summary = trim($this->cleaned_data['summary']);
|
||||
$resource->title = trim($this->cleaned_data['title']);
|
||||
$resource->mime_type = $mimeType;
|
||||
$resource->create();
|
||||
|
||||
// add the first revision
|
||||
$rev = new IDF_Wiki_ResourceRevision();
|
||||
$rev->wikiresource = $resource;
|
||||
$rev->submitter = $this->user;
|
||||
$rev->summary = __('Initial resource creation');
|
||||
$rev->filesize = filesize($tempFile);
|
||||
$rev->fileext = $extension;
|
||||
$rev->create();
|
||||
|
||||
$finalFile = $rev->getFilePath();
|
||||
if (!@mkdir(dirname($finalFile), 0755, true)) {
|
||||
@unlink($tempFile);
|
||||
$rev->delete();
|
||||
$resource->delete();
|
||||
throw new Exception('could not create final resource path');
|
||||
}
|
||||
|
||||
if (!@rename($tempFile, $finalFile)) {
|
||||
@unlink($tempFile);
|
||||
$rev->delete();
|
||||
$resource->delete();
|
||||
throw new Exception('could not move resource to final location');
|
||||
}
|
||||
|
||||
return $resource;
|
||||
}
|
||||
|
||||
private function getTempUploadPath()
|
||||
{
|
||||
return Pluf::f('upload_path').'/'.$this->project->shortname.'/wiki/temp/';
|
||||
}
|
||||
}
|
64
indefero/src/IDF/Form/WikiResourceDelete.php
Normal file
64
indefero/src/IDF/Form/WikiResourceDelete.php
Normal file
@@ -0,0 +1,64 @@
|
||||
<?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-2011 Céondo Ltd and contributors.
|
||||
#
|
||||
# InDefero is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# InDefero is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/**
|
||||
* Delete a documentation page.
|
||||
*
|
||||
* This is a hard delete of the page and the revisions.
|
||||
*
|
||||
*/
|
||||
class IDF_Form_WikiResourceDelete extends Pluf_Form
|
||||
{
|
||||
protected $resource = null;
|
||||
|
||||
public function initFields($extra=array())
|
||||
{
|
||||
$this->resource = $extra['resource'];
|
||||
$this->fields['confirm'] = new Pluf_Form_Field_Boolean(
|
||||
array('required' => true,
|
||||
'label' => __('Yes, I understand that the resource and all its revisions will be deleted.'),
|
||||
'initial' => '',
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the confirmation.
|
||||
*/
|
||||
public function clean_confirm()
|
||||
{
|
||||
if (!$this->cleaned_data['confirm']) {
|
||||
throw new Pluf_Form_Invalid(__('You need to confirm the deletion.'));
|
||||
}
|
||||
return $this->cleaned_data['confirm'];
|
||||
}
|
||||
|
||||
|
||||
function save($commit=true)
|
||||
{
|
||||
if (!$this->isValid()) {
|
||||
throw new Exception(__('Cannot save the model from an invalid form.'));
|
||||
}
|
||||
$this->resource->delete();
|
||||
return true;
|
||||
}
|
||||
}
|
161
indefero/src/IDF/Form/WikiResourceUpdate.php
Normal file
161
indefero/src/IDF/Form/WikiResourceUpdate.php
Normal file
@@ -0,0 +1,161 @@
|
||||
<?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-2011 Céondo Ltd and contributors.
|
||||
#
|
||||
# InDefero is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# InDefero is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/**
|
||||
* Update a documentation page.
|
||||
*
|
||||
* This add a corresponding revision.
|
||||
*
|
||||
*/
|
||||
class IDF_Form_WikiResourceUpdate extends Pluf_Form
|
||||
{
|
||||
public $user = null;
|
||||
public $project = null;
|
||||
public $page = null;
|
||||
public $show_full = false;
|
||||
|
||||
|
||||
public function initFields($extra=array())
|
||||
{
|
||||
$this->resource = $extra['resource'];
|
||||
$this->user = $extra['user'];
|
||||
$this->project = $extra['project'];
|
||||
|
||||
$this->fields['summary'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Description'),
|
||||
'help_text' => __('This one line description is displayed in the list of resources.'),
|
||||
'initial' => $this->resource->summary,
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 200,
|
||||
'size' => 67,
|
||||
),
|
||||
));
|
||||
$this->fields['file'] = new Pluf_Form_Field_File(
|
||||
array('required' => true,
|
||||
'label' => __('File'),
|
||||
'initial' => '',
|
||||
'max_size' => Pluf::f('max_upload_size', 2097152),
|
||||
'move_function_params' => array('upload_path' => $this->getTempUploadPath(),
|
||||
'upload_path_create' => true,
|
||||
'upload_overwrite' => true),
|
||||
));
|
||||
|
||||
$this->fields['comment'] = new Pluf_Form_Field_Varchar(
|
||||
array('required' => true,
|
||||
'label' => __('Comment'),
|
||||
'help_text' => __('One line to describe the changes you made.'),
|
||||
'initial' => '',
|
||||
'widget_attrs' => array(
|
||||
'maxlength' => 200,
|
||||
'size' => 67,
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
public function clean_file()
|
||||
{
|
||||
// FIXME: we do the same in IDF_Form_Upload and a couple of other places as well
|
||||
$extra = strtolower(implode('|', explode(' ', Pluf::f('idf_extra_upload_ext'))));
|
||||
if (strlen($extra)) $extra .= '|';
|
||||
if (!preg_match('/\.('.$extra.'png|jpg|jpeg|gif|bmp|psd|tif|aiff|asf|avi|bz2|css|doc|eps|gz|jar|mdtext|mid|mov|mp3|mpg|ogg|pdf|ppt|ps|qt|ra|ram|rm|rtf|sdd|sdw|sit|sxi|sxw|swf|tgz|txt|wav|xls|xml|war|wmv|zip)$/i', $this->cleaned_data['file'])) {
|
||||
@unlink($this->getTempUploadPath().$this->cleaned_data['file']);
|
||||
throw new Pluf_Form_Invalid(__('For security reasons, you cannot upload a file with this extension.'));
|
||||
}
|
||||
|
||||
list($mimeType, , $extension) = IDF_FileUtil::getMimeType($this->getTempUploadPath().$this->cleaned_data['file']);
|
||||
if ($this->resource->mime_type != $mimeType) {
|
||||
throw new Pluf_Form_Invalid(sprintf(
|
||||
__('The mime type of the uploaded file "%1$s" does not match the mime type of this resource "%2$s"'),
|
||||
$mimeType, $this->resource->mime_type
|
||||
));
|
||||
}
|
||||
$this->cleaned_data['fileext'] = $extension;
|
||||
|
||||
if (md5_file($this->getTempUploadPath().$this->cleaned_data['file']) ===
|
||||
md5_file($this->resource->get_current_revision()->getFilePath())) {
|
||||
throw new Pluf_Form_Invalid(__('The current version of the resource and the uploaded file are equal.'));
|
||||
}
|
||||
return $this->cleaned_data['file'];
|
||||
}
|
||||
|
||||
/**
|
||||
* If we have uploaded a file, but the form failed remove it.
|
||||
*
|
||||
*/
|
||||
function failed()
|
||||
{
|
||||
if (!empty($this->cleaned_data['file'])
|
||||
and file_exists($this->getTempUploadPath().$this->cleaned_data['file'])) {
|
||||
@unlink($this->getTempUploadPath().$this->cleaned_data['file']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the model in the database.
|
||||
*
|
||||
* @param bool Commit in the database or not. If not, the object
|
||||
* is returned but not saved in the database.
|
||||
* @return Object Model with data set from the form.
|
||||
*/
|
||||
function save($commit=true)
|
||||
{
|
||||
if (!$this->isValid()) {
|
||||
throw new Exception(__('Cannot save the model from an invalid form.'));
|
||||
}
|
||||
|
||||
$tempFile = $this->getTempUploadPath().$this->cleaned_data['file'];
|
||||
|
||||
$this->resource->summary = trim($this->cleaned_data['summary']);
|
||||
$this->resource->update();
|
||||
|
||||
// add the new revision
|
||||
$rev = new IDF_Wiki_ResourceRevision();
|
||||
$rev->wikiresource = $this->resource;
|
||||
$rev->submitter = $this->user;
|
||||
$rev->summary = $this->cleaned_data['comment'];
|
||||
$rev->filesize = filesize($tempFile);
|
||||
$rev->fileext = $this->cleaned_data['fileext'];
|
||||
$rev->create();
|
||||
|
||||
$finalFile = $rev->getFilePath();
|
||||
if (!is_dir(dirname($finalFile))) {
|
||||
@unlink($tempFile);
|
||||
$rev->delete();
|
||||
throw new Exception('resource path does not exist');
|
||||
}
|
||||
|
||||
if (!@rename($tempFile, $finalFile)) {
|
||||
@unlink($tempFile);
|
||||
$rev->delete();
|
||||
throw new Exception('could not move resource to final location');
|
||||
}
|
||||
|
||||
return $this->resource;
|
||||
}
|
||||
|
||||
private function getTempUploadPath()
|
||||
{
|
||||
return Pluf::f('upload_path').'/'.$this->project->shortname.'/wiki/temp/';
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user