<?php
// QuickTicket 2.5 build:20101222
class cSection extends aQTcontainer implements IOptions,IStats
{
// aQTcontainer's extra properties
public $domname; // Domain name
public $name; // Section name (translation of the title)
public $notify; // Notify: 0=disable, 1=enabled
public $modid; // Moderator id
public $modname; // Moderaotr name
public $numfield; // Format of the ref number: 'N' means no ref number
public $titlefield; // Topic title: 0=None, 1=Optional, 2=Mandatory
public $wisheddate=0;// Topic wisheddate: 0=None, 1=Optional, 2=Mandatory
public $wisheddflt=0;// Topic wisheddate [2] default: 0=None, 1=Today, 2=Day+1, 3=Day+2
public $notifycc; // Topic alternate notify: 0=None, 1=Optional, 2=Mandatory
public $prefix; // Prefix icon from the serie 'a'
public $options=''; // Several stats (no used)
public $stats=''; // Several stats (no used)
// stats
// public $items=0; // Total topics (including news) //already defined in aQTcontainer
public $itemsZ=0; // Total topics closed (including news)
public $replies=0; // Total replies (type R and F), not D
public $repliesZ=0; // Total replies in topics closed (type R,F or D)
public $tags=0; // >0 means tags exists (may be several time the same!)
// options
public $d_order=''; // Teams member default sort order (not used)
public $d_last='none'; // Last column in the topic list: 'none' means no last column
public $d_logo=''; // Section picture named s_x.gif/.jpeg/.jpg/.png (where x is the section id)
// computed values
public $lastpostid;
public $lastposttopic;
public $lastpostdate;
public $lastpostuser;
public $lastpostname;
// --------
function __construct($aSection=null,$bLast=false)
{
// Constructor accepts an id or an array as parameter
if ( isset($aSection) )
{
if ( is_int($aSection) )
{
if ( $aSection<0 ) die('No section '.$aSection);
global $oDB;
$oDB->Query('SELECT * FROM '.TABSECTION.' WHERE id='.$aSection);
$row = $oDB->Getrow();
if ( $row===False ) die('No section '.$aSection);
$this->MakeFromArray($row);
}
elseif ( is_array($aSection) )
{
$this->MakeFromArray($aSection);
}
else
{
die('Invalid constructor parameter #1 for the class cSection');
}
}
// Read options/stats
$this->ReadOptions(); // initialise options properties
$this->ReadStats(); // initialise stats properties
// Find last post. NOTE $bLast can be an id (int) to bypass the search step and get directly the lastpost info
if ( $bLast ) $this->GetSectionLastPost($bLast);
// Default sort order and last column
if ( empty($this->d_order) ) $this->d_order='lastpostdate';
if ( $this->d_last=='wisheddate' && $this->wisheddate==0 ) $this->d_last='none';
if ( $this->d_last=='notifiedname' && $this->notifycc==0 ) $this->d_last='none';
if ( $this->d_last=='no' || empty($this->d_last) ) $this->d_last='none';
}
// --------
private function MakeFromArray($aSection)
{
foreach($aSection as $strKey=>$oValue) {
switch ($strKey) {
case 'domainid': $this->parentid = intval($oValue); break;
case 'id': $this->id = intval($oValue); break;
case 'title': $this->title = $oValue; break;
case 'type': $this->type = intval($oValue); break;
case 'status': $this->status = intval($oValue); break;
case 'notify': $this->notify = intval($oValue); break;
case 'moderator': $this->modid = intval($oValue); break;
case 'moderatorname':$this->modname = $oValue; break;
case 'stats': $this->stats = $oValue; break;
case 'options': $this->options = $oValue; break;
case 'numfield': $this->numfield = $oValue; break;
case 'titlefield': $this->titlefield= intval($oValue); break;
case 'wisheddate':
$this->wisheddate = intval($oValue);
if ( $this->wisheddate>2 ) { $this->wisheddflt=$this->wisheddate-2; $this->wisheddate=2; }
break;
case 'alternate': $this->notifycc = intval($oValue); break;
case 'prefix': $this->prefix = $oValue; break;
}}
$this->name = ObjTrans('sec','s'.$this->id,$this->title);
$this->descr = ObjTrans('secdesc','s'.$this->id,false);
$this->domname= ObjTrans('domain','d'.$this->parentid,'(domain '.$this->parentid.')');
}
// --------
public function GetSectionLastPost($intLast)
{
// Initialize
$this->lastpostid = null;
$this->lastposttopic = null;
$this->lastpostdate = null;
$this->lastpostuser = null;
$this->lastpostname = null;
// Check
if ( $this->id<0 ) return null;
if ( $this->items==0 ) return null;
// Query - attention: Subqueries requires mysql 4.1. We use two queries
// Search query can be bypassed by providing a $intLast
global $oDB;
// Search (maxid)
if ( is_integer($intLast) )
{
$intId = $intLast;
}
else
{
$oDB->Query( 'SELECT MAX(id) as maxid FROM '.TABPOST.' WHERE forum='.$this->id );
$row = $oDB->Getrow();
$intId = intval($row['maxid']);
}
// Get lastpost informations
if ( $intId>0 )
{
$oDB->Query( 'SELECT id,topic,issuedate,userid,username FROM '.TABPOST.' WHERE id='.$intId );
if ( $row=$oDB->Getrow() )
{
$this->lastpostid = intval($row['id']);
$this->lastposttopic = intval($row['topic']);
$this->lastpostdate = $row['issuedate'];
$this->lastpostuser = intval($row['userid']);
$this->lastpostname = $row['username'];
}
}
}
// --------
public function GetLogo()
{
if ( !empty($this->d_logo) )
{
if ( file_exists('upload/section/'.$this->d_logo) ) return 'upload/section/'.$this->d_logo;
}
return $_SESSION[QT]['skin_dir'].'/ico_section_'.$this->type.'_'.$this->status.'.gif';
}
// --------
public static function GetTagsUsed($id=-1,$intMax=50)
{
// -1 to compute on all sections // maximum returned is $intMax distinct tags
// Check
if ( !is_int($id) ) die('cSection->GetTagsUsed: Argument #1 must be integer');
// Process
$arrTags = array();
global $oDB;
$oDB->Query( 'SELECT DISTINCT tags FROM '.TABTOPIC.($id==-1 ? '' : ' WHERE forum='.$id) );
$i=0;
while($row=$oDB->Getrow()) {
if ( !empty($row['tags']) ) {
$arr = explode(';',$row['tags']);
foreach($arr as $str)
{
if ( !empty($str) ) {
if ( !in_array($str,$arrTags) ) {
$arrTags[$str] = $str;
$i++;
if ( $i>$intMax ) break;
}}
}
if ( $i>$intMax ) break;
}}
if ( count($arrTags)>2 ) asort($arrTags);
return $arrTags;
}
// --------
public function MoveTopics($intD=0,$intRenum=1,$intTopic=-1,$bClosedOnly=false,$strYear='')
{
if ( !is_int($intD) ) die('cSection->MoveTopics: Argument #2 must be integer');
if ( $this->id<0 ) die('cSection->MoveTopics: Wrong argument #1 (id<0)');
if ( $intD<0 ) die('cSection->MoveTopics: Wrong argument #2 (d<1)');
if ( $this->id==$intD ) die('cSection->MoveTopics: Wrong argument, source=destination');
if ( !is_string($strYear) ) $strYear = intval($strYear); // $strYear can be a integer or "old"
if ( strlen($strYear)>4 ) die('cSection->MoveTopics: Argument #2 must be a string');
global $oDB;
$strWhere = (empty($strYear) ? '' : ' AND '.SqlDateCondition($strYear));
$strTopic = '';
$strPost = '';
$strField = ''; if ( $intRenum==0 ) $strField = ', numid = 0';
// Move only one topic
if ( $intTopic>=0 )
{
$strTopic=" AND id=$intTopic";
$strPost=" AND topic=$intTopic";
if ( $intRenum==2 )
{
$nextnumid = $oDB->Nextid(TABTOPIC,'numid','WHERE forum='.$intD);
$strField = ', numid='.intval($nextnumid);
}
$bClosedOnly=false;
}
else
{
if ( $intRenum==2 )
{
$nextnumid = $oDB->Nextid(TABTOPIC,'numid','WHERE forum='.$intD);
$oDB->Query('SELECT MIN(numid) as minnumid FROM '.TABTOPIC.' WHERE forum='.$this->id);
$row = $oDB->Getrow();
$minnumid = $row['minnumid'];
$strField = ", numid = $nextnumid + (numid - $minnumid)";
}
}
// Check if prefix system are the same. If not, remove the prefix.
$strSetPrefix = '';
if ( !empty($this->prefix) )
{
$oDB->Query('SELECT prefix FROM '.TABSECTION.' WHERE id='.$intD);
$row = $oDB->Getrow();
if ( $row['prefix']!=$this->prefix ) $strSetPrefix = ',icon="00"';
}
// Update topics and posts
if ( $bClosedOnly )
{
$arr = array();
$oDB->Query('SELECT id FROM '.TABTOPIC.' WHERE forum='.$this->id.' AND status="Z" AND type="T"'.$strWhere);
while($row=$oDB->Getrow()) $arr[] = intval($row['id']);
foreach($arr as $intVal)
{
$oDB->Query( 'UPDATE '.TABTOPIC.' SET forum='.$intD.$strField.',modifdate="'.date('Ymd His').'" WHERE id='.$intVal );
$oDB->Query( 'UPDATE '.TABPOST.' SET forum='.$intD.$strSetPrefix.' WHERE topic='.$intVal );
}
}
else
{
$oDB->Query( 'UPDATE '.TABTOPIC.' SET forum='.$intD.$strField.',modifdate="'.date('Ymd His').'" WHERE forum='.$this->id.$strTopic.$strWhere );
$oDB->Query( 'UPDATE '.TABPOST.' SET forum='.$intD.$strSetPrefix.' WHERE forum='.$this->id.$strPost.str_replace('firstpostdate','issuedate',$strWhere) );
}
// Update stats of this section and stats of destination section
$this->UpdateStats(array('tags'=>$this->tags),true,true);
$voidSEC = new cSection(); $voidSEC->id=$intD; $voidSEC->UpdateStats(array(),true,true);
}
// --------
public function DeleteTopics($bClosedOnly=false,$strYear='',$bUpdateStats=true)
{
if ( $this->id<0 ) die('cSection->DeleteTopics: Wrong argument #1 (id<0)');
if ( !is_string($strYear) ) $strYear = intval($strYear); // $strYear can be a integer or the string 'old'
if ( strlen($strYear)>4 ) die('cSection->DeleteTopics: Argument #2 must be a string');
// Process - delete topics and posts
global $oDB;
$strWhere = (empty($strYear) ? '' : ' AND '.SqlDateCondition($strYear));
if ( $bClosedOnly )
{
$arr = array();
$oDB->Query( 'SELECT id FROM '.TABTOPIC.' WHERE forum='.$this->id.' AND status="Z" AND type="T"'.$strWhere );
while($row=$oDB->Getrow())
{
$arr[] = $row['id'];
}
foreach($arr as $intKey=>$id)
{
$oDB->Query( 'DELETE FROM '.TABPOST.' WHERE topic='.$id );
$oDB->Query( 'DELETE FROM '.TABTOPIC.' WHERE id='.$id );
}
}
else
{
$oDB->Query( 'DELETE FROM '.TABPOST.' WHERE forum='.$this->id.str_replace('firstpostdate','issuedate',$strWhere) );
$oDB->Query( 'DELETE FROM '.TABTOPIC.' WHERE forum='.$this->id.$strWhere );
}
if ( $bUpdateStats ) $this->UpdateStats(array('tags'=>$this->tags));
}
// --------
public function UpdateLastPostDate()
{
global $oDB;
if ( in_array($oDB->type,array('sqlite','mssql','pg','access','db2')) )
{
$oDB->Query( 'UPDATE '.TABTOPIC.' SET lastpostdate=(SELECT MAX(issuedate) FROM '.TABPOST.' p, '.TABTOPIC.' t WHERE t.id=p.topic) WHERE forum='.$this->id );
}
else
{
$oDB->Query( 'UPDATE '.TABTOPIC.' t SET t.lastpostdate=(SELECT MAX(p.issuedate) FROM '.TABPOST.' p WHERE t.id=p.topic) WHERE t.forum='.$this->id );
}
}
public function UpdateReplies()
{
global $oDB;
if ( in_array($oDB->type,array('sqlite','mssql','pg','access','db2')) )
{
$oDB->Query( 'UPDATE '.TABTOPIC.' SET replies=(SELECT COUNT(*) FROM '.TABPOST.' p, '.TABTOPIC.' t WHERE t.id=p.topic) WHERE forum='.$this->id );
}
else
{
$oDB->Query( 'UPDATE '.TABTOPIC.' t SET t.replies=(SELECT COUNT(p.id) FROM '.TABPOST.' p WHERE t.id=p.topic AND p.type<>"P") WHERE t.forum='.$this->id );
}
}
// --------
public function UpdateStats($arrValues=array(),$bLastPostDate=false,$bReplies=false)
{
if ( $this->id<0 ) die('UpdateSectionStats: Wrong id');
// Process (provided values are not recomputed)
if ( !isset($arrValues['topics']) ) $arrValues['topics'] = cSection::CountItems($this->id,'topics');
if ( !isset($arrValues['replies']) ) $arrValues['replies'] = cSection::CountItems($this->id,'replies');
if ( !isset($arrValues['tags']) ) $arrValues['tags'] = cSection::CountItems($this->id,'tags');
if ( !isset($arrValues['topicsZ']) ) $arrValues['topicsZ'] = cSection::CountItems($this->id,'topicsZ');
if ( !isset($arrValues['repliesZ']) ) $arrValues['repliesZ']= cSection::CountItems($this->id,'repliesZ');
$this->stats = QTimplode($arrValues);
$this->WriteStats();
if ( $bLastPostDate ) $this->UpdateLastPostDate(); // used after import
if ( $bReplies ) $this->UpdateReplies(); // used after import
}
// --------
// aQTcontainer implementations
// --------
public static function Create($title,$parentid)
{
QTargs( 'cSection->Create',array($title,$parentid),array('str','int') );
if ( empty($title) ) die('cSection->Create: Argument #1 must be a string');
global $oDB;
$id = $oDB->Nextid(TABSECTION);
$oDB->Query( 'INSERT INTO '.TABSECTION.' (domainid,id,titleorder,moderator,type,status,notify,titlefield,wisheddate,alternate,title,stats,options,moderatorname,numfield,prefix) VALUES ('.$parentid.','.$id.',0,1,"0","0","0","0","0","0","'.addslashes($title).'","","coord=0;order=0;last=0;logo=0","Admin","%03s","a")' );
// Impact on globals
if ( isset($_SESSION[QT]['sys_sections']) ) Unset($_SESSION[QT]['sys_sections']);
return $id;
}
public static function Drop($id)
{
if ( $id<1 ) die('cSection->Drop: Cannot delete section 0');
global $oDB;
$oDB->Query('DELETE FROM '.TABSECTION.' WHERE id='.$id);
cVIP::LangDel(array('sec','secdesc'),'s'.$id);
// Impact on globals
if ( isset($_SESSION[QT]['sys_sections']) ) Unset($_SESSION[QT]['sys_sections']);
}
public static function MoveItems($id,$destination)
{
// See MoveTopics
}
public static function CountItems($id,$status,$intD=10,$strYear='')
{
if ( !is_int($intD) ) die('cSection->Count: Argument #2 must be an int');
if ( $id<0 ) die('cSection->Count: Wrong argument (id<0)');
if ( $intD<1 ) die('cSection->Count: Wrong argument #2 (d<1)');
if ( !is_string($strYear) ) $strYear = intval($strYear); // $strYear can be a integer or "old"
if ( strlen($strYear)>4 ) die('cSection->Count: Argument #3 must be a string');
global $oDB;
$strWhere = (empty($strYear) ? '' : ' AND '.SqlDateCondition($strYear));
// Process
switch($status)
{
case 'topics': $oDB->Query( 'SELECT count(*) as countid FROM '.TABTOPIC.' WHERE forum='.$id.$strWhere ); break;
case 'topicsZ': $oDB->Query( 'SELECT count(*) as countid FROM '.TABTOPIC.' WHERE status="Z" AND forum='.$id.$strWhere ); break;
case 'news': $oDB->Query( 'SELECT count(*) as countid FROM '.TABTOPIC.' WHERE forum='.$id.' AND type="A"'.$strWhere ); break;
case 'inspections': $oDB->Query( 'SELECT count(*) as countid FROM '.TABTOPIC.' WHERE forum='.$id.' AND type="I"'.$strWhere ); break;
case 'replies': $oDB->Query( 'SELECT count(*) as countid FROM '.TABPOST.' WHERE forum='.$id.' AND (type="R" OR type="F")'.str_replace('firstpostdate','issuedate',$strWhere) ); break;
case 'repliesZ': $oDB->Query( 'SELECT count(*) as countid FROM '.TABPOST.' p INNER JOIN '.TABTOPIC.' t ON p.topic=t.id WHERE p.forum='.$id.' AND p.type<>"P" AND t.status="Z"'.$strWhere ); break;
case 'unreplied': $oDB->Query( 'SELECT count(*) as countid FROM '.TABTOPIC.' WHERE forum='.$id.' AND replies=0 AND firstpostdate<"'.DateAdd(date('Ymd His'),-$intD,'day').'"'.$strWhere ); break;
case 'unrepliedT': $oDB->Query( 'SELECT count(id) as countid FROM '.TABTOPIC.' WHERE forum='.$id.' AND type="T" AND replies=0 AND firstpostdate<"'.DateAdd(date('Ymd His'),-$intD,'day').'"'.$strWhere ); break;
case 'unrepliedA': $oDB->Query( 'SELECT count(id) as countid FROM '.TABTOPIC.' WHERE forum='.$id.' AND type="A" AND replies=0 AND firstpostdate<"'.DateAdd(date('Ymd His'),-$intD,'day').'"'.$strWhere ); break;
case 'unrepliedI': $oDB->Query( 'SELECT count(id) as countid FROM '.TABTOPIC.' WHERE forum='.$id.' AND type="I" AND replies=0 AND firstpostdate<"'.DateAdd(date('Ymd His'),-$intD,'day').'"'.$strWhere ); break;
case 'tags': $oDB->Query( 'SELECT count(*) as countid FROM '.TABTOPIC.' WHERE tags<>"" AND forum='.$id.$strWhere ); break;
case 'messages': $oDB->Query( 'SELECT count(*) as countid FROM '.TABPOST.' WHERE forum='.$id.$strWhere ); break;
case 'unrepliednews': $oDB->Query( 'SELECT count(id) as countid FROM '.TABTOPIC.' WHERE forum='.$id.' AND type="A" AND replies=0 AND firstpostdate<"'.DateAdd(date('Ymd His'),-$intD,'day').'"'.$strWhere ); break; // (unrepliedA) stays for backbward compatibility
default: die('cSection->Count: Wrong argument #1 '.$strObject);
}
$row = $oDB->Getrow();
return intval($row['countid']);
}
// --------
// IOptions, IStats implementations
// --------
public function ChangeOption($strKey,$strValue)
{
QTargs('cSection->ChangeOption',array($strKey,$strValue));
if ( $strKey==='' ) die ('cSection->ChangeOption: Missing key'); // $strKey can be ''
$arr = QTarradd(QTexplode($this->options),$strKey,$strValue);
$this->options = QTimplode($arr);
$this->WriteOptions();
return $arr;
}
public function ReadOptions()
{
$arr = QTexplode($this->options);
if ( isset($arr['order']) ) $this->d_order = $arr['order'];
if ( isset($arr['last']) ) $this->d_last = $arr['last'];
if ( isset($arr['logo']) ) $this->d_logo = $arr['logo'];
return $arr;
}
public function WriteOptions()
{
global $oDB;
$oDB->Query('UPDATE '.TABSECTION.' SET options="'.$this->options.'" WHERE id='.$this->id);
}
public function ChangeStat($strKey,$strValue)
{
QTargs('cSection->ChangeStat',array($strKey,$strValue));
if ( $strKey==='' ) die ('cSection->ChangeStat: Missing key'); // $strKey can be ''
$arr = QTarradd(QTexplode($this->stats),$strKey,$strValue);
$this->stats = QTimplode($arr);
$this->WriteOptions();
return $arr;
}
public function ReadStats()
{
$arr = QTexplode($this->stats);
if ( isset($arr['topics']) ) $this->items = intval($arr['topics']);
if ( isset($arr['replies']) ) $this->replies = intval($arr['replies']);
if ( isset($arr['tags']) ) $this->tags = intval($arr['tags']);
if ( isset($arr['topicsZ']) ) $this->itemsZ = intval($arr['topicsZ']);
if ( isset($arr['repliesZ']) ) $this->repliesZ = intval($arr['repliesZ']);
return $arr;
}
public function WriteStats()
{
global $oDB;
$oDB->Query('UPDATE '.TABSECTION.' SET stats="'.$this->stats.'" WHERE id='.$this->id);
}
// --------
}