packaging/tag_packaging_delete -text
plugins/coclico/Makefile -text
plugins/coclico/Makefile.debian -text
+plugins/coclico/codendi-specific/common/dao/include/DataAccess.class.php -text
+plugins/coclico/codendi-specific/common/dao/include/DataAccess.class.php.orig -text
+plugins/coclico/codendi-specific/common/dao/include/DataAccessObject.class.php -text
+plugins/coclico/codendi-specific/common/dao/include/DataAccessObject.class.php.orig -text
+plugins/coclico/codendi-specific/common/dao/include/diffDataAccess -text
+plugins/coclico/codendi-specific/common/dao/include/diffDataAccessObject -text
+plugins/coclico/codendi-specific/env.inc.php -text
+plugins/coclico/codendi-specific/plugins_utils.php~ -text
+plugins/coclico/codendi-specific/www/include/plugins_utils.php -text
plugins/coclico/forumml/README.txt -text
plugins/coclico/forumml/TODO -text
plugins/coclico/forumml/bin/db-upgrade.pl -text
--- /dev/null
+<?php
+/**
+ * Copyright (c) Xerox Corporation, Codendi Team, 2001-2009. All rights reserved
+ *
+ * This file is a part of Codendi.
+ *
+ * Codendi 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.
+ *
+ * Codendi 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 Codendi. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+require_once('DataAccessResult.class.php');
+require_once('DataAccessException.class.php');
+
+$GLOBALS['DEBUG_DAO_QUERY_COUNT'] = 0;
+
+if(!defined('CODENDI_DB_NULL')) define('CODENDI_DB_NULL', 0);
+if(!defined('CODENDI_DB_NOT_NULL')) define('CODENDI_DB_NOT_NULL', 1);
+
+/**
+ * A simple class for querying MySQL
+ */
+class DataAccess {
+ /**
+ * @access protected
+ * $db stores a database resource
+ */
+ var $db;
+
+ /**
+ * store the database name used to instantiate the connection
+ */
+ public $db_name;
+
+ /**
+ * Constucts a new DataAccess object
+ * @param $host string hostname for dbserver
+ * @param $user string dbserver user
+ * @param $pass string dbserver user password
+ * @param $db string database name
+ */
+ function DataAccess($host,$user,$pass,$db,$opt=0) {
+ $this->store = array();
+ $this->db = $this->connect($host, $user, $pass, $opt);
+ if ($this->db) {
+ mysql_query("SET NAMES 'utf8'", $this->db);
+ if (!mysql_select_db($db,$this->db)) {
+ trigger_error(mysql_error(), E_USER_ERROR);
+ }
+ $this->db_name = $db;
+ } else {
+ throw new DataAccessException('Unable to access the database. Please contact your administrator.');
+ }
+ }
+
+ protected function connect($host, $user, $pass, $opt) {
+ return mysql_connect($host, $user, $pass, true, $opt);
+ }
+
+ var $store;
+
+ /**
+ * Fetches a query resources and stores it in a local member
+ * @param $sql string the database query to run
+ * @return object DataAccessResult
+ */
+ function &fetch($sql,$params=array()) {
+ $time = microtime(1);
+ $res = $this->mysql_query_params($sql,$params,$this->db);
+ if (isset($GLOBALS['DEBUG_MODE']) && $GLOBALS['DEBUG_MODE']) {
+ $GLOBALS['DEBUG_DAO_QUERY_COUNT']++;
+ $GLOBALS['QUERIES'][]=$sql;
+ if (!isset($GLOBALS['DBSTORE'][md5($sql)])) {
+ $GLOBALS['DBSTORE'][md5($sql)] = array('sql' => $sql, 'nb' => 0, 'trace' => array());
+ }
+ $GLOBALS['DBSTORE'][md5($sql)]['trace'][$GLOBALS['DBSTORE'][md5($sql)]['nb']++] = array(debug_backtrace(), $time, microtime(1));
+ }
+ $dar = new DataAccessResult($this, $res);
+ return $dar;
+ }
+
+ /**
+ * Return ID generated from the previous INSERT operation.
+ *
+ * @return int, or 0 if the previous query does not generate an AUTO_INCREMENT value, or FALSE if no MySQL connection was established
+ */
+ function lastInsertId() {
+ if($this->db) {
+ return mysql_insert_id($this->db);
+ } else {
+ return mysql_insert_id();
+ }
+ }
+
+ /**
+ * Return number of rows affected by the last INSERT, UPDATE or DELETE.
+ *
+ * @return int
+ */
+ function affectedRows() {
+ if($this->db) {
+ return mysql_affected_rows($this->db);
+ } else {
+ return mysql_affected_rows();
+ }
+ }
+
+ /**
+ * Returns any MySQL errors
+ * @return string a MySQL error
+ */
+ function isError() {
+ if ($this->db) {
+ return mysql_error($this->db);
+ } else {
+ return mysql_error();
+ }
+ }
+
+ /**
+ * Quote variable to make safe
+ * @see http://php.net/mysql-real-escape-string
+ * @static
+ */
+ function quoteSmart($value, $params = array()) {
+ // Quote if not integer
+ if ($this->db) {
+ $value = mysql_real_escape_string($value, $this->db);
+ } else {
+ $value = mysql_escape_string($value);
+ }
+ if (!is_numeric($value) || (isset($params['force_string']) && $params['force_string'])) {
+ $value = "'" . $value . "'";
+ }
+ return $value;
+ }
+
+ /**
+ * Safe implode function to use with SQL queries
+ * @static
+ */
+ function quoteSmartImplode($glue, $pieces, $params = array()) {
+ $lem = array_keys($pieces);
+ $str='';
+ $after_first=false;
+ foreach ($pieces as $piece) {
+ if ($after_first) {
+ $str.=$glue;
+ }
+ $str.=$this->quoteSmart($piece,$params);
+ $after_first=true;
+ }
+ return $str;
+ }
+
+
+ function escapeInt($v, $null = CODENDI_DB_NOT_NULL) {
+ $m = array();
+ if($null === CODENDI_DB_NULL && $v === '') {
+ return 'NULL';
+ }
+ if(preg_match('/^([+-]?[1-9][0-9]*|[+-]?0)$/', $v, $m)) {
+ return $m[1];
+ }
+ return '0';
+ }
+
+ # Parameterised query implementation for MySQL (similar PostgreSQL's PHP function pg_query_params)
+ # Example: mysql_query_params( "SELECT * FROM my_table WHERE col1=$1 AND col2=$2", array( 42, "It's ok" ) );
+ function mysql_query_params($sql,$params=array(),$database) {
+ if(!empty($params)) {
+ for ($i=1;$i<=count($params);$i++ ) {
+ $args[]="$".$i;
+ }
+ return mysql_query(str_replace($args,$params,$sql),$database);
+ } else {
+ return mysql_query($sql,$database);
+ }
+
+ }
+
+
+
+
+}
+?>
--- /dev/null
+<?php
+/**
+ * Copyright (c) Xerox Corporation, Codendi Team, 2001-2009. All rights reserved
+ *
+ * This file is a part of Codendi.
+ *
+ * Codendi 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.
+ *
+ * Codendi 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 Codendi. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+require_once('DataAccessResult.class.php');
+require_once('DataAccessException.class.php');
+
+$GLOBALS['DEBUG_DAO_QUERY_COUNT'] = 0;
+
+if(!defined('CODENDI_DB_NULL')) define('CODENDI_DB_NULL', 0);
+if(!defined('CODENDI_DB_NOT_NULL')) define('CODENDI_DB_NOT_NULL', 1);
+
+/**
+ * A simple class for querying MySQL
+ */
+class DataAccess {
+ /**
+ * @access protected
+ * $db stores a database resource
+ */
+ var $db;
+
+ /**
+ * store the database name used to instantiate the connection
+ */
+ public $db_name;
+
+ /**
+ * Constucts a new DataAccess object
+ * @param $host string hostname for dbserver
+ * @param $user string dbserver user
+ * @param $pass string dbserver user password
+ * @param $db string database name
+ */
+ function DataAccess($host,$user,$pass,$db,$opt=0) {
+ $this->store = array();
+ $this->db = $this->connect($host, $user, $pass, $opt);
+ if ($this->db) {
+ mysql_query("SET NAMES 'utf8'", $this->db);
+ if (!mysql_select_db($db,$this->db)) {
+ trigger_error(mysql_error(), E_USER_ERROR);
+ }
+ $this->db_name = $db;
+ } else {
+ throw new DataAccessException('Unable to access the database. Please contact your administrator.');
+ }
+ }
+
+ protected function connect($host, $user, $pass, $opt) {
+ return mysql_connect($host, $user, $pass, true, $opt);
+ }
+
+ var $store;
+
+ /**
+ * Fetches a query resources and stores it in a local member
+ * @param $sql string the database query to run
+ * @return object DataAccessResult
+ */
+ function &fetch($sql) {
+ $time = microtime(1);
+ $res = mysql_query($sql,$this->db);
+ if (isset($GLOBALS['DEBUG_MODE']) && $GLOBALS['DEBUG_MODE']) {
+ $GLOBALS['DEBUG_DAO_QUERY_COUNT']++;
+ $GLOBALS['QUERIES'][]=$sql;
+ if (!isset($GLOBALS['DBSTORE'][md5($sql)])) {
+ $GLOBALS['DBSTORE'][md5($sql)] = array('sql' => $sql, 'nb' => 0, 'trace' => array());
+ }
+ $GLOBALS['DBSTORE'][md5($sql)]['trace'][$GLOBALS['DBSTORE'][md5($sql)]['nb']++] = array(debug_backtrace(), $time, microtime(1));
+ }
+ $dar = new DataAccessResult($this, $res);
+ return $dar;
+ }
+
+ /**
+ * Return ID generated from the previous INSERT operation.
+ *
+ * @return int, or 0 if the previous query does not generate an AUTO_INCREMENT value, or FALSE if no MySQL connection was established
+ */
+ function lastInsertId() {
+ if($this->db) {
+ return mysql_insert_id($this->db);
+ } else {
+ return mysql_insert_id();
+ }
+ }
+
+ /**
+ * Return number of rows affected by the last INSERT, UPDATE or DELETE.
+ *
+ * @return int
+ */
+ function affectedRows() {
+ if($this->db) {
+ return mysql_affected_rows($this->db);
+ } else {
+ return mysql_affected_rows();
+ }
+ }
+
+ /**
+ * Returns any MySQL errors
+ * @return string a MySQL error
+ */
+ function isError() {
+ if ($this->db) {
+ return mysql_error($this->db);
+ } else {
+ return mysql_error();
+ }
+ }
+
+ /**
+ * Quote variable to make safe
+ * @see http://php.net/mysql-real-escape-string
+ * @static
+ */
+ function quoteSmart($value, $params = array()) {
+ // Quote if not integer
+ if ($this->db) {
+ $value = mysql_real_escape_string($value, $this->db);
+ } else {
+ $value = mysql_escape_string($value);
+ }
+ if (!is_numeric($value) || (isset($params['force_string']) && $params['force_string'])) {
+ $value = "'" . $value . "'";
+ }
+ return $value;
+ }
+
+ /**
+ * Safe implode function to use with SQL queries
+ * @static
+ */
+ function quoteSmartImplode($glue, $pieces, $params = array()) {
+ $lem = array_keys($pieces);
+ $str='';
+ $after_first=false;
+ foreach ($pieces as $piece) {
+ if ($after_first) {
+ $str.=$glue;
+ }
+ $str.=$this->quoteSmart($piece,$params);
+ $after_first=true;
+ }
+ return $str;
+ }
+
+
+ function escapeInt($v, $null = CODENDI_DB_NOT_NULL) {
+ $m = array();
+ if($null === CODENDI_DB_NULL && $v === '') {
+ return 'NULL';
+ }
+ if(preg_match('/^([+-]?[1-9][0-9]*|[+-]?0)$/', $v, $m)) {
+ return $m[1];
+ }
+ return '0';
+ }
+
+}
+?>
--- /dev/null
+<?php
+/**
+ * Base class for data access objects
+ */
+class DataAccessObject {
+ /**
+ * Private
+ * $da stores data access object
+ */
+ var $da;
+
+ //! A constructor
+ /**
+ * Constructs the Dao
+ * @param $da instance of the DataAccess class
+ */
+ function DataAccessObject( & $da ) {
+ $this->table_name = 'CLASSNAME_MUST_BE_DEFINE_FOR_EACH_CLASS';
+ //Dynamic table_name guessing does not work (at least in php4)
+ //because classname are lowercase only :(
+ /*
+ $s = get_class($this);
+ $this->table_name = '';
+ $len = strlen($s);
+ for($i = 1 ; $i <= $len ; ++$i) {
+ if ($i < $len && preg_match('`[A-Z]`', $s[$i - 1]) && preg_match('`[a-z]`', $s[$i])) {
+ $this->table_name .= '_';
+ }
+ $this->table_name .= strtolower($s[$i - 1]);
+ }
+ */
+ $this->da=$da;
+ }
+
+ //! An accessor
+ /**
+ * For SELECT queries
+ * @param $sql the query string
+ * @return mixed either false if error or object DataAccessResult
+ */
+ function &retrieve($sql,$params=array()) {
+ $result =& $this->da->fetch($sql,$params);
+ if ($error = $result->isError()) {
+ $trace = debug_backtrace();
+ $i = isset($trace[1]) ? 1 : 0;
+ trigger_error($error .' ==> '. $sql ." @@ ". $trace[$i]['file'] .' at line '. $trace[$i]['line']);
+ $result = false;
+ }
+ return $result;
+ }
+
+ //! An accessor
+ /**
+ * For INSERT, UPDATE and DELETE queries
+ * @param $sql the query string
+ * @return boolean true if success
+ */
+ function update($sql,$params=array()) {
+ $result = $this->da->fetch($sql,$params);
+ if ($error = $result->isError()) {
+ $trace = debug_backtrace();
+ $i = isset($trace[1]) ? 1 : 0;
+ trigger_error($error .' ==> '. $sql ." @@ ". $trace[$i]['file'] .' at line '. $trace[$i]['line']);
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ /**
+ * Prepare ranking of items.
+ *
+ * @see https://partners.xrce.xerox.com/plugins/docman/?group_id=120&action=show&id=95
+ *
+ * @param int $id The id of the item to rank. 0 if the item doesn't exist.
+ * @param int $parent_id The id of the element used to group items
+ * @param mixed $rank The rank asked for the items. Possible values are :
+ * '--' => do not change the rank
+ * 'beginning' => to put item before each others
+ * 'end' => to put item after each others
+ * 'up' => to put item before previous sibling
+ * 'down' => to put item after next sibling
+ * <int> => to put item at a specific position.
+ * Please note that for a new item ($id = 0) you must not use
+ * '--', 'up' or 'down' value
+ * @param string $primary_key the column name of the primary key. Default 'id'
+ * @param string $parent_key the column key used to groups items. Default 'parent_id'
+ * @param string $rank_key the column key used to rank items. Default 'rank'
+ * @return mixed false if there is no rank to update of the numerical
+ * value of the new rank of the item. If return 'null' it means
+ * that sth wrong happended.
+ */
+ function prepareRanking($id, $parent_id, $rank, $primary_key = 'id', $parent_key = 'parent_id', $rank_key = 'rank') {
+ $newRank = null;
+
+ // First, check if there is already some items
+ $sql = sprintf('SELECT NULL'.
+ ' FROM '. $this->table_name .
+ ' WHERE '. $parent_key .' = %d',
+ $parent_id);
+ $dar = $this->retrieve($sql);
+ if($dar && !$dar->isError() && $dar->rowCount() == 0) {
+ // No items: nice, just set the first one to 0.
+ $newRank = 0;
+ }
+ else {
+ switch((string)$rank) {
+ case '--':
+ $sql = sprintf('SELECT '. $rank_key .
+ ' FROM '. $this->table_name .
+ ' WHERE '. $primary_key .' = %d',
+ (int)$id);
+ $dar = $this->retrieve($sql);
+ if($dar && !$dar->isError() && $dar->rowCount() == 1) {
+ $row = $dar->current();
+ $newRank = $row[$rank_key];
+ }
+ break;
+ case 'end':
+ // Simple case: just pickup the most high rank in the table
+ // and add 1 to be laster than the first.
+ $sql = sprintf('SELECT MAX('. $rank_key .')+1 as '. $rank_key .
+ ' FROM '. $this->table_name .
+ ' WHERE '. $parent_key .' = %d',
+ $parent_id);
+ $dar = $this->retrieve($sql);
+ if($dar && !$dar->isError() && $dar->rowCount() == 1) {
+ $row = $dar->current();
+ $newRank = $row[$rank_key];
+ }
+ break;
+
+ case 'up':
+ case 'down':
+ // Those 2 cases are quite complex and are only mandatory if
+ // you want to 'Move up' or 'Move down' an item. If you can
+ // only select in a select box you can remove this part of
+ // the code.
+
+ // The general idea here is: we want to move up (or down) an
+ // item but we only know it's id and the sens (up/down) of the
+ // slide. Our goal is to exchange the rank value of the item
+ // behind (in case of up) with the current one.
+
+ // This is done in 2 steps:
+ // * first fetch the item_id and the rank of the item we want
+ // to stole the place.
+ // * then exchange the 2 rank values.
+
+ if ($rank == 'down') {
+ $op = '>';
+ $order = 'ASC';
+ } else {
+ $op = '<';
+ $order = 'DESC';
+ }
+
+ // This SQL query aims to get the item_id and the rank of the item
+ // Just behind us (for 'up' case).
+ // In your implementation, USING(parent_id) should refer to the field
+ // that group all the items in one list.
+ $sql = sprintf('SELECT i1.'. $primary_key .' as id, i1.'. $rank_key .' as '. $rank_key .
+ ' FROM '. $this->table_name .' i1'.
+ ' INNER JOIN '. $this->table_name .' i2 USING('. $parent_key .')'.
+ ' WHERE i2.'. $primary_key .' = %d'.
+ ' AND i1.'. $parent_key .' = %d'.
+ ' AND i1.'. $rank_key .' %s i2.'. $rank_key .
+ ' ORDER BY i1.'. $rank_key .' %s'.
+ ' LIMIT 1',
+ $id,
+ $parent_id,
+ $op,
+ $order);
+ $dar = $this->retrieve($sql);
+ if ($dar && !$dar->isError() && $dar->rowCount() == 1) {
+ $row = $dar->current();
+ // This query exchange the two values.
+ // Warning: the order is very important, please check that
+ // your final query work as expected.
+ $sql = sprintf('UPDATE '. $this->table_name .' i1, '. $this->table_name .' i2'.
+ ' SET i1.'. $rank_key .' = i2.'. $rank_key .', i2.'. $rank_key .' = %d'.
+ ' WHERE i1.'. $primary_key .' = %d '.
+ ' AND i2.'. $primary_key .' = %d',
+ $row[$rank_key],
+ $row['id'],
+ $id);
+ $this->update($sql);
+ $newRank = false;
+ }
+ break;
+
+ case 'beginning':
+ // This first part is quite simple: just pickup the lower rank
+ // in the table
+ $sql = sprintf('SELECT MIN('. $rank_key .') as '. $rank_key .
+ ' FROM '. $this->table_name .
+ ' WHERE '. $parent_key .' = %d',
+ $parent_id);
+ $dar = $this->retrieve($sql);
+ if($dar && !$dar->isError()) {
+ $row = $dar->current();
+ $rank = $row[$rank_key];
+ }
+ // Very important: no break here, because we have to update all
+ // ranks upper:
+ // no break;
+
+ default:
+ // Here $rank is a numerical value that represent the rank after
+ // one item (user selected 'After XXX' in select box).
+ // The idea is to move up all the ranks upper to this value and to
+ // return the current value as the new rank.
+ $sql = sprintf('UPDATE '. $this->table_name .
+ ' SET '. $rank_key .' = '. $rank_key .' + 1'.
+ ' WHERE '. $parent_key .' = %d'.
+ ' AND '. $rank_key .' >= %d',
+ $parent_id, $rank);
+ $updated = $this->update($sql);
+ if($updated) {
+ $newRank = $rank;
+ }
+ }
+ }
+ return $newRank;
+ }
+
+ /**
+ * Return the result of 'FOUND_ROWS()' SQL method for the last query.
+ */
+ function foundRows() {
+ $sql = "SELECT FOUND_ROWS() as nb";
+ $dar = $this->retrieve($sql);
+ if($dar && !$dar->isError()) {
+ $row = $dar->getRow();
+ return $row['nb'];
+ } else {
+ return false;
+ }
+ }
+}
+?>
--- /dev/null
+<?php
+/**
+ * Base class for data access objects
+ */
+class DataAccessObject {
+ /**
+ * Private
+ * $da stores data access object
+ */
+ var $da;
+
+ //! A constructor
+ /**
+ * Constructs the Dao
+ * @param $da instance of the DataAccess class
+ */
+ function DataAccessObject( & $da ) {
+ $this->table_name = 'CLASSNAME_MUST_BE_DEFINE_FOR_EACH_CLASS';
+ //Dynamic table_name guessing does not work (at least in php4)
+ //because classname are lowercase only :(
+ /*
+ $s = get_class($this);
+ $this->table_name = '';
+ $len = strlen($s);
+ for($i = 1 ; $i <= $len ; ++$i) {
+ if ($i < $len && preg_match('`[A-Z]`', $s[$i - 1]) && preg_match('`[a-z]`', $s[$i])) {
+ $this->table_name .= '_';
+ }
+ $this->table_name .= strtolower($s[$i - 1]);
+ }
+ */
+ $this->da=$da;
+ }
+
+ //! An accessor
+ /**
+ * For SELECT queries
+ * @param $sql the query string
+ * @return mixed either false if error or object DataAccessResult
+ */
+ function &retrieve($sql) {
+ $result =& $this->da->fetch($sql);
+ if ($error = $result->isError()) {
+ $trace = debug_backtrace();
+ $i = isset($trace[1]) ? 1 : 0;
+ trigger_error($error .' ==> '. $sql ." @@ ". $trace[$i]['file'] .' at line '. $trace[$i]['line']);
+ $result = false;
+ }
+ return $result;
+ }
+
+ //! An accessor
+ /**
+ * For INSERT, UPDATE and DELETE queries
+ * @param $sql the query string
+ * @return boolean true if success
+ */
+ function update($sql) {
+ $result = $this->da->fetch($sql);
+ if ($error = $result->isError()) {
+ $trace = debug_backtrace();
+ $i = isset($trace[1]) ? 1 : 0;
+ trigger_error($error .' ==> '. $sql ." @@ ". $trace[$i]['file'] .' at line '. $trace[$i]['line']);
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ /**
+ * Prepare ranking of items.
+ *
+ * @see https://partners.xrce.xerox.com/plugins/docman/?group_id=120&action=show&id=95
+ *
+ * @param int $id The id of the item to rank. 0 if the item doesn't exist.
+ * @param int $parent_id The id of the element used to group items
+ * @param mixed $rank The rank asked for the items. Possible values are :
+ * '--' => do not change the rank
+ * 'beginning' => to put item before each others
+ * 'end' => to put item after each others
+ * 'up' => to put item before previous sibling
+ * 'down' => to put item after next sibling
+ * <int> => to put item at a specific position.
+ * Please note that for a new item ($id = 0) you must not use
+ * '--', 'up' or 'down' value
+ * @param string $primary_key the column name of the primary key. Default 'id'
+ * @param string $parent_key the column key used to groups items. Default 'parent_id'
+ * @param string $rank_key the column key used to rank items. Default 'rank'
+ * @return mixed false if there is no rank to update of the numerical
+ * value of the new rank of the item. If return 'null' it means
+ * that sth wrong happended.
+ */
+ function prepareRanking($id, $parent_id, $rank, $primary_key = 'id', $parent_key = 'parent_id', $rank_key = 'rank') {
+ $newRank = null;
+
+ // First, check if there is already some items
+ $sql = sprintf('SELECT NULL'.
+ ' FROM '. $this->table_name .
+ ' WHERE '. $parent_key .' = %d',
+ $parent_id);
+ $dar = $this->retrieve($sql);
+ if($dar && !$dar->isError() && $dar->rowCount() == 0) {
+ // No items: nice, just set the first one to 0.
+ $newRank = 0;
+ }
+ else {
+ switch((string)$rank) {
+ case '--':
+ $sql = sprintf('SELECT '. $rank_key .
+ ' FROM '. $this->table_name .
+ ' WHERE '. $primary_key .' = %d',
+ (int)$id);
+ $dar = $this->retrieve($sql);
+ if($dar && !$dar->isError() && $dar->rowCount() == 1) {
+ $row = $dar->current();
+ $newRank = $row[$rank_key];
+ }
+ break;
+ case 'end':
+ // Simple case: just pickup the most high rank in the table
+ // and add 1 to be laster than the first.
+ $sql = sprintf('SELECT MAX('. $rank_key .')+1 as '. $rank_key .
+ ' FROM '. $this->table_name .
+ ' WHERE '. $parent_key .' = %d',
+ $parent_id);
+ $dar = $this->retrieve($sql);
+ if($dar && !$dar->isError() && $dar->rowCount() == 1) {
+ $row = $dar->current();
+ $newRank = $row[$rank_key];
+ }
+ break;
+
+ case 'up':
+ case 'down':
+ // Those 2 cases are quite complex and are only mandatory if
+ // you want to 'Move up' or 'Move down' an item. If you can
+ // only select in a select box you can remove this part of
+ // the code.
+
+ // The general idea here is: we want to move up (or down) an
+ // item but we only know it's id and the sens (up/down) of the
+ // slide. Our goal is to exchange the rank value of the item
+ // behind (in case of up) with the current one.
+
+ // This is done in 2 steps:
+ // * first fetch the item_id and the rank of the item we want
+ // to stole the place.
+ // * then exchange the 2 rank values.
+
+ if ($rank == 'down') {
+ $op = '>';
+ $order = 'ASC';
+ } else {
+ $op = '<';
+ $order = 'DESC';
+ }
+
+ // This SQL query aims to get the item_id and the rank of the item
+ // Just behind us (for 'up' case).
+ // In your implementation, USING(parent_id) should refer to the field
+ // that group all the items in one list.
+ $sql = sprintf('SELECT i1.'. $primary_key .' as id, i1.'. $rank_key .' as '. $rank_key .
+ ' FROM '. $this->table_name .' i1'.
+ ' INNER JOIN '. $this->table_name .' i2 USING('. $parent_key .')'.
+ ' WHERE i2.'. $primary_key .' = %d'.
+ ' AND i1.'. $parent_key .' = %d'.
+ ' AND i1.'. $rank_key .' %s i2.'. $rank_key .
+ ' ORDER BY i1.'. $rank_key .' %s'.
+ ' LIMIT 1',
+ $id,
+ $parent_id,
+ $op,
+ $order);
+ $dar = $this->retrieve($sql);
+ if ($dar && !$dar->isError() && $dar->rowCount() == 1) {
+ $row = $dar->current();
+ // This query exchange the two values.
+ // Warning: the order is very important, please check that
+ // your final query work as expected.
+ $sql = sprintf('UPDATE '. $this->table_name .' i1, '. $this->table_name .' i2'.
+ ' SET i1.'. $rank_key .' = i2.'. $rank_key .', i2.'. $rank_key .' = %d'.
+ ' WHERE i1.'. $primary_key .' = %d '.
+ ' AND i2.'. $primary_key .' = %d',
+ $row[$rank_key],
+ $row['id'],
+ $id);
+ $this->update($sql);
+ $newRank = false;
+ }
+ break;
+
+ case 'beginning':
+ // This first part is quite simple: just pickup the lower rank
+ // in the table
+ $sql = sprintf('SELECT MIN('. $rank_key .') as '. $rank_key .
+ ' FROM '. $this->table_name .
+ ' WHERE '. $parent_key .' = %d',
+ $parent_id);
+ $dar = $this->retrieve($sql);
+ if($dar && !$dar->isError()) {
+ $row = $dar->current();
+ $rank = $row[$rank_key];
+ }
+ // Very important: no break here, because we have to update all
+ // ranks upper:
+ // no break;
+
+ default:
+ // Here $rank is a numerical value that represent the rank after
+ // one item (user selected 'After XXX' in select box).
+ // The idea is to move up all the ranks upper to this value and to
+ // return the current value as the new rank.
+ $sql = sprintf('UPDATE '. $this->table_name .
+ ' SET '. $rank_key .' = '. $rank_key .' + 1'.
+ ' WHERE '. $parent_key .' = %d'.
+ ' AND '. $rank_key .' >= %d',
+ $parent_id, $rank);
+ $updated = $this->update($sql);
+ if($updated) {
+ $newRank = $rank;
+ }
+ }
+ }
+ return $newRank;
+ }
+
+ /**
+ * Return the result of 'FOUND_ROWS()' SQL method for the last query.
+ */
+ function foundRows() {
+ $sql = "SELECT FOUND_ROWS() as nb";
+ $dar = $this->retrieve($sql);
+ if($dar && !$dar->isError()) {
+ $row = $dar->getRow();
+ return $row['nb'];
+ } else {
+ return false;
+ }
+ }
+}
+?>
--- /dev/null
+76c76
+< function &fetch($sql,$params=array()) {
+---
+> function &fetch($sql) {
+78c78
+< $res = $this->mysql_query_params($sql,$params,$this->db);
+---
+> $res = mysql_query($sql,$this->db);
+177,193d176
+< # Parameterised query implementation for MySQL (similar PostgreSQL's PHP function pg_query_params)
+< # Example: mysql_query_params( "SELECT * FROM my_table WHERE col1=$1 AND col2=$2", array( 42, "It's ok" ) );
+< function mysql_query_params($sql,$params=array(),$database) {
+< if(!empty($params)) {
+< for ($i=1;$i<=count($params);$i++ ) {
+< $args[]="$".$i;
+< }
+< return mysql_query(str_replace($args,$params,$sql),$database);
+< } else {
+< return mysql_query($sql,$database);
+< }
+<
+< }
+<
+<
+<
+<
--- /dev/null
+41,42c41,42
+< function &retrieve($sql,$params=array()) {
+< $result =& $this->da->fetch($sql,$params);
+---
+> function &retrieve($sql) {
+> $result =& $this->da->fetch($sql);
+58,59c58,59
+< function update($sql,$params=array()) {
+< $result = $this->da->fetch($sql,$params);
+---
+> function update($sql) {
+> $result = $this->da->fetch($sql);
--- /dev/null
+<?php
+
+require_once('pre.php');
+
+/**
+ * userIsAdmin - use this function to know if the user can administrate mailing lists
+ *
+ * This is a static method. Currently the user must be a project or a sitewide admin to administrate the mailing lists
+ *
+ * @return boolean true if the user can administrate mailing lists
+ */
+function userIsProjectAdmin($group_id) {
+ $current_user=UserManager::instance()->getCurrentUser();
+ if (!$current_user->isMember($group_id,'A')) {
+ return false;
+ } else {
+ return true;
+ }
+}
+
+function & getGroup($group_id)
+{
+
+ $pm = ProjectManager::instance();
+ $Group = $pm->getProject($group_id);
+ return $Group;
+}
+
+function isLogged(){
+ return user_isloggedin();
+}
+
+function ismember($group_id){
+ $current_user=UserManager::instance()->getCurrentUser();
+ return $current_user->isMember($group_id);
+}
+
+function getCurrentID()
+{
+ $current_user=UserManager::instance()->getCurrentUser();
+ return $current_user->getID();
+}
+function getEmail($id=false)
+{
+ if(!$id) {
+ $id =getCurrentID();
+ }
+ $user=UserManager::instance()->getUserByID($id);
+ return $user->getEmail();
+}
+function getPasswd()
+{
+ $current_user=UserManager::instance()->getCurrentUser();
+ return $current_user->getUserPw();
+}
+function getRealName()
+{
+ $current_user=UserManager::instance()->getCurrentUser();
+ return $current_user->getRealName();
+}
+function getRequest($param)
+{
+ $request =& HTTPRequest::instance();
+ if ($request->exist($param)) {
+ $result=$request->get($param);
+ }
+ else {
+ $result = false;
+ }
+ return $result;
+
+}
+function htmlRedirect($url) {
+ $GLOBALS['HTML']->redirect($url);
+}
+function htmlIframe($url,$poub) {
+ $GLOBALS['HTML']->iframe($url,array('class' => 'iframe_service'));
+}
+
+
+function helpButton($params)
+{
+ echo ' | ';
+ echo help_button($params,false,_('Help'));
+}
+function getIcon() {
+ echo '<IMG SRC="'.util_get_image_theme("ic/cfolder15.png").'" HEIGHT="13" WIDTH="15" BORDER="0">';
+}
+?>
+
+
--- /dev/null
+<?php
+
+require_once('pre.php');
+$GLOBALS['mailman_lib_dir'] = '/var/lib/mailman';
+$GLOBALS['mailman_bin_dir'] = '/usr/lib/mailman/bin';
+$GLOBALS['forumml_arch'] = '/var/lib/mailman/archives';
+$GLOBALS['forumml_tmp'] = '/var/run/forumml';
+$GLOBALS['forumml_dir'] = '/var/lib/codendi/forumml';
+
+function isLogged(){
+ return user_isloggedin();
+}
+
+
+function htmlRedirect($url) {
+ $GLOBALS['HTML']->redirect($url);
+}
+function htmlIframe($url,$poub) {
+ $GLOBALS['HTML']->iframe($url,array('class' => 'iframe_service'));
+}
+
+
+function helpButton($params)
+{
+ echo ' | ';
+ echo help_button($params,false,_('Help'));
+}
+function getIcon() {
+ echo '<IMG SRC="'.util_get_image_theme("ic/cfolder15.png").'" HEIGHT="13" WIDTH="15" BORDER="0">';
+}
+function util_make_url ($loc) {
+ return session_make_url($loc);
+}
+function plugin_hook($hook,$params) {
+ $em =& EventManager::instance();
+ $em->processEvent($hook,$params);
+}
+function getImage($url) {
+return util_get_image_theme($url);
+}
+?>
+