Source for file pepr-proposal.php
Documentation is available at pepr-proposal.php
* Establishes the procedures, objects and variables used throughout PEPr.
* The <var>$proposalStatiMap</var> is defined here.
* NOTE: Proposal constants are defined in pearweb/include/pear-config.php.
* This source file is subject to version 3.0 of the PHP license,
* that is bundled with this package in the file LICENSE, and is
* available through the world-wide-web at the following URI:
* http://www.php.net/license/3_0.txt.
* If you did not receive a copy of the PHP license and are unable to
* obtain it through the world-wide-web, please send a note to
* license@php.net so we can mail you a copy immediately.
* @author Tobias Schlitt <toby@php.net>
* @author Daniel Convissor <danielc@php.net>
* @copyright Copyright (c) 1997-2005 The PHP Group
* @license http://www.php.net/license/3_0.txt PHP License
* @version $Id: pepr-proposal.php 309391 2011-03-18 15:37:50Z till $
global $proposalStatiMap;
$proposalStatiMap = array (
'proposal' => 'Proposed',
'vote' => 'Called for Votes',
foreach ($dbhResArr as $name => $value) {
if ($name == 'pkg_describtion') {
$name = 'pkg_description';
'link' => 'http://' . PEAR_CHANNELNAME . '/pepr/pepr-proposal-show.php?id='. $this->id,
Proposer: '.user_link ($this->user_handle, true ). '<br />
// Switching markup types
include_once 'Text/Wiki.php';
$wiki->disableRule ('wikilink');
include_once 'HTML/BBCodeParser.php';
$bbparser = new HTML_BBCodeParser (array ('filters' => 'Basic,Images,Links,Lists,Extended'));
$sql = "SELECT pkg_name, pkg_category, pkg_license, pkg_describtion, pkg_deps
FROM package_proposals WHERE id = ". $id;
$res = $dbh->getRow ($sql, null , DB_FETCHMODE_ASSOC );
* Look up proposal information based on the proposal ID number
* @param object $dbh the current DB object
* @param int $id the ID number of the proposal being looked for
* @return object a new proposal object. false if the $id provided is
* not numeric. null if the $id doesn't refer to
$sql = "SELECT *, UNIX_TIMESTAMP(draft_date) as draft_date,
UNIX_TIMESTAMP(proposal_date) as proposal_date,
UNIX_TIMESTAMP(vote_date) as vote_date,
UNIX_TIMESTAMP(longened_date) as longened_date
FROM package_proposals WHERE id = ". $id;
$res = $dbh->getRow ($sql, null , DB_FETCHMODE_ASSOC );
return self ::getAll ($dbh, null , $n, 'proposal_date DESC');
* Receive a complete bunch of proposals.
* @param object $dbh the current DB object
* @param string $status the of the proposals to select
* @param int $limit limit the number of proposals to receive
* @param string $order an SQL expression used by the "ORDER BY" statement
* @return array an array of proposal objects (maybe with 0 elements,
* if no proposals received)
function &getAll(&$dbh, $status = null , $limit = null , $order = null )
$sql = "SELECT *, UNIX_TIMESTAMP(draft_date) as draft_date,
UNIX_TIMESTAMP(proposal_date) as proposal_date,
UNIX_TIMESTAMP(vote_date) as vote_date,
UNIX_TIMESTAMP(longened_date) as longened_date
$sql .= " WHERE status = '". $status. "'";
$sql .= " ORDER BY status ASC, draft_date DESC";
$sql .= " ORDER BY ". $order;
$res = $dbh->query ($sql);
while ($set = $res->fetchRow (DB_FETCHMODE_ASSOC )) {
$result[$set['id']] = new proposal($set);
function &search($searchString)
'/%/', '/_/', '/ /', '/\*/', '/\?/');
'\%', '\_', '%', '%', '_');
$searchString = "%". preg_replace($replacers, $replacements, $searchString). "%";
$sql = "SELECT *, UNIX_TIMESTAMP(draft_date) as draft_date,
UNIX_TIMESTAMP(proposal_date) as proposal_date,
UNIX_TIMESTAMP(vote_date) as vote_date,
UNIX_TIMESTAMP(longened_date) as longened_date
WHERE pkg_describtion LIKE ". $dbh->quoteSmart ($searchString). "
OR pkg_name LIKE ". $dbh->quoteSmart ($searchString). "
OR pkg_category LIKE ". $dbh->quoteSmart ($searchString). "
ORDER BY status ASC, draft_date DESC";
$res = $dbh->query ($sql);
while ($set = $res->fetchRow (DB_FETCHMODE_ASSOC )) {
$result[$set['id']] = new proposal($set);
return PEAR ::raiseError ("Not initialized");
return PEAR ::raiseError ("Not initialized");
$test = $dbh->getOne ('SELECT id FROM package_proposals WHERE pkg_category = ?
AND pkg_name = ? AND user_handle = ? AND id <> ?', array ($this->pkg_category,
$next = $dbh->getAll ('SELECT id, status FROM package_proposals WHERE pkg_category = ?
AND pkg_name = ? AND user_handle = ? AND id <> ?', array ($this->pkg_category,
$test = $dbh->getOne ('SELECT id FROM package_proposals WHERE pkg_category = ?
AND pkg_name = ? AND user_handle = ?', array ($this->pkg_category,
$next = $dbh->getAll ('SELECT id, status FROM package_proposals WHERE pkg_category = ?
AND pkg_name = ? AND user_handle = ?', array ($this->pkg_category,
if ($p[1 ] != 'finished') {
// proposal was accepted, can't repropose
$inf = $dbh->getAll ('SELECT pkg_name, pkg_category FROM package_proposals
WHERE id = ?', array ($this->id));
return PEAR ::raiseError ('A proposal with that Category -'
. ' Name combination already exists.');
$sql = "UPDATE package_proposals SET
pkg_name = ". $dbh->quoteSmart ($this->pkg_name). ",
pkg_license = ". $dbh->quoteSmart ($this->pkg_license). ",
pkg_deps = ". $dbh->quoteSmart ($this->pkg_deps)." ,
vote_date = FROM_UNIXTIME({ $this->vote_date}),
status = ".$dbh->quoteSmart ($this->status). ",
user_handle = ". $dbh->quoteSmart ($this->user_handle). ",
markup = ". $dbh->quoteSmart ($this->markup). "
$dbh->pushErrorHandling (PEAR_ERROR_RETURN );
$res = $dbh->query ($sql);
$dbh->popErrorHandling ();
if ($res->getCode () == DB_ERROR_CONSTRAINT ) {
return PEAR::raiseError('A proposal with that Category -'
. ' Name combination already exists.',
$res->getCode (), null , null , $res->getUserInfo ());
return PEAR::raiseError($res->getMessage (),
$res->getCode (), null , null ,
if ($dbh->getOne ('SELECT id FROM package_proposals WHERE pkg_category = ?
AND pkg_name = ? AND user_handle <> ?', array ($this->pkg_category,
return PEAR::raiseError('A proposal with that Category -'
. ' Name combination already exists.');
// proposal was accepted, can't repropose
return PEAR::raiseError('A non-rejected proposal with that Category -'
. ' Name combination already exists.');
$sql = "INSERT INTO package_proposals (pkg_category, pkg_name, pkg_license, pkg_describtion,
pkg_deps, draft_date, status, user_handle, markup) VALUES (
FROM_UNIXTIME(".time (). "),
". $dbh->quoteSmart ($this->status). ",
". $dbh->quoteSmart ($this->markup). ")";
$dbh->pushErrorHandling (PEAR_ERROR_RETURN );
$res = $dbh->query ($sql);
$dbh->popErrorHandling ();
if ($res->getCode () == DB_ERROR_CONSTRAINT ) {
return PEAR::raiseError('A proposal with that Catetory -'
. ' Name combination already exists.',
$res->getCode (), null , null , $res->getUserInfo ());
return PEAR::raiseError($res->getMessage (),
$res->getCode (), null , null ,
$this->id = mysqli_insert_id ($dbh->connection );
ppLink::deleteAll($dbh, $this->id);
foreach ($this->links as $link) {
if (!empty($link->url )) {
$res = $link->store ($dbh, $this->id);
if (!empty($this->comment)) {
$this->comment->store ($dbh, $this->id);
function addVote($dbh, $vote)
if (!empty($this->votes[$vote->user_handle ])) {
return PEAR::raiseError("You already voted!");
$vote->pkg_propop_id = $this->id;
$this->votes[$vote->user_handle ] = $vote;
$vote->store ($dbh, $this->id);
function addComment($comment, $table = 'package_proposal_changelog')
$commentData = array("pkg_prop_id" => $this->id,
"user_handle" => $auth_user->handle ,
$comment = new ppComment ( $commentData, $table );
$comment->store ($this->id);
$link = new ppLink($link);
$link->pkg_prop_id = $this->id;
function isOwner($handle)
if (strtolower($this->user_handle) != strtolower ($handle)) {
function mayEdit($handle = '')
$karma = new Damblan_Karma($dbh);
if ($this->isOwner($handle) || $karma->has ($handle, 'pear.pepr.admin')) {
if (!$this->isOwner($handle) && $karma->has ($handle, 'pear.pepr.admin')) {
* Determine if the current user can vote on the current proposal
* + Proposal must be in the "Called for Votes" phase.
* + User must be logged in.
* + User must be a full-featured PEAR developer.
* + Only one vote can be cast.
* + Proposers can't vote on their own package, though can for RFC's.
* @param object $dbh the current DB object
* @param string $userHandle the user's handle
function mayVote(&$dbh, $userHandle)
$karma = new Damblan_Karma($dbh);
$karma->has ($userHandle, 'pear.dev') &&
!ppVote ::hasVoted ($dbh, $userHandle, $this->id) &&
function getStatus($humanReadable = false)
return $GLOBALS['proposalStatiMap'][$this->status];
* Answers the question "Is this proposal $operator than $status?"
* @param string $operator the operator (<, <=, ==, >=, >, !=)
* @param string $status the status ('draft', 'vote', 'finished', etc)
function compareStatus($operator, $status)
return ($num[$this->status] < $num[$status]);
return ($num[$this->status] <= $num[$status]);
return ($num[$this->status] == $num[$status]);
return ($num[$this->status] >= $num[$status]);
return ($num[$this->status] > $num[$status]);
return ($num[$this->status] != $num[$status]);
PEAR ::raiseError ('Invalid $operator passed to compareStatus()');
case 'proposal': return true;
if (($this->proposal_date + PROPOSAL_STATUS_PROPOSAL_TIMELINE ) < time ()) {
return (int)($this->proposal_date + PROPOSAL_STATUS_PROPOSAL_TIMELINE );
if (($this->longened_date + PROPOSAL_STATUS_VOTE_TIMELINE ) > time ()) {
return (int)($this->longened_date + PROPOSAL_STATUS_VOTE_TIMELINE );
if (($this->vote_date + PROPOSAL_STATUS_VOTE_TIMELINE ) > time ()) {
return (int)($this->vote_date + PROPOSAL_STATUS_VOTE_TIMELINE );
return PEAR::raiseError("Proposal does not exist!");
$sql = "DELETE FROM package_proposals WHERE id = ".$this->id;
$res = $dbh->query ($sql);
$sql = "DELETE FROM package_proposal_votes WHERE pkg_prop_id = ".$this->id;
$res = $dbh->query ($sql);
$sql = "DELETE FROM package_proposal_links WHERE pkg_prop_id = ".$this->id;
$res = $dbh->query ($sql);
$sql = "DELETE FROM package_proposal_changelog WHERE pkg_prop_id = ".$this->id;
$res = $dbh->query ($sql);
$sql = "DELETE FROM package_proposal_comments WHERE pkg_prop_id = ".$this->id;
$res = $dbh->query ($sql);
function sendActionEmail($event, $userType, $user_handle = null,
global $dbh, $karma, $auth_user;
$karma = new Damblan_Karma($dbh);
require 'pepr/pepr-emails.php';
$email = $proposalEmailTexts[$event];
return PEAR::raiseError("Email template for $event not found");
if ($karma->has ($user_handle, "pear.pepr.admin") && ($this->user_handle != $user_handle)) {
$prefix = PROPOSAL_EMAIL_PREFIX . $prefix . " ";
include_once 'pear-database-user.php';
$actorinfo = user::info($user_handle);
$vote = @$this->votes[$user_handle];
$vote->value = ($vote->value > 0 ) ? "+". $vote->value : $vote->value;
if ($vote->is_conditional ) {
$vote_conditional = "\n\nThis vote is conditional. The condition is:\n\n".$vote->comment;
} elseif ($vote->comment ) {
$comment = "\n\nComment:\n\n" . $vote->comment;
$vote_url = "http://" . PEAR_CHANNELNAME . "/pepr/pepr-vote-show.php?id=".$this->id. "&handle=". $user_handle;
if ($event == 'change_status_finished') {
$proposalVotesSum = ppVote::getSum($dbh, $this->id);
$vote_result = 'Sum of Votes: ' . $proposalVotesSum['all'];
$vote_result .= ' (' . $proposalVotesSum['conditional']
if ($proposalVotesSum['all'] >= 5 ) {
$vote_result .= "\nResult: This proposal was accepted";
$vote_result .= "\nResult: This proposal was rejected";
$proposal_url = "http://" . PEAR_CHANNELNAME . "/pepr/pepr-proposal-show.php?id=".$this->id;
if ($event == 'proposal_comment' && $user_handle == $this->user_handle) {
$email['to'] = $email['to']['owner'];
if (!isset($user_handle)) {
$email['to'] = $email['to']['pearweb'];
} else if ($karma->has ($user_handle, "pear.pepr.admin")) {
$email['to'] = $email['to']['admin'];
$email['to'] = $email['to']['user'];
$email['subject'] = $prefix . $email['subject'];
"/\{email_pear_group\}/",
(isset ($ownerinfo['name'])) ? $ownerinfo['name'] : "",
(isset ($ownerinfo['email'])) ? "<{ $ownerinfo['email']}>" : '',
(isset($ownerinfo['handle'])) ? user_link($ownerinfo['handle'], true) : "",
(isset($actorinfo['name'])) ? $actorinfo['name'] : "",
(isset($actorinfo['email'])) ? $actorinfo['email'] : "",
(isset($actorinfo['handle'])) ? "http://" . PEAR_CHANNELNAME . "/user/".$actorinfo['handle'] : "",
format_date($end_voting_time),
(isset($vote)) ? $vote->value : 0 ,
(isset ($vote)) ? $vote_url : "",
PROPOSAL_MAIL_PEAR_GROUP ,
(isset ($comment)) ? wordwrap ($comment) : '',
(isset ($vote_result)) ? $vote_result : '',
(isset ($vote_conditional)) ? $vote_conditional : ""
$email = preg_replace ($replace, $replacements, $email);
$email['text'] .= PROPOSAL_EMAIL_POSTFIX;
if (is_object ($auth_user)) {
$from = '"' . $auth_user->name . '" <' . $auth_user->email . '>';
$from = PROPOSAL_MAIL_FROM ;
$to = explode(", ", $email['to']);
$email['to'] = array_shift($to);
$headers = "CC: ". implode(", ", $to) . "\n";
$headers .= "From: " . $from . "\n";
$headers .= "X-Mailer: " . "PEPr, PEAR Proposal System" . "\n";
$headers .= "X-PEAR-Category: " . $this->pkg_category . "\n";
$headers .= "X-PEAR-Package: " . $this->pkg_name . "\n";
$headers .= "X-PEPr-Status: " . $this->getStatus() . "\n";
if ($event == "change_status_proposal") {
$headers .= "Message-ID: <proposal-" . $this->id . "@" . PEAR_CHANNELNAME . ">\n";
$headers .= "In-Reply-To: <proposal-" . $this->id . "@" . PEAR_CHANNELNAME . ">\n";
$res = mail($email['to'], $email['subject'], $email['text'],
$headers, '-f ' . PEAR_BOUNCE_EMAIL);
return PEAR::raiseError('Could not send notification email.');
Documentation generated on Mon, 11 Mar 2019 15:44:05 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.
|