diff --git a/assets/default/css/theme.css b/assets/default/css/theme.css index d004c4069706a8bc1d62e34fe19dd9850eaa3f9c..3f1cb699c0c6d477b45bec4a4e08b2626b75ade4 100644 --- a/assets/default/css/theme.css +++ b/assets/default/css/theme.css @@ -379,19 +379,33 @@ body { font-size: 15px; margin-left: 0; padding-left: 0; + border-top:1px solid #ddd; } #faq ol li { list-style: none; - margin: 0 0 10px 0; + margin: 0; + padding:0; color: #999; } #faq ol li a { - display: block; - height: 16px; + display:block; + padding:5px 0; + height:auto !important; + overflow:hidden; + margin:0; + border-bottom:1px solid #ddd; line-height: 16px; padding-left: 24px; background: url('../images/icons/page.png?1319579499') 0 50% no-repeat; } +#faq ol li a:hover { + background-color:#e9f5ff; +} + +.article-meta { + padding:5px; + background:#fafafa; +} /* Knowledgebase */ #kb { @@ -401,12 +415,21 @@ body { } #kb > li { - margin: 0 0 5px 0; - padding: 10px; - width: auto; - float: left; - clear: both; - list-style: none; + padding:10px; + height:auto !important; + overflow:hidden; + margin:0; + background:url(../images/kb_category_bg.png) bottom left repeat-x; + border-bottom:1px solid #ddd; +} + +#kb li i { + display:block; + width:32px; + height:32px; + float:left; + margin-right:6px; + background:url(../images/kb_large_folder.png) top left no-repeat; } #kb > li h4 { @@ -420,10 +443,51 @@ body { #kb > li h4 a { font-size: 14px; - padding-left: 24px; - background: url('../images/icons/page.png?1319579499') 0 50% no-repeat; } +#kb-search { + padding:10px 0; + overflow:hidden; +} + +#kb-search div { + clear:both; + overflow:hidden; + padding-top:5px; +} + +#kb-search #query { + margin:0; + display:inline-block; + float:left; + width:200px; + margin-right:5px; +} + +#kb-search #cid { + margin:0; + display:inline-block; + float:left; + width:200px; + margin-right:5px; + position:relative; + top:2px; +} + +#kb-search #topic-id { + margin:0; + display:inline-block; + float:left; + width:410px; +} + +#kb-search #searchSubmit { + margin:0; + display:inline-block; + float:left; + position:relative; + top:2px; +} #breadcrumbs { color: #333; diff --git a/assets/default/images/kb_category_bg.png b/assets/default/images/kb_category_bg.png new file mode 100644 index 0000000000000000000000000000000000000000..174d675f4c491060a413232bdef7e0e9298df60e Binary files /dev/null and b/assets/default/images/kb_category_bg.png differ diff --git a/assets/default/images/kb_large_folder.png b/assets/default/images/kb_large_folder.png new file mode 100644 index 0000000000000000000000000000000000000000..144fa828a3fc83613dd7a5b29368b6da290fd09d Binary files /dev/null and b/assets/default/images/kb_large_folder.png differ diff --git a/client.inc.php b/client.inc.php index b714e93b44bd587f4d10a2f292b2d4890bc63a3f..3b450e9e2491653ec44c65f346ef79758cc1d1a8 100644 --- a/client.inc.php +++ b/client.inc.php @@ -28,21 +28,12 @@ define('OSTCLIENTINC',TRUE); define('ASSETS_PATH',ROOT_PATH.'assets/default/'); - //Check the status of the HelpDesk. -if(!is_object($cfg) || !$cfg->getId() || $cfg->isHelpDeskOffline()) { +if(!is_object($cfg) || !$cfg->getId() || $cfg->isHelpDeskOffline() || $cfg->isUpgradePending()) { include('./offline.php'); exit; } -//Forced upgrade? Version mismatch. -if(defined('THIS_VERSION') && strcasecmp($cfg->getVersion(),THIS_VERSION)) { - die('System is offline for an upgrade.'); - exit; -} - - - /* include what is needed on client stuff */ require_once(INCLUDE_DIR.'class.client.php'); require_once(INCLUDE_DIR.'class.ticket.php'); diff --git a/include/ajax.config.php b/include/ajax.config.php index 7dcfd9972717e9c8cd5cb14a217b0e3b361dd9ee..fc9fb2c3fc8622108054052828b7e6bb9a42dcd6 100644 --- a/include/ajax.config.php +++ b/include/ajax.config.php @@ -19,7 +19,7 @@ if(!defined('INCLUDE_DIR')) die('!'); class ConfigAjaxAPI extends AjaxController { //config info UI might need. - function ui() { + function scp_ui() { global $thisstaff, $cfg; $config=array('ticket_lock_time'=>($cfg->getLockTime()*3600), diff --git a/include/ajax.tickets.php b/include/ajax.tickets.php index 458e430ea83192703bea52c026413af63c4edb63..f67581005194848131dbaf1c709b8c238c8e404a 100644 --- a/include/ajax.tickets.php +++ b/include/ajax.tickets.php @@ -20,11 +20,11 @@ include_once(INCLUDE_DIR.'class.ticket.php'); class TicketsAjaxAPI extends AjaxController { - function search() { + function lookup() { global $thisstaff; if(!is_numeric($_REQUEST['q'])) - return self::searchByEmail(); + return self::lookupByEmail(); $limit = isset($_REQUEST['limit']) ? (int) $_REQUEST['limit']:25; @@ -53,7 +53,7 @@ class TicketsAjaxAPI extends AjaxController { return $this->json_encode($tickets); } - function searchByEmail() { + function lookupByEmail() { global $thisstaff; @@ -84,6 +84,100 @@ class TicketsAjaxAPI extends AjaxController { return $this->json_encode($tickets); } + function search() { + global $thisstaff; + + $result=array(); + $select = 'SELECT count(ticket.ticket_id) as tickets '; + $from = ' FROM '.TICKET_TABLE.' ticket '; + $where = ' WHERE 1 '; + + //Access control. + $where.=' AND ( ticket.staff_id='.db_input($thisstaff->getId()); + + if(($teams=$thisstaff->getTeams()) && count(array_filter($teams))) + $where.=' OR ticket.team_id IN('.implode(',', array_filter($teams)).')'; + + if(!$thisstaff->showAssignedOnly() && ($depts=$thisstaff->getDepts())) + $where.=' OR ticket.dept_id IN ('.implode(',', $depts).')'; + + $where.=' ) '; + + //Department + if($_REQUEST['deptId']) + $where.=' AND ticket.dept_id='.db_input($_REQUEST['deptId']); + + //Status + switch(strtolower($_REQUEST['status'])) { + case 'open'; + $where.=' AND ticket.status="open" '; + break; + case 'overdue': + $where.=' AND ticket.status="open" AND ticket.isoverdue=1 '; + break; + case 'closed': + $where.=' AND ticket.status="closed" '; + break; + } + + //Assignee + if($_REQUEST['assignee'] && strcasecmp($_REQUEST['status'], 'closed')) { + $id=preg_replace("/[^0-9]/", "", $_REQUEST['assignee']); + $assignee = $_REQUEST['assignee']; + $where.= ' AND ( '; + if($assignee[0]=='t') + $where.=' (ticket.team_id='.db_input($id). ' AND ticket.status="open") '; + elseif($assignee[0]=='s') + $where.=' (ticket.staff_id='.db_input($id). ' AND ticket.status="open") '; + else + $where.=' (ticket.staff_id='.db_input($id). ' AND ticket.status="open") '; + + if($_REQUEST['staffId'] && !$_REQUEST['status']) //Assigned TO + Closed By + $where.= ' OR (ticket.staff_id='.db_input($_REQUEST['staffId']). ' AND ticket.status="closed") '; + + $where.= ' ) '; + } elseif($_REQUEST['staffId']) { + $where.=' AND (ticket.staff_id='.db_input($_REQUEST['staffId']).' AND ticket.status="closed") '; + } + + //dates + $startTime =($_REQUEST['startDate'] && (strlen($_REQUEST['startDate'])>=8))?strtotime($_REQUEST['startDate']):0; + $endTime =($_REQUEST['endDate'] && (strlen($_REQUEST['endDate'])>=8))?strtotime($_REQUEST['endDate']):0; + if( ($startTime && $startTime>time()) or ($startTime>$endTime && $endTime>0)) + $startTime=$endTime=0; + + if($startTime) + $where.=' AND ticket.created>=FROM_UNIXTIME('.$startTime.')'; + + if($endTime) + $where.=' AND ticket.created<=FROM_UNIXTIME('.$endTime.')'; + + //Query + if($_REQUEST['query']) { + $queryterm=db_real_escape($_REQUEST['query'], false); + + $from.=' LEFT JOIN '.TICKET_THREAD_TABLE.' thread ON (ticket.ticket_id=thread.ticket_id )'; + $where.=" AND ( ticket.email LIKE '%$queryterm%'" + ." OR ticket.name LIKE '%$queryterm%'" + ." OR ticket.subject LIKE '%$queryterm%'" + ." OR thread.title LIKE '%$queryterm%'" + ." OR thread.body LIKE '%$queryterm%'" + .' )'; + $groupby = 'GROUP BY ticket.ticket_id '; + } + + $sql="$select $from $where $groupby"; + if(($tickets=db_result(db_query($sql)))) { + $result['success'] =sprintf("Search criteria matched %s - <a href='tickets.php?%s'>view</a>", + ($tickets>1?"$tickets tickets":"$tickets ticket"), + str_replace(array('&', '&'), array('&', '&'), $_SERVER['QUERY_STRING'])); + } else { + $result['fail']='No tickets found matching your search criteria.'; + } + + return $this->json_encode($result); + } + function acquireLock($tid) { global $cfg,$thisstaff; diff --git a/include/class.config.php b/include/class.config.php index c51814bebc73aef1ae3a9052db364d2702798c04..95a5204e389b55c161cf192c1af9511793732e70 100644 --- a/include/class.config.php +++ b/include/class.config.php @@ -67,22 +67,35 @@ class Config { return !$this->isSystemOnline(); } + function isHelpDeskOnline() { + return $this->isSystemOnline(); + } + function isSystemOnline() { - return ($this->config['isonline']); + return ($this->config['isonline'] && !$this->isUpgradePending()); } - function isKnowledgebaseEnabled() { + function isUpgradePending() { + return (defined('SCHEMA_SIGNATURE') && strcasecmp($this->getSchemaSignature(), SCHEMA_SIGNATURE)); + } + function isKnowledgebaseEnabled() { require_once(INCLUDE_DIR.'class.faq.php'); return ($this->config['enable_kb'] && FAQ::countPublishedFAQs()); } function getVersion() { - return '1.7-DPR2'; + return THIS_VERSION; } function getSchemaSignature() { - return $this->config['schema_signature']; + + if($this->config['schema_signature']) + return $this->config['schema_signature']; + elseif($this->config['ostversion']) //old version 1.6 st. + return md5(strtoupper($this->config['ostversion'])); + + return null; } function setMysqlTZ($tz) { diff --git a/include/class.dept.php b/include/class.dept.php index 8bd575116a421dba88b82dd236243829aeadfc32..bf82b76526b7ce77abbdcdbaa213c939207ca4ad 100644 --- a/include/class.dept.php +++ b/include/class.dept.php @@ -47,6 +47,7 @@ class Dept { $this->id=$this->ht['dept_id']; $this->email=$this->sla=$this->manager=null; $this->getEmail(); //Auto load email struct. + $this->members=array(); return true; } @@ -88,6 +89,21 @@ class Dept { return $this->getNumStaff(); } + function getAvailableMembers(){ + + if(!$this->members && $this->getNumStaff()){ + $sql='SELECT m.staff_id FROM '.STAFF_TABLE.' m ' + .'WHERE m.dept_id='.db_input($this->getId()) + .' AND s.staff_id IS NOT NULL ' + .'ORDER BY s.lastname, s.firstname'; + if(($res=db_query($sql)) && db_num_rows($res)){ + while(list($id)=db_fetch_row($res)) + if($staff= Staff::lookup($id) && $staff->isAvailable()) + $this->members[]= $staff; + } + } + return $this->members; + } function getSLAId(){ return $this->ht['sla_id']; diff --git a/include/class.knowledgebase.php b/include/class.knowledgebase.php index d8a64689168de48014011bf46c45e029056efdea..6bb67898f7a94f7b6f95c547b646241aa45c2699 100644 --- a/include/class.knowledgebase.php +++ b/include/class.knowledgebase.php @@ -55,9 +55,11 @@ class Knowledgebase { function publish() { $this->published = true; } function unpublish() { $this->published = false; } function setPublished($val) { $this->published = !!$val; } + function setEnabled($val) { $this->enabled = !!$val; } function setTitle($title) { $this->title = $title; } function setKeywords($words) { $this->keywords = $words; } function setAnswer($text) { $this->answer = $text; } + function setDepartment($id) { $this->department = $id; } /* -------------> Validation and Clean methods <------------ */ function validate(&$errors, $what=null) { diff --git a/include/class.mailfetch.php b/include/class.mailfetch.php index 5f97775930f25da87f80261cc20b66cdad947b8f..4ee15ecca38404efcd943fcd984d6b3d335854b6 100644 --- a/include/class.mailfetch.php +++ b/include/class.mailfetch.php @@ -242,7 +242,7 @@ class MailFetcher { function getBody($mid) { $body =''; - if(!($body = $this->getpart($mid,'TEXT/PLAIN',$this->charset))) { + if(!($body = $this->getPart($mid,'TEXT/PLAIN',$this->charset))) { if(($body = $this->getPart($mid,'TEXT/HTML',$this->charset))) { //Convert tags of interest before we striptags $body=str_replace("</DIV><DIV>", "\n", $body); diff --git a/include/class.staff.php b/include/class.staff.php index 0630a0fe514d391c90af98bd47fe06c7c3871422..26ffcc703a144981c1142987d9eb50f6ff233b06 100644 --- a/include/class.staff.php +++ b/include/class.staff.php @@ -220,7 +220,7 @@ class Staff { return $this->showAssignedOnly(); } - function isadmin() { + function isAdmin() { return ($this->ht['isadmin']); } @@ -261,7 +261,7 @@ class Staff { } function canManageTickets() { - return ($this->isadmin() + return ($this->isAdmin() || $this->canDeleteTickets() || $this->canCloseTickets()); } diff --git a/include/class.sys.php b/include/class.sys.php index ab10cd99442fa640bd36a6a329b6cc27e18f1b7f..33b5c830407f1b56fb1ef8eff47657e1296bb97a 100644 --- a/include/class.sys.php +++ b/include/class.sys.php @@ -96,7 +96,7 @@ class Sys { function purgeLogs(){ global $cfg; - if($cfg && ($gp=$cfg->getLogGraceperiod()) && is_numeric($gp)) { + if($cfg && ($gp=$cfg->getLogGracePeriod()) && is_numeric($gp)) { $sql='DELETE FROM '.SYSLOG_TABLE.' WHERE DATE_ADD(created, INTERVAL '.$gp.' MONTH)<=NOW()'; db_query($sql); } diff --git a/include/class.team.php b/include/class.team.php index 7aada43a3b13a6529822ef8a764ba958b7f838d8..b3f996d28fc658ed03d5e458679fc97953de000b 100644 --- a/include/class.team.php +++ b/include/class.team.php @@ -200,7 +200,6 @@ class Team { $sql='SET updated=NOW(),isenabled='.db_input($vars['isenabled']). ',name='.db_input($vars['name']). - ',isenabled='.db_input($vars['isenabled']). ',noalerts='.db_input(isset($vars['noalerts'])?$vars['noalerts']:0). ',notes='.db_input($vars['notes']); diff --git a/include/class.ticket.php b/include/class.ticket.php index 8eca918fbb101b71f02276b930e62b1bde35a3b1..275ef78c26b88c7dc306e18753c7196b2b8cf51d 100644 --- a/include/class.ticket.php +++ b/include/class.ticket.php @@ -75,18 +75,25 @@ class Ticket{ $sql='SELECT ticket.*, topic.topic as helptopic, lock_id, dept_name, priority_desc ' .' ,count(attach.attach_id) as attachments ' - .' ,count(DISTINCT message.msg_id) as messages ' - .' ,count(DISTINCT response.response_id) as responses ' - .' ,count(DISTINCT note.note_id) as notes ' + .' ,count(DISTINCT message.id) as messages ' + .' ,count(DISTINCT response.id) as responses ' + .' ,count(DISTINCT note.id) as notes ' .' FROM '.TICKET_TABLE.' ticket ' .' LEFT JOIN '.DEPT_TABLE.' dept ON (ticket.dept_id=dept.dept_id) ' - .' LEFT JOIN '.TICKET_PRIORITY_TABLE.' pri ON (ticket.priority_id=pri.priority_id) ' - .' LEFT JOIN '.TOPIC_TABLE.' topic ON (ticket.topic_id=topic.topic_id) ' - .' LEFT JOIN '.TICKET_LOCK_TABLE.' tlock ON (ticket.ticket_id=tlock.ticket_id AND tlock.expire>NOW()) ' - .' LEFT JOIN '.TICKET_ATTACHMENT_TABLE.' attach ON (ticket.ticket_id=attach.ticket_id) ' - .' LEFT JOIN '.TICKET_MESSAGE_TABLE.' message ON (ticket.ticket_id=message.ticket_id) ' - .' LEFT JOIN '.TICKET_RESPONSE_TABLE.' response ON (ticket.ticket_id=response.ticket_id) ' - .' LEFT JOIN '.TICKET_NOTE_TABLE.' note ON (ticket.ticket_id=note.ticket_id ) ' + .' LEFT JOIN '.TICKET_PRIORITY_TABLE.' pri ON (' + .'ticket.priority_id=pri.priority_id) ' + .' LEFT JOIN '.TOPIC_TABLE.' topic ON (' + .'ticket.topic_id=topic.topic_id) ' + .' LEFT JOIN '.TICKET_LOCK_TABLE.' tlock ON (' + .'ticket.ticket_id=tlock.ticket_id AND tlock.expire>NOW()) ' + .' LEFT JOIN '.TICKET_ATTACHMENT_TABLE.' attach ON (' + .'ticket.ticket_id=attach.ticket_id) ' + .' LEFT JOIN '.TICKET_THREAD_TABLE.' message ON (' + ."ticket.ticket_id=message.ticket_id AND message.thread_type = 'M') " + .' LEFT JOIN '.TICKET_THREAD_TABLE.' response ON (' + ."ticket.ticket_id=response.ticket_id AND response.thread_type = 'R') " + .' LEFT JOIN '.TICKET_THREAD_TABLE.' note ON ( ' + ."ticket.ticket_id=note.ticket_id AND note.thread_type = 'N') " .' WHERE ticket.ticket_id='.db_input($id) .' GROUP BY ticket.ticket_id'; @@ -437,9 +444,10 @@ class Ticket{ function getLastRespondent() { $sql ='SELECT resp.staff_id ' - .' FROM '.TICKET_RESPONSE_TABLE.' resp ' + .' FROM '.TICKET_THREAD_TABLE.' resp ' .' LEFT JOIN '.STAFF_TABLE. ' USING(staff_id) ' .' WHERE resp.ticket_id='.db_input($this->getId()).' AND resp.staff_id>0 ' + .' AND resp.thread_type="R"' .' ORDER BY resp.created DESC LIMIT 1'; if(!($res=db_query($sql)) || !db_num_rows($res)) @@ -457,8 +465,9 @@ class Ticket{ return $this->lastmsgdate; //for old versions...XXX: still needed???? - $sql='SELECT created FROM '.TICKET_MESSAGE_TABLE + $sql='SELECT created FROM '.TICKET_THREAD_TABLE .' WHERE ticket_id='.db_input($this->getId()) + ." AND thread_type = 'M'" .' ORDER BY created DESC LIMIT 1'; if(($res=db_query($sql)) && db_num_rows($res)) list($this->lastmsgdate)=db_fetch_row($res); @@ -475,8 +484,9 @@ class Ticket{ if($this->lastrespdate) return $this->lastrespdate; - $sql='SELECT created FROM '.TICKET_RESPONSE_TABLE + $sql='SELECT created FROM '.TICKET_THREAD_TABLE .' WHERE ticket_id='.db_input($this->getId()) + .' AND thread_type="R"' .' ORDER BY created DESC LIMIT 1'; if(($res=db_query($sql)) && db_num_rows($res)) list($this->lastrespdate)=db_fetch_row($res); @@ -523,11 +533,12 @@ class Ticket{ $order='DESC'; $sql ='SELECT note.*, count(DISTINCT attach.attach_id) as attachments ' - .' FROM '.TICKET_NOTE_TABLE.' note ' + .' FROM '.TICKET_THREAD_TABLE.' note ' .' LEFT JOIN '.TICKET_ATTACHMENT_TABLE.' attach - ON (note.ticket_id=attach.ticket_id AND note.note_id=attach.ref_id AND ref_type="N") ' + ON (note.ticket_id=attach.ticket_id AND note.id=attach.ref_id AND ref_type="N") ' .' WHERE note.ticket_id='.db_input($this->getId()) - .' GROUP BY note.note_id ' + .' AND note.thread_type="N"' + .' GROUP BY note.id ' .' ORDER BY note.created '.$order; $notes=array(); @@ -540,14 +551,17 @@ class Ticket{ function getMessages() { - $sql='SELECT msg.msg_id, msg.created, msg.message ' - .' ,count(DISTINCT attach.attach_id) as attachments, count( DISTINCT resp.response_id) as responses ' - .' FROM '.TICKET_MESSAGE_TABLE.' msg ' - .' LEFT JOIN '.TICKET_RESPONSE_TABLE. ' resp ON(resp.msg_id=msg.msg_id) ' - .' LEFT JOIN '.TICKET_ATTACHMENT_TABLE.' attach - ON (msg.ticket_id=attach.ticket_id AND msg.msg_id=attach.ref_id AND ref_type="M") ' + $sql='SELECT msg.id, msg.created, msg.body ' + .' ,count(DISTINCT attach.attach_id) as attachments ' + .' ,count( DISTINCT resp.id) as responses ' + .' FROM '.TICKET_THREAD_TABLE.' msg ' + .' LEFT JOIN '.TICKET_THREAD_TABLE.' resp ON (' + .'resp.pid=msg.id AND resp.thread_type = "R") ' + .' LEFT JOIN '.TICKET_ATTACHMENT_TABLE.' attach ' + .'ON (msg.ticket_id=attach.ticket_id AND msg.id=attach.ref_id AND ref_type="M") ' .' WHERE msg.ticket_id='.db_input($this->getId()) - .' GROUP BY msg.msg_id ' + .' AND msg.thread_type="M"' + .' GROUP BY msg.id ' .' ORDER BY msg.created ASC '; $messages=array(); @@ -561,11 +575,12 @@ class Ticket{ function getResponses($msgId) { $sql='SELECT resp.*, count(DISTINCT attach.attach_id) as attachments ' - .' FROM '.TICKET_RESPONSE_TABLE. ' resp ' + .' FROM '.TICKET_THREAD_TABLE. ' resp ' .' LEFT JOIN '.TICKET_ATTACHMENT_TABLE.' attach - ON (resp.ticket_id=attach.ticket_id AND resp.response_id=attach.ref_id AND ref_type="R") ' + ON (resp.ticket_id=attach.ticket_id AND resp.id=attach.ref_id AND ref_type="R") ' .' WHERE resp.ticket_id='.db_input($this->getId()) - .' GROUP BY resp.response_id ' + .' AND resp.thread_type="R"' + .' GROUP BY resp.id ' .' ORDER BY resp.created'; $responses=array(); @@ -654,10 +669,14 @@ class Ticket{ //Set staff ID...assign/unassign/release (id can be 0) function setStaffId($staffId){ - $sql='UPDATE '.TICKET_TABLE.' SET updated=NOW(), staff_id='.db_input($staffId) - .' WHERE ticket_id='.db_input($this->getId()); + $sql='UPDATE '.TICKET_TABLE.' SET updated=NOW(), staff_id='.db_input($staffId) + .' WHERE ticket_id='.db_input($this->getId()); - return (db_query($sql) && db_affected_rows()); + if (db_query($sql) && db_affected_rows()) { + $this->staff_id = $staffId; + return true; + } + return false; } function setSLAId($slaId) { @@ -769,7 +788,7 @@ class Ticket{ $sql.=' WHERE ticket_id='.db_input($this->getId()); - $this->track('closed'); + $this->logEvent('closed'); return (db_query($sql) && db_affected_rows()); } @@ -783,7 +802,7 @@ class Ticket{ //TODO: log reopen event here - $this->track('reopened'); + $this->logEvent('reopened'); return (db_query($sql) && db_affected_rows()); } @@ -873,7 +892,7 @@ class Ticket{ $msg=sprintf('Max open tickets (%d) reached for %s ', $cfg->getMaxOpenTickets(), $this->getEmail()); sys::log(LOG_WARNING, 'Max. Open Tickets Limit ('.$this->getEmail().')', $msg); - if(!$sendNotice || !$cfg->sendOverlimitNotice()) return true; + if(!$sendNotice || !$cfg->sendOverLimitNotice()) return true; //Send notice to user. $dept = $this->getDept(); @@ -953,7 +972,7 @@ class Ticket{ $email=$cfg->getDefaultEmail(); if($email) { - $email->send($this->getEMail(),$subj,$body); + $email->send($this->getEmail(),$subj,$body); } } @@ -996,12 +1015,12 @@ class Ticket{ $recipients=array(); //Assigned staff or team... if any // Assigning a ticket to a team when already assigned to staff disables alerts to the team (!)) - if($cfg->alertStaffONAssign() && $this->getStaffId()) + if($cfg->alertStaffONAssignment() && $this->getStaffId()) $recipients[]=$this->getStaff(); elseif($this->getTeamId() && ($team=$this->getTeam())) { - if($cfg->alertTeamMembersOnAssignment() && ($members=$team->getMembers())) + if($cfg->alertTeamMembersONAssignment() && ($members=$team->getMembers())) $recipients+=$members; - elseif($cfg->alertTeamLeadOnAssignment() && ($lead=$team->getTeamLead())) + elseif($cfg->alertTeamLeadONAssignment() && ($lead=$team->getTeamLead())) $recipients[]=$lead; } //Send the alerts. @@ -1128,8 +1147,8 @@ class Ticket{ if(!db_query($sql) || !db_affected_rows()) return false; + $this->logEvent('overdue'); $this->onOverdue($whine); - $this->track('overdue'); return true; } @@ -1150,6 +1169,7 @@ class Ticket{ $this->reopen(); $this->reload(); //reload - new dept!! + $this->logEvent('transferred'); //Send out alerts if enabled AND requested if(!$alert || !$cfg->alertONTransfer() || !($dept=$this->getDept())) return true; //no alerts!! @@ -1196,7 +1216,6 @@ class Ticket{ } } - $this->track('transferred'); return true; } @@ -1209,8 +1228,8 @@ class Ticket{ return false; $this->onAssign($note, $alert); + $this->logEvent('assigned'); - $this->track('assigned'); return true; } @@ -1228,8 +1247,8 @@ class Ticket{ $this->setStaffId(0); $this->onAssign($note, $alert); + $this->logEvent('assigned'); - $this->track('assigned'); return true; } @@ -1270,18 +1289,18 @@ class Ticket{ } //Insert message from client - function postMessage($msg,$source='',$msgid=NULL,$headers='',$newticket=false){ + function postMessage($msg,$source='',$emsgid=null,$headers='',$newticket=false){ global $cfg; if(!$this->getId()) return 0; # XXX: Refuse auto-response messages? (via email) XXX: No - but kill our auto-responder. - $sql='INSERT INTO '.TICKET_MESSAGE_TABLE.' SET created=NOW() ' + $sql='INSERT INTO '.TICKET_THREAD_TABLE.' SET created=NOW()' + .' ,thread_type="M" ' .' ,ticket_id='.db_input($this->getId()) - .' ,messageId='.db_input($msgid) - .' ,message='.db_input(Format::striptags($msg)) //Tags/code stripped...meaning client can not send in code..etc - .' ,headers='.db_input($headers) //Raw header. + # XXX: Put Subject header into the 'title' field + .' ,body='.db_input(Format::striptags($msg)) //Tags/code stripped...meaning client can not send in code..etc .' ,source='.db_input($source?$source:$_SERVER['REMOTE_ADDR']) .' ,ip_address='.db_input($_SERVER['REMOTE_ADDR']); @@ -1289,6 +1308,15 @@ class Ticket{ $this->setLastMsgId($msgid); + if ($emsgid !== null) { + $sql='INSERT INTO '.TICKET_EMAIL_INFO_TABLE + .' SET msg_id='.db_input($msgid) + .', email_mid='.db_input($emsgid) + .', headers='.db_input($headers); + + if (!db_query($sql)) return 0; + } + if($newticket) return $msgid; //Our work is done... $autorespond = true; @@ -1353,10 +1381,11 @@ class Ticket{ if($errors) return 0; - $sql='INSERT INTO '.TICKET_RESPONSE_TABLE.' SET created=NOW() ' + $sql='INSERT INTO '.TICKET_THREAD_TABLE.' SET created=NOW() ' + .' ,thread_type="R"' .' ,ticket_id='.db_input($this->getId()) - .' ,msg_id='.db_input($vars['msgId']) - .' ,response='.db_input(Format::striptags($vars['response'])) + .' ,pid='.db_input($vars['msgId']) + .' ,body='.db_input(Format::striptags($vars['response'])) .' ,staff_id='.db_input($thisstaff->getId()) .' ,staff_name='.db_input($thisstaff->getName()) .' ,ip_address='.db_input($thisstaff->getIP()); @@ -1430,11 +1459,11 @@ class Ticket{ if(!$cfg || !$cfg->logTicketActivity()) return 0; - return $this->postNote($title,$note,false,'system'); + return $this->postNote($title,$note,false,'System'); } // History log -- used for statistics generation (pretty reports) - function track($state, $staff=null) { + function logEvent($state, $staff=null) { global $thisstaff; if ($staff === null) { @@ -1442,8 +1471,12 @@ class Ticket{ else $staff='SYSTEM'; # XXX: Security Violation ? } - return db_query('INSERT INTO '.TICKET_HISTORY_TABLE + return db_query('INSERT INTO '.TICKET_EVENT_TABLE .' SET ticket_id='.db_input($this->getId()) + .', staff_id='.db_input($this->getStaffId()) + .', team_id='.db_input($this->getTeamId()) + .', dept_id='.db_input($this->getDeptId()) + .', topic_id='.db_input($this->getTopicId()) .', timestamp=NOW(), state='.db_input($state) .', staff='.db_input($staff)) && db_affected_rows() == 1; @@ -1453,12 +1486,13 @@ class Ticket{ function postNote($title,$note,$alert=true,$poster='') { global $thisstaff,$cfg; - $sql= 'INSERT INTO '.TICKET_NOTE_TABLE.' SET created=NOW() '. + $sql= 'INSERT INTO '.TICKET_THREAD_TABLE.' SET created=NOW() '. + ',thread_type="N"'. ',ticket_id='.db_input($this->getId()). ',title='.db_input(Format::striptags($title)). - ',note='.db_input(Format::striptags($note)). + ',body='.db_input(Format::striptags($note)). ',staff_id='.db_input($thisstaff?$thisstaff->getId():0). - ',source='.db_input(($poster || !$thisstaff)?$poster:$thisstaff->getName()); + ',poster='.db_input(($poster || !$thisstaff)?$poster:$thisstaff->getName()); //echo $sql; if(!db_query($sql) || !($id=db_insert_id())) return false; @@ -1560,9 +1594,7 @@ class Ticket{ if(!db_query($sql) || !db_affected_rows()) return false; - db_query('DELETE FROM '.TICKET_MESSAGE_TABLE.' WHERE ticket_id='.db_input($this->getId())); - db_query('DELETE FROM '.TICKET_RESPONSE_TABLE.' WHERE ticket_id='.db_input($this->getId())); - db_query('DELETE FROM '.TICKET_NOTE_TABLE.' WHERE ticket_id='.db_input($this->getId())); + db_query('DELETE FROM '.TICKET_THREAD_TABLE.' WHERE ticket_id='.db_input($this->getId())); $this->deleteAttachments(); return true; @@ -1678,8 +1710,9 @@ class Ticket{ return 0; $sql='SELECT ticket.ticket_id FROM '.TICKET_TABLE. ' ticket '. - ' LEFT JOIN '.TICKET_MESSAGE_TABLE.' msg USING(ticket_id) '. - ' WHERE messageId='.db_input($mid).' AND email='.db_input($email); + ' LEFT JOIN '.TICKE_THREAD_TABLE.' msg USING(ticket_id) '. + ' INNER JOIN '.TICKET_EMAIL_INFO_TABLE.' emsg ON (msg.id = emsg.message_id) '. + ' WHERE email_mid='.db_input($mid).' AND email='.db_input($email); $id=0; if(($res=db_query($sql)) && db_num_rows($res)) list($id)=db_fetch_row($res); @@ -1962,6 +1995,9 @@ class Ticket{ && ($client->getNumOpenTickets()==$cfg->getMaxOpenTickets())) { $ticket->onOpenLimit(($autorespond && strcasecmp($origin, 'staff'))); } + + /* Start tracking ticket lifecycle events */ + $ticket->logEvent('created'); /* Phew! ... time for tea (KETEPA) */ diff --git a/include/client/faq.inc.php b/include/client/faq.inc.php index c944f8316f58fb1b1ff59854bb7a63c05d505de5..65f770e9673083d2474d2a9eb260771492541d41 100644 --- a/include/client/faq.inc.php +++ b/include/client/faq.inc.php @@ -6,7 +6,7 @@ $category=$faq->getCategory(); ?> <h1>Frequently Asked Questions</h1> <div id="breadcrumbs"> - <a href="index.php">All Categories</a> + <a href="index.php">All Categories</a> » <a href="faq.php?cid=<? echo $category->getId(); ?>"><? echo $category->getName(); ?></a> </div> <div style="width:700;padding-top:2px; float:left;"> @@ -23,7 +23,8 @@ if($faq->getNumAttachments()) { ?> <div><span class="faded"><b>Attachments:</b></span> <?php echo $faq->getAttachmentsLinks(); ?></div> <? }?> -<div><span class="faded"><b>Help Topics:</b></span> + +<div class="article-meta"><span class="faded"><b>Help Topics:</b></span> <?php echo ($topics=$faq->getHelpTopics())?implode(', ',$topics):' '; ?> </div> </p> diff --git a/include/client/knowledgebase.inc.php b/include/client/knowledgebase.inc.php index 83484e95de818d732a67fed39b980fd5e9262e95..d8f402e7b5d191b224dc638b54f3a3177bddce85 100644 --- a/include/client/knowledgebase.inc.php +++ b/include/client/knowledgebase.inc.php @@ -3,61 +3,53 @@ if(!defined('OSTCLIENTINC')) die('Access Denied'); ?> <h1>Frequently Asked Questions</h1> -<form action="index.php" method="get" style="padding-top:15px;"> +<form action="index.php" method="get" id="kb-search"> <input type="hidden" name="a" value="search"> - <table border="0" cellspacing="0" cellpadding="3"> - <tr> - <td width="440"> - <input id="query" type="text" size="20" name="q" value="<?php echo Format::htmlchars($_REQUEST['q']); ?>"> - <select name="cid"> - <option value="">— All Categories —</option> - <?php - $sql='SELECT category_id, name, count(faq.category_id) as faqs ' - .' FROM '.FAQ_CATEGORY_TABLE.' cat ' - .' LEFT JOIN '.FAQ_TABLE.' faq USING(category_id) ' - .' WHERE cat.ispublic=1 AND faq.ispublished=1 ' - .' GROUP BY cat.category_id ' - .' HAVING faqs>0 ' - .' ORDER BY cat.name DESC '; - if(($res=db_query($sql)) && db_num_rows($res)) { - while($row=db_fetch_array($res)) - echo sprintf('<option value="%d" %s>%s (%d)</option>', - $row['category_id'], - ($_REQUEST['cid'] && $row['category_id']==$_REQUEST['cid']?'selected="selected"':''), - $row['name'], - $row['faqs']); - } - ?> - </select> - </td> - <td width="100" rowspan="2" style="text-align:left;vertical-align: middle;"> - <input id="searchSubmit" type="submit" value="Search"> - </td> - </tr> - <tr> - <td width="400"> - <select name="topicId" style="width:350px;"> - <option value="">— All Help Topics —</option> - <?php - $sql='SELECT ht.topic_id, ht.topic, count(faq.topic_id) as faqs ' - .' FROM '.TOPIC_TABLE.' ht ' - .' LEFT JOIN '.FAQ_TOPIC_TABLE.' faq USING(topic_id) ' - .' WHERE ht.ispublic=1 ' - .' GROUP BY ht.topic_id ' - .' HAVING faqs>0 ' - .' ORDER BY ht.topic DESC '; - if(($res=db_query($sql)) && db_num_rows($res)) { - while($row=db_fetch_array($res)) - echo sprintf('<option value="%d" %s>%s (%d)</option>', - $row['topic_id'], - ($_REQUEST['topicId'] && $row['topic_id']==$_REQUEST['topicId']?'selected="selected"':''), - $row['topic'], $row['faqs']); - } - ?> - </select> - </td> - </tr> - </table> + <div> + <input id="query" type="text" size="20" name="q" value="<?php echo Format::htmlchars($_REQUEST['q']); ?>"> + <select name="cid" id="cid"> + <option value="">— All Categories —</option> + <?php + $sql='SELECT category_id, name, count(faq.category_id) as faqs ' + .' FROM '.FAQ_CATEGORY_TABLE.' cat ' + .' LEFT JOIN '.FAQ_TABLE.' faq USING(category_id) ' + .' WHERE cat.ispublic=1 AND faq.ispublished=1 ' + .' GROUP BY cat.category_id ' + .' HAVING faqs>0 ' + .' ORDER BY cat.name DESC '; + if(($res=db_query($sql)) && db_num_rows($res)) { + while($row=db_fetch_array($res)) + echo sprintf('<option value="%d" %s>%s (%d)</option>', + $row['category_id'], + ($_REQUEST['cid'] && $row['category_id']==$_REQUEST['cid']?'selected="selected"':''), + $row['name'], + $row['faqs']); + } + ?> + </select> + <input id="searchSubmit" type="submit" value="Search"> + </div> + <div> + <select name="topicId" id="topic-id"> + <option value="">— All Help Topics —</option> + <?php + $sql='SELECT ht.topic_id, ht.topic, count(faq.topic_id) as faqs ' + .' FROM '.TOPIC_TABLE.' ht ' + .' LEFT JOIN '.FAQ_TOPIC_TABLE.' faq USING(topic_id) ' + .' WHERE ht.ispublic=1 ' + .' GROUP BY ht.topic_id ' + .' HAVING faqs>0 ' + .' ORDER BY ht.topic DESC '; + if(($res=db_query($sql)) && db_num_rows($res)) { + while($row=db_fetch_array($res)) + echo sprintf('<option value="%d" %s>%s (%d)</option>', + $row['topic_id'], + ($_REQUEST['topicId'] && $row['topic_id']==$_REQUEST['topicId']?'selected="selected"':''), + $row['topic'], $row['faqs']); + } + ?> + </select> + </div> </form> <hr> <div> @@ -100,9 +92,10 @@ if($_REQUEST['q'] || $_REQUEST['cid'] || $_REQUEST['topicId']) { //Search. echo '<div>Click on the category to browse FAQs.</div> <ul id="kb">'; while($row=db_fetch_array($res)) { - + echo sprintf(' <li> + <i></i> <h4><a href="faq.php?cid=%d">%s (%d)</a></h4> %s </li>',$row['category_id'], diff --git a/include/client/tickets.inc.php b/include/client/tickets.inc.php index a360217167bde83dedcb4decb339677e3c5370d6..7719ec74a7ef2a58babcae7112a0d2cb05caa92e 100644 --- a/include/client/tickets.inc.php +++ b/include/client/tickets.inc.php @@ -59,13 +59,12 @@ if($search) { $queryterm=db_real_escape($_REQUEST['q'],false); //escape the term ONLY...no quotes. $qwhere.=' AND ( ' ." ticket.subject LIKE '%$queryterm%'" - ." OR message.message LIKE '%$queryterm%'" - ." OR response.response LIKE '%$queryterm%'" + ." OR thread.body LIKE '%$queryterm%'" .' ) '; $deep_search=true; //Joins needed for search - $qfrom.=' LEFT JOIN '.TICKET_MESSAGE_TABLE.' message ON (ticket.ticket_id=message.ticket_id )' - .' LEFT JOIN '.TICKET_RESPONSE_TABLE.' response ON (ticket.ticket_id=response.ticket_id )'; + $qfrom.=' LEFT JOIN '.TICKET_THREAD_TABLE.' thread ON (' + .'ticket.ticket_id=thread.ticket_id AND thread.thread_type IN ("M","R"))'; } } diff --git a/include/client/view.inc.php b/include/client/view.inc.php index e720ed96bffa58c5d7321e7fe2544c7829a86678..f67e6d94bd3a4456e30b17797254dff49204b960 100644 --- a/include/client/view.inc.php +++ b/include/client/view.inc.php @@ -67,11 +67,11 @@ if($ticket->getThreadCount() && ($messages = $ticket->getMessages())) { <tr><th><?php echo Format::db_datetime($message['created']); ?></th></tr> - <tr><td><?php echo Format::display($message['message']); ?></td></tr> + <tr><td><?php echo Format::display($message['body']); ?></td></tr> <?php - if($message['attachments'] && ($links=$ticket->getAttachmentsLinks($message['msg_id'],'M'))) { ?> + if($message['attachments'] && ($links=$ticket->getAttachmentsLinks($message['id'],'M'))) { ?> <tr><td class="info"><?php echo $links; ?></td></tr> @@ -81,7 +81,7 @@ if($ticket->getThreadCount() && ($messages = $ticket->getMessages())) { </table> <?php - if($message['responses'] && ($responses=$ticket->getResponses($message['msg_id']))) { + if($message['responses'] && ($responses=$ticket->getResponses($message['id']))) { foreach($responses as $resp) { $staff=$cfg->hideStaffName()?'staff':Format::htmlchars($resp['staff_name']); ?> @@ -89,9 +89,9 @@ if($ticket->getThreadCount() && ($messages = $ticket->getMessages())) { <tr> <th><?php echo Format::db_datetime($resp['created']);?> - <?php echo $staff; ?></th> </tr> - <tr><td><?php echo Format::display($resp['response']); ?></td></tr> + <tr><td><?php echo Format::display($resp['body']); ?></td></tr> <?php - if($resp['attachments'] && ($links=$ticket->getAttachmentsLinks($resp['response_id'],'R'))) {?> + if($resp['attachments'] && ($links=$ticket->getAttachmentsLinks($resp['id'],'R'))) {?> <tr><td class="info"><?php echo $links; ?></td></tr> <?php }?> diff --git a/include/staff/api.inc.php b/include/staff/api.inc.php deleted file mode 100644 index 21eac469162af3d2cc9652d8e8255f230ee18460..0000000000000000000000000000000000000000 --- a/include/staff/api.inc.php +++ /dev/null @@ -1,147 +0,0 @@ -<?php -if(!defined('OSTADMININC') || !$thisstaff->isadmin()) die('Access Denied'); - - -$info['phrase']=($errors && $_POST['phrase'])?Format::htmlchars($_POST['phrase']):$cfg->getAPIPassphrase(); -$select='SELECT * '; -$from='FROM '.API_KEY_TABLE; -$where=''; -$sortOptions=array('date'=>'created','ip'=>'ipaddr'); -$orderWays=array('DESC'=>'DESC','ASC'=>'ASC'); -//Sorting options... -if($_REQUEST['sort']) { - $order_column =$sortOptions[$_REQUEST['sort']]; -} - -if($_REQUEST['order']) { - $order=$orderWays[$_REQUEST['order']]; -} -$order_column=$order_column?$order_column:'ipaddr'; -$order=$order?$order:'ASC'; -$order_by=" ORDER BY $order_column $order "; - -$total=db_count('SELECT count(*) '.$from.' '.$where); -$pagelimit=1000;//No limit. TODO: Add limit. -$page=($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1; -$pageNav=new Pagenate($total,$page,$pagelimit); -$pageNav->setURL('admin.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&order='.urlencode($_REQUEST['order'])); -$query="$select $from $where $order_by"; -//echo $query; -$result = db_query($query); -$showing=db_num_rows($result)?$pageNav->showing():''; -$negorder=$order=='DESC'?'ASC':'DESC'; //Negate the sorting.. -$deletable=0; -?> -<div class="msg">API Keys</div> -<hr> -<div><b><?php echo $showing; ?></b></div> - <table width="100%" border="0" cellspacing=1 cellpadding=2> - <form action="admin.php?t=api" method="POST" name="api" onSubmit="return checkbox_checker(document.forms['api'],1,0);"> - <input type=hidden name='t' value='api'> - <input type=hidden name='do' value='mass_process'> - <tr><td> - <table border="0" cellspacing=0 cellpadding=2 class="dtable" align="center" width="100%"> - <tr> - <th width="7px"> </th> - <th>API Key</th> - <th width="10" nowrap>Active</th> - <th width="100" nowrap> IP Address</th> - <th width="150" nowrap> - <a href="admin.php?t=api&sort=date&order=<?php echo $negorder; ?><?php echo $qstr; ?>" title="Sort By Create Date <?php echo $negorder; ?>">Created</a></th> - </tr> - <?php - $class = 'row1'; - $total=0; - $active=$inactive=0; - $sids=($errors && is_array($_POST['ids']))?$_POST['ids']:null; - if($result && db_num_rows($result)): - $dtpl=$cfg->getDefaultTemplateId(); - while ($row = db_fetch_array($result)) { - $sel=false; - $disabled=''; - if($row['isactive']) - $active++; - else - $inactive++; - - if($sids && in_array($row['id'],$sids)){ - $class="$class highlight"; - $sel=true; - } - ?> - <tr class="<?php echo $class; ?>" id="<?php echo $row['id']; ?>"> - <td width=7px> - <input type="checkbox" name="ids[]" value="<?php echo $row['id']; ?>" <?php echo $sel?'checked':''; ?> - onClick="highLight(this.value,this.checked);"> - <td> <?php echo $row['apikey']; ?></td> - <td><?php echo $row['isactive']?'<b>Yes</b>':'No'; ?></td> - <td> <?php echo $row['ipaddr']; ?></td> - <td> <?php echo Format::db_datetime($row['created']); ?></td> - </tr> - <?php - $class = ($class =='row2') ?'row1':'row2'; - } //end of while. - else: //nothin' found!! ?> - <tr class="<?php echo $class; ?>"><td colspan=5><b>Query returned 0 results</b> <a href="admin.php?t=templates">Index list</a></td></tr> - <?php - endif; ?> - - </table> - </td></tr> - <?php - if(db_num_rows($result)>0): //Show options.. - ?> - <tr> - <td align="center"> - <?php - if($inactive) { ?> - <input class="button" type="submit" name="enable" value="Enable" - onClick='return confirm("Are you sure you want to ENABLE selected keys?");'> - <?php - } - if($active){ ?> - - <input class="button" type="submit" name="disable" value="Disable" - onClick='return confirm("Are you sure you want to DISABLE selected keys?");'> - <?php } ?> - - <input class="button" type="submit" name="delete" value="Delete" - onClick='return confirm("Are you sure you want to DELETE selected keys?");'> - </td> - </tr> - <?php - endif; - ?> - </form> - </table> - <br/> - <div class="msg">Add New IP</div> - <hr> - <div> - Add a new IP address. <font class="error"><?php echo $errors['ip']; ?></font> - <form action="admin.php?t=api" method="POST" > - <input type=hidden name='t' value='api'> - <input type=hidden name='do' value='add'> - New IP: - <input name="ip" size=30 value="<?php echo ($errors['ip'])?Format::htmlchars($_REQUEST['ip']):''; ?>" /> - <font class="error">* </font> - <input class="button" type="submit" name="add" value="Add"> - </form> - </div> - <br/> - <div class="msg">API Passphrase</div> - <hr> - <div> - Passphrase must be at least 3 words. Required to generate the api keys.<br/> - <form action="admin.php?t=api" method="POST" > - <input type=hidden name='t' value='api'> - <input type=hidden name='do' value='update_phrase'> - Phrase: - <input name="phrase" size=50 value="<?php echo Format::htmlchars($info['phrase']); ?>" /> - <font class="error">* <?php echo $errors['phrase']; ?></font> - <input class="button" type="submit" name="update" value="Submit"> - </form> - <br/><br/> - <div><i>Please note that changing the passprase does NOT invalidate existing keys. To regerate a key you need to delete and readd it.</i></div> - </div> - diff --git a/include/staff/apikey.inc.php b/include/staff/apikey.inc.php index 5a82ee39bf264a821de957a779c0a73087f78bd9..7bcac1cb03e257feb855fbf0436769b8b3a3650e 100644 --- a/include/staff/apikey.inc.php +++ b/include/staff/apikey.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied'); $info=array(); $qstr=''; if($api && $_REQUEST['a']!='add'){ diff --git a/include/staff/apikeys.inc.php b/include/staff/apikeys.inc.php index d7063c749ce92c04cddc36f20902b88181ab51d4..3deccb941222f8d771eb120ea90ab7e27557203c 100644 --- a/include/staff/apikeys.inc.php +++ b/include/staff/apikeys.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff->isAdmin()) die('Access Denied'); $qstr=''; $sql='SELECT * FROM '.API_KEY_TABLE.' WHERE 1'; diff --git a/include/staff/attachment.inc.php b/include/staff/attachment.inc.php index 17819867e69a458517e7c312075c07ffe3eeb06c..5951b87c0b0788767b34c98d1a7290a7c1debcdd 100644 --- a/include/staff/attachment.inc.php +++ b/include/staff/attachment.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff->isAdmin()) die('Access Denied'); //Get the config info. $config=($errors && $_POST)?Format::input($_POST):$cfg->getConfig(); ?> diff --git a/include/staff/banlist.inc.php b/include/staff/banlist.inc.php index ecef00ba4325e18339b4f733d82a34b38466b950..430b51f4835bbf7038941109621774b409485b2e 100644 --- a/include/staff/banlist.inc.php +++ b/include/staff/banlist.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isadmin() || !$filter) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin() || !$filter) die('Access Denied'); $qstr=''; $select='SELECT rule.* '; diff --git a/include/staff/banrule.inc.php b/include/staff/banrule.inc.php index bd28d19dea8368b395122beeb861045205d7ddff..0560b4a4d6268961220dad69de5d7b73617afec2 100644 --- a/include/staff/banrule.inc.php +++ b/include/staff/banrule.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied'); $info=array(); $qstr=''; diff --git a/include/staff/department.inc.php b/include/staff/department.inc.php index fa32ec2795d1ab1635fa126ab639a5d1259f3258..521cee9bf9e9eb7446420c26c4e0ab03a1c3ad69 100644 --- a/include/staff/department.inc.php +++ b/include/staff/department.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied'); $info=array(); $qstr=''; if($dept && $_REQUEST['a']!='add'){ diff --git a/include/staff/departments.inc.php b/include/staff/departments.inc.php index 805b7ec20706c7cbbfa1bb2dd331068aa3bc8154..71b702a0676cff5f6824c933fc458882fff9e991 100644 --- a/include/staff/departments.inc.php +++ b/include/staff/departments.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff->isAdmin()) die('Access Denied'); $qstr=''; $sql='SELECT dept.dept_id,dept_name,email.email_id,email.email,email.name as email_name,ispublic,count(staff.staff_id) as users '. diff --git a/include/staff/email.inc.php b/include/staff/email.inc.php index 4f2d695b09304c4dcd5fc850e32ede734c514bbf..2fd2b8857494c64c061524a5bd294e4433299ee4 100644 --- a/include/staff/email.inc.php +++ b/include/staff/email.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied'); $info=array(); $qstr=''; if($email && $_REQUEST['a']!='add'){ diff --git a/include/staff/emails.inc.php b/include/staff/emails.inc.php index 65d34d7b9bfb0b10acd983bfe41e5671932d3060..8d5f221177051e484fcaff4457c5f9f60bffbc99 100644 --- a/include/staff/emails.inc.php +++ b/include/staff/emails.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff->isAdmin()) die('Access Denied'); $qstr=''; $sql='SELECT email.*,dept.dept_name as department,priority_desc as priority '. diff --git a/include/staff/filter.inc.php b/include/staff/filter.inc.php index 91f74501661cda00d97aada035b28559a9961d41..6f8cce2c41a1e6acd8f4810b3cdc7e643a9a4471 100644 --- a/include/staff/filter.inc.php +++ b/include/staff/filter.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied'); $matches=array('name'=>"Sender's Name",'email'=>"Sender's Email",'subject'=>'Email Subject','body'=>'Email Body/Text','header'=>'Email Header'); $match_types=array('equal'=>'Equal','not_equal'=>'Not Equal','contains'=>'Contains','dn_contain'=>'Does Not Contain'); diff --git a/include/staff/filters.inc.php b/include/staff/filters.inc.php index fb8a48d268a7705d5eb3a49b4076a6dcdb3b0b17..b5534bdde77a12ffe88a8f2362046c5d2e64fce2 100644 --- a/include/staff/filters.inc.php +++ b/include/staff/filters.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff->isAdmin()) die('Access Denied'); $qstr=''; $sql='SELECT filter.*,count(rule.id) as rules '. diff --git a/include/staff/group.inc.php b/include/staff/group.inc.php index 87921a63cb18aad7a2c73ab73ab5a2c7fb3d8acd..afb574f5f3cea7ff161dc34e90c05fa77f955b51 100644 --- a/include/staff/group.inc.php +++ b/include/staff/group.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied'); $info=array(); $qstr=''; if($group && $_REQUEST['a']!='add'){ diff --git a/include/staff/groups.inc.php b/include/staff/groups.inc.php index 15b9b6610916c203cdf25e902228dd8d5281ba5a..ed5e3638a8d0528908584ddfad5320d885a38e4d 100644 --- a/include/staff/groups.inc.php +++ b/include/staff/groups.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied'); $qstr=''; diff --git a/include/staff/header.inc.php b/include/staff/header.inc.php index 58d4f28dcdf77cbe3fa184e8a4979982b01de0fe..b0a7c4efef46bfa5ce923ac251beb101c3125293 100644 --- a/include/staff/header.inc.php +++ b/include/staff/header.inc.php @@ -26,7 +26,7 @@ <div id="container"> <div id="header"> <a href="index.php" id="logo">osTicket - Customer Support System</a> - <p id="info">Welcome back, <strong><?php echo $thisstaff->getUsername(); ?></strong> + <p id="info">Welcome back, <strong><?php echo $thisstaff->getUserName(); ?></strong> <?php if($thisstaff->isAdmin() && !defined('ADMINPAGE')) { ?> | <a href="admin.php">Admin Panel</a> diff --git a/include/staff/helptopic.inc.php b/include/staff/helptopic.inc.php index ad9f808bcfd6afedfabec510dda920ca2abaae0a..c0fdcd34010266a802bbffdd3f31c741c36f0b9a 100644 --- a/include/staff/helptopic.inc.php +++ b/include/staff/helptopic.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied'); $info=array(); $qstr=''; if($topic && $_REQUEST['a']!='add'){ diff --git a/include/staff/helptopics.inc.php b/include/staff/helptopics.inc.php index 27ffde9bdacac59c2687b30b5046dde4255b1537..b3d58c777517753e02b41d1aaa703ed6e5500c01 100644 --- a/include/staff/helptopics.inc.php +++ b/include/staff/helptopics.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff->isAdmin()) die('Access Denied'); $qstr=''; $sql='SELECT topic.*,dept.dept_name as department,priority_desc as priority '. diff --git a/include/staff/preference.inc.php b/include/staff/preference.inc.php index d956d011dff2c15ad87c7e023f69303a87034353..054d592a7555f8d16f436f9cc5c9c66a91b6f27b 100644 --- a/include/staff/preference.inc.php +++ b/include/staff/preference.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff->isAdmin()) die('Access Denied'); //Get the config info. $config=($errors && $_POST)?Format::input($_POST):Format::htmlchars($cfg->getConfig()); diff --git a/include/staff/slaplan.inc.php b/include/staff/slaplan.inc.php index 91d896d639d688813389ed0582ecd800beb2a842..70db620e84d83dc66a53cf6c08e1d97ea2b31f24 100644 --- a/include/staff/slaplan.inc.php +++ b/include/staff/slaplan.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied'); $info=array(); $qstr=''; if($sla && $_REQUEST['a']!='add'){ diff --git a/include/staff/slaplans.inc.php b/include/staff/slaplans.inc.php index 5dea61f69b8ccaeaec3b84411185fbe4a26da886..b8997b6a34be75b697624384e0e39006c5c16feb 100644 --- a/include/staff/slaplans.inc.php +++ b/include/staff/slaplans.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff->isAdmin()) die('Access Denied'); $qstr=''; $sql='SELECT * FROM '.SLA_TABLE.' sla WHERE 1'; diff --git a/include/staff/staff.inc.php b/include/staff/staff.inc.php index 8883397f51fe86c6b46c5207a099ad33ec50ec31..ddfa1e6dfb716240f1d1fce6b12bcd43112e974e 100644 --- a/include/staff/staff.inc.php +++ b/include/staff/staff.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied'); $info=array(); $qstr=''; diff --git a/include/staff/staffmembers.inc.php b/include/staff/staffmembers.inc.php index aa41b1bbf4a00a6143bb8bd0961d8a8ab4a801b0..b01e3387ff28da3e2f8e419b4e728293fe851254 100644 --- a/include/staff/staffmembers.inc.php +++ b/include/staff/staffmembers.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied'); $qstr=''; $select='SELECT staff.*,CONCAT_WS(" ",firstname,lastname) as name, grp.group_name, dept.dept_name as dept,count(m.team_id) as teams '; $from='FROM '.STAFF_TABLE.' staff '. diff --git a/include/staff/syslogs.inc.php b/include/staff/syslogs.inc.php index 482dd429c3738faea83e49df05a09c8dd391a7e2..cb43e905e4ef0914b09067dd753f7bf67a39498b 100644 --- a/include/staff/syslogs.inc.php +++ b/include/staff/syslogs.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied'); $qstr=''; if($_REQUEST['type']) { diff --git a/include/staff/team.inc.php b/include/staff/team.inc.php index 7f8c409decba5de347d3cac28b848ce3ad78fa44..51b06ce2d1fa51344dbef35258a72cc68ddbf60b 100644 --- a/include/staff/team.inc.php +++ b/include/staff/team.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied'); $info=array(); $qstr=''; if($team && $_REQUEST['a']!='add'){ diff --git a/include/staff/teams.inc.php b/include/staff/teams.inc.php index 1aa6dc4ed0554692b67449970caf0d799673f709..ab3a2f58d4a88e94ea4d08653b853352d37be680 100644 --- a/include/staff/teams.inc.php +++ b/include/staff/teams.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied'); $qstr=''; $sql='SELECT team.*,count(m.staff_id) as members,CONCAT_WS(" ",lead.firstname,lead.lastname) as team_lead '. diff --git a/include/staff/template.inc.php b/include/staff/template.inc.php index 15881945e369c2fa541163008b3c9f4c9ce2352f..ac5c09a744879021e7286f116dc91e18a26df95f 100644 --- a/include/staff/template.inc.php +++ b/include/staff/template.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied'); $info=array(); $qstr=''; diff --git a/include/staff/templates.inc.php b/include/staff/templates.inc.php index 7f82f656f12cafe984de35ff205eb62bfef2b1a7..f60e3b010ec7efe053fd1a73df1cefe9366b9daa 100644 --- a/include/staff/templates.inc.php +++ b/include/staff/templates.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff->isAdmin()) die('Access Denied'); $qstr=''; $sql='SELECT tpl.*,count(dept.tpl_id) as depts '. diff --git a/include/staff/ticket-view.inc.php b/include/staff/ticket-view.inc.php index 33f46eadd443ccf0cda94867d0e54a924b73e30e..faac0f86ef791a8726c266a8121a980860ddc267 100644 --- a/include/staff/ticket-view.inc.php +++ b/include/staff/ticket-view.inc.php @@ -196,11 +196,11 @@ if($ticket->isOverdue()) </tr> <tr> <td colspan="2"> - <?php echo Format::htmlchars($note['note']); ?> + <?php echo Format::htmlchars($note['body']); ?> </td> </tr> <?php - if($note['attachments'] && ($links=$ticket->getAttachmentsLinks($note['note_id'],'N'))) {?> + if($note['attachments'] && ($links=$ticket->getAttachmentsLinks($note['id'],'N'))) {?> <tr> <td class="info" colspan="2"><?php echo $links; ?></td> </tr> @@ -220,9 +220,9 @@ if($ticket->isOverdue()) foreach($messages as $message) {?> <table class="message" cellspacing="0" cellpadding="1" width="940" border="0"> <tr><th><?php echo Format::db_datetime($message['created']); ?></th></tr> - <tr><td><?php echo Format::display($message['message']); ?></td></tr> + <tr><td><?php echo Format::display($message['body']); ?></td></tr> <?php - if($message['attachments'] && ($links=$ticket->getAttachmentsLinks($message['msg_id'],'M'))) {?> + if($message['attachments'] && ($links=$ticket->getAttachmentsLinks($message['id'],'M'))) {?> <tr> <td class="info"><?php echo $links; ?></td> </tr> @@ -231,17 +231,17 @@ if($ticket->isOverdue()) </table> <?php /* --------- Responses ------------ */ - if($message['responses'] && ($responses=$ticket->getResponses($message['msg_id']))) { + if($message['responses'] && ($responses=$ticket->getResponses($message['id']))) { foreach($responses as $resp) {?> <table class="response" cellspacing="0" cellpadding="1" width="100%" border="0"> <tr> <th><?php echo Format::db_datetime($resp['created']); ?> - <?php echo Format::htmlchars($resp['staff_name']); ?></th> </tr> <tr> - <td><?php echo Format::display($resp['response']); ?></td> + <td><?php echo Format::display($resp['body']); ?></td> </tr> <?php - if($resp['attachments'] && ($links=$ticket->getAttachmentsLinks($resp['response_id'],'R'))) {?> + if($resp['attachments'] && ($links=$ticket->getAttachmentsLinks($resp['id'],'R'))) {?> <tr> <td class="info"><?php echo $links; ?></td> </tr> @@ -251,7 +251,7 @@ if($ticket->isOverdue()) <?php } } - $msgId=$message['msg_id']; + $msgId=$message['id']; } } else { echo '<p>Error fetching ticket thread - get technical help.</p>'; diff --git a/include/staff/tickets.inc.php b/include/staff/tickets.inc.php index 67d270c3f033e0db98e901d66b09fdcabf5247c6..9d6d5c7bcf0005e315f4e6e032943c97a237c01d 100644 --- a/include/staff/tickets.inc.php +++ b/include/staff/tickets.inc.php @@ -42,6 +42,7 @@ switch(strtolower($_REQUEST['status'])){ //Status is overloaded case 'assigned': $status='open'; $staffId=$thisstaff->getId(); + $results_type='My Tickets'; break; case 'answered': $status='open'; @@ -97,9 +98,6 @@ $deep_search=false; if($search): $qstr.='&a='.urlencode($_REQUEST['a']); $qstr.='&t='.urlencode($_REQUEST['t']); - if(isset($_REQUEST['advance_search'])){ //advance search box! - $qstr.='&advance_search=Search'; - } //query if($searchTerm){ @@ -108,6 +106,8 @@ if($search): if(is_numeric($searchTerm)){ $qwhere.=" AND ticket.ticketID LIKE '$queryterm%'"; }elseif(strpos($searchTerm,'@') && Validator::is_email($searchTerm)){ //pulling all tricks! + # XXX: What about searching for email addresses in the body of + # the thread message $qwhere.=" AND ticket.email='$queryterm'"; }else{//Deep search! //This sucks..mass scan! search anything that moves! @@ -117,33 +117,50 @@ if($search): $qwhere.=" AND ( ticket.email LIKE '%$queryterm%'". " OR ticket.name LIKE '%$queryterm%'". " OR ticket.subject LIKE '%$queryterm%'". - " OR note.title LIKE '%$queryterm%'". - " OR MATCH(message.message) AGAINST('$queryterm')". - " OR MATCH(response.response) AGAINST('$queryterm')". - " OR MATCH(note.note) AGAINST('$queryterm')". + " OR thread.title LIKE '%$queryterm%'". + " OR MATCH(thread.body) AGAINST('$queryterm')". ' ) '; }else{ $qwhere.=" AND ( ticket.email LIKE '%$queryterm%'". " OR ticket.name LIKE '%$queryterm%'". " OR ticket.subject LIKE '%$queryterm%'". - " OR message.message LIKE '%$queryterm%'". - " OR response.response LIKE '%$queryterm%'". - " OR note.note LIKE '%$queryterm%'". - " OR note.title LIKE '%$queryterm%'". + " OR thread.body LIKE '%$queryterm%'". + " OR thread.title LIKE '%$queryterm%'". ' ) '; } } } //department - if($_REQUEST['dept'] && in_array($_REQUEST['dept'],$thisstaff->getDepts())) { + if($_REQUEST['deptId'] && in_array($_REQUEST['deptId'],$thisstaff->getDepts())) { //This is dept based search..perm taken care above..put the sucker in. - $qwhere.=' AND ticket.dept_id='.db_input($_REQUEST['dept']); - $qstr.='&dept='.urlencode($_REQUEST['dept']); + $qwhere.=' AND ticket.dept_id='.db_input($_REQUEST['deptId']); + $qstr.='&deptId='.urlencode($_REQUEST['deptId']); } - //Teams - if($_REQUEST['team'] && ($thisuser->isadmin() || in_array($_REQUEST['team'],$thisuser->getTeams()))) { - $qwhere.=' AND ticket.team_id='.db_input($_REQUEST['team']); - $qstr.='&team='.urlencode($_REQUEST['team']); + + //Assignee + if($_REQUEST['assignee'] && strcasecmp($_REQUEST['status'], 'closed')) { + $id=preg_replace("/[^0-9]/", "", $_REQUEST['assignee']); + $assignee = $_REQUEST['assignee']; + $qstr.='&assignee='.urlencode($_REQUEST['assignee']); + $qwhere.= ' AND ( '; + + if($assignee[0]=='t') + $qwhere.=' (ticket.team_id='.db_input($id). ' AND ticket.status="open") '; + elseif($assignee[0]=='s') + $qwhere.=' (ticket.staff_id='.db_input($id). ' AND ticket.status="open") '; + else + $qwhere.=' (ticket.staff_id='.db_input($id). ' AND ticket.status="open") '; + + + if($_REQUEST['staffId'] && !$_REQUEST['status']) { //Assigned TO + Closed By + $qwhere.= ' OR (ticket.staff_id='.db_input($_REQUEST['staffId']). ' AND ticket.status="closed") '; + $qstr.='&staffId='.urlencode($_REQUEST['staffId']); + } + + $qwhere.= ' ) '; + } elseif($_REQUEST['staffId']) { + $qwhere.=' AND (ticket.staff_id='.db_input($_REQUEST['staffId']).' AND ticket.status="closed") '; + $qstr.='&staffId='.urlencode($_REQUEST['staffId']); } //dates @@ -163,7 +180,7 @@ if($search): $qwhere.=' AND ticket.created<=FROM_UNIXTIME('.$endTime.')'; $qstr.='&endDate='.urlencode($_REQUEST['endDate']); } -} + } endif; @@ -206,9 +223,7 @@ $qfrom=' FROM '.TICKET_TABLE.' ticket '. $sjoin=''; if($search && $deep_search) { - $sjoin=' LEFT JOIN '.TICKET_MESSAGE_TABLE.' message ON (ticket.ticket_id=message.ticket_id )' - .' LEFT JOIN '.TICKET_RESPONSE_TABLE.' response ON (ticket.ticket_id=response.ticket_id )' - .' LEFT JOIN '.TICKET_NOTE_TABLE.' note ON (ticket.ticket_id=note.ticket_id ) '; + $sjoin=' LEFT JOIN '.TICKET_THREAD_TABLE.' thread ON (ticket.ticket_id=thread.ticket_id )'; } $qgroup=' GROUP BY ticket.ticket_id'; @@ -222,9 +237,7 @@ $pageNav->setURL('tickets.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&ord //ADD attachment,priorities, lock and other crap $qselect.=' ,count(attach.attach_id) as attachments ' - .' ,count(DISTINCT message.msg_id) as messages ' - .' ,count(DISTINCT response.response_id) as responses ' - .' ,count(DISTINCT note.note_id) as notes ' + .' ,count(DISTINCT thread.id) as thread_count ' .' ,IF(ticket.reopened is NULL,IF(ticket.lastmessage is NULL,ticket.created,ticket.lastmessage),ticket.reopened) as effective_date ' .' ,CONCAT_WS(" ", staff.firstname, staff.lastname) as staff, team.name as team ' .' ,IF(staff.staff_id IS NULL,team.name,CONCAT_WS(" ", staff.lastname, staff.firstname)) as assigned '; @@ -233,9 +246,7 @@ $qfrom.=' LEFT JOIN '.TICKET_PRIORITY_TABLE.' pri ON (ticket.priority_id=pri.pri .' LEFT JOIN '.TICKET_LOCK_TABLE.' tlock ON (ticket.ticket_id=tlock.ticket_id AND tlock.expire>NOW() AND tlock.staff_id!='.db_input($thisstaff->getId()).') ' .' LEFT JOIN '.TICKET_ATTACHMENT_TABLE.' attach ON (ticket.ticket_id=attach.ticket_id) ' - .' LEFT JOIN '.TICKET_MESSAGE_TABLE.' message ON (ticket.ticket_id=message.ticket_id) ' - .' LEFT JOIN '.TICKET_RESPONSE_TABLE.' response ON (ticket.ticket_id=response.ticket_id) ' - .' LEFT JOIN '.TICKET_NOTE_TABLE.' note ON (ticket.ticket_id=note.ticket_id ) ' + .' LEFT JOIN '.TICKET_THREAD_TABLE.' thread ON ( ticket.ticket_id=thread.ticket_id) ' .' LEFT JOIN '.STAFF_TABLE.' staff ON (ticket.staff_id=staff.staff_id) ' .' LEFT JOIN '.TEAM_TABLE.' team ON (ticket.team_id=team.team_id) '; @@ -245,17 +256,18 @@ $hash = md5($query); $_SESSION['search_'.$hash] = $query; $res = db_query($query); $showing=db_num_rows($res)?$pageNav->showing():""; -if(!$results_type) { - $results_type=($search)?'Search Results':ucfirst($status).' Tickets'; -} -$negorder=$order=='DESC'?'ASC':'DESC'; //Negate the sorting.. +if(!$results_type) + $results_type = ucfirst($status).' Tickets'; -$basic_display=!isset($_REQUEST['advance_search'])?true:false; +if($search) + $results_type.= ' (Search Results)'; + +$negorder=$order=='DESC'?'ASC':'DESC'; //Negate the sorting.. //YOU BREAK IT YOU FIX IT. ?> <!-- SEARCH FORM START --> -<div id='basic' style="display:<?php echo $basic_display?'block':'none'; ?>"> +<div id='basic_search'> <form action="tickets.php" method="get"> <input type="hidden" name="a" value="search"> <table> @@ -263,6 +275,7 @@ $basic_display=!isset($_REQUEST['advance_search'])?true:false; <td><input type="text" id="basic-ticket-search" name="query" size=30 value="<?php echo Format::htmlchars($_REQUEST['query']); ?>" autocomplete="off" autocorrect="off" autocapitalize="off"></td> <td><input type="submit" name="basic_search" class="button" value="Search"></td> + <td> <a href="" id="go-advanced">[advanced]</a></td> </tr> </table> </form> @@ -300,7 +313,7 @@ $basic_display=!isset($_REQUEST['advance_search'])?true:false; title="Sort By Status <?php echo $negorder; ?>">Status</a></th> <?php } else { ?> - <th width="60" <?=$pri_sort?>> + <th width="60" <?php echo $pri_sort;?>> <a <?php echo $pri_sort; ?> href="tickets.php?sort=pri&order=<?php echo $negorder; ?><?php echo $qstr; ?>" title="Sort By Priority <?php echo $negorder; ?>">Priority</a></th> <?php @@ -310,15 +323,18 @@ $basic_display=!isset($_REQUEST['advance_search'])?true:false; <th width="150"> <a <?php echo $assignee_sort; ?> href="tickets.php?sort=assignee&order=<?php echo $negorder; ?><?php echo $qstr; ?>" title="Sort By Assignee <?php echo $negorder;?>">Assigned To</a></th> - <?}elseif(!strcasecmp($status,'closed')){?> + <?php + } elseif(!strcasecmp($status,'closed')) { ?> <th width="150"> <a <?php echo $staff_sort; ?> href="tickets.php?sort=staff&order=<?php echo $negorder; ?><?php echo $qstr; ?>" title="Sort By Closing Staff Name <?php echo $negorder; ?>">Closed By</a></th> - <?}else{?> + <?php + } else { ?> <th width="150"> - <a <?=$dept_sort?> href="tickets.php?sort=dept&order=<?=$negorder?><?=$qstr?>" - title="Sort By Department <?=$negorder?>">Department</a></th> - <?}?> + <a <?php echo $dept_sort; ?> href="tickets.php?sort=dept&order=<?php echo $negorder;?><?php echo $qstr; ?>" + title="Sort By Department <?php echo $negorder; ?>">Department</a></th> + <?php + } ?> </tr> </thead> <tbody> @@ -347,7 +363,7 @@ $basic_display=!isset($_REQUEST['advance_search'])?true:false; } $tid=$row['ticketID']; $subject = Format::truncate($row['subject'],40); - $threadcount=$row['messages']+$row['responses']; + $threadcount=$row['thread_count']; if(!strcasecmp($row['status'],'open') && !$row['isanswered'] && !$row['lock_id']) { $tid=sprintf('<b>%s</b>',$tid); } @@ -449,3 +465,89 @@ $basic_display=!isset($_REQUEST['advance_search'])?true:false; } ?> </form> </div> +<div id="overlay"></div> +<div style="display:none;" id="advanced-search"> + <h3>Advanced Ticket Search</h3> + <a class="close" href="">×</a> + <form action="tickets.php" method="post" id="search" name="search"> + <input type="hidden" name="a" value="search"> + <fieldset class="query"> + <label for="query">Keyword:</label> + <input type="input" id="query" name="query" size="20"> <em>Optional</em> + </fieldset> + <fieldset> + <label for="status">Status:</label> + <select id="status" name="status"> + <option value="">— Any Status —</option> + <option value="open">Open</option> + <option value="overdue">Overdue</option> + <option value="closed">Closed</option> + </select> + <label for="deptId">Dept:</label> + <select id="deptId" name="deptId"> + <option value="">— All Departments —</option> + <?php + if(($mydepts = $thisstaff->getDepts()) && ($depts=Dept::getDepartments())) { + foreach($depts as $id =>$name) { + if(!in_array($id, $mydepts)) continue; + echo sprintf('<option value="%d">%s</option>', $id, $name); + } + } + ?> + </select> + </fieldset> + <fieldset class="owner"> + <label for="assignee">Assigned To:</label> + <select id="assignee" name="assignee"> + <option value="0">— Anyone —</option> + <?php + if(($users=Staff::getStaffMembers())) { + echo '<OPTGROUP label="Staff Members ('.count($users).')">'; + foreach($users as $id => $name) { + $k="s$id"; + echo sprintf('<option value="%s">%s</option>', $k, $name); + } + echo '</OPTGROUP>'; + } + + if(($teams=Team::getTeams())) { + echo '<OPTGROUP label="Teams ('.count($teams).')">'; + foreach($teams as $id => $name) { + $k="t$id"; + echo sprintf('<option value="%s">%s</option>', $k, $name); + } + echo '</OPTGROUP>'; + } + ?> + </select> + <label for="staffId">Closed By:</label> + <select id="staffId" name="staffId"> + <option value="0">— Anyone —</option> + <?php + if(($users=Staff::getStaffMembers())) { + foreach($users as $id => $name) + echo sprintf('<option value="%d">%s</option>', $id, $name); + } + ?> + </select> + </fieldset> + <fieldset class="date_range"> + <label>Date Range:</label> + <input class="dp" type="input" size="20" name="startDate"><i></i> + <span>TO</span> + <input class="dp" type="input" size="20" name="endDate"><i></i> + </fieldset> + <p> + <span class="buttons"> + <input type="submit" value="Search"> + <input type="reset" value="Reset"> + <input type="button" value="Cancel" class="close"> + </span> + <span class="spinner"> + <img src="./images/ajax-loader.gif" width="16" height="16"> + </span> + </p> + </form> + <div id="result-count"> + </div> +</div> diff --git a/include/staff/topic.inc.php b/include/staff/topic.inc.php index 6504c5443200a4a3bd82624fec18c27c0ff3ea24..f0f895409d99ebd2c39c4013572b1ee455887090 100644 --- a/include/staff/topic.inc.php +++ b/include/staff/topic.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff->isAdmin()) die('Access Denied'); $info=($_POST && $errors)?Format::input($_POST):array(); //Re-use the post info on error...savekeyboards.org if($topic && $_REQUEST['a']!='new'){ diff --git a/login.php b/login.php index 044d74644785f32a0f79bae76e6c4309fd473b2a..48dc9ec4aea9a5ab7c427cacc30b17c8005944b5 100644 --- a/login.php +++ b/login.php @@ -45,7 +45,7 @@ if($_POST && (!empty($_POST['lemail']) && !empty($_POST['lticket']))): //At this point we know the ticket is valid. //TODO: 1) Check how old the ticket is...3 months max?? 2) Must be the latest 5 tickets?? //Check the email given. - if($ticket->getId() && strcasecmp($ticket->getEMail(),$email)==0){ + if($ticket->getId() && strcasecmp($ticket->getEmail(),$email)==0){ //valid match...create session goodies for the client. $user = new ClientSession($email,$ticket->getId()); $_SESSION['_client']=array(); //clear. diff --git a/main.inc.php b/main.inc.php index bb997ebd6cb5d1d98d30136a66c55bd8a79008a7..fdd1a6863cc1e4b2210235415af5dbe49ee7634f 100644 --- a/main.inc.php +++ b/main.inc.php @@ -55,7 +55,7 @@ #Current version && schema signature (Changes from version to version) define('THIS_VERSION','1.7-DPR2'); //Shown on admin panel - define('SCHEMA_SIGNATURE','ssddsdsd'); //MD5 signature of the db schema. (used to trigger upgrades) + define('SCHEMA_SIGNATURE','abe9c0cb845be52c10fcd7b3e626a589'); //MD5 signature of the db schema. (used to trigger upgrades) #load config info $configfile=''; @@ -135,14 +135,12 @@ define('CANNED_ATTACHMENT_TABLE',TABLE_PREFIX.'canned_attachment'); define('TICKET_TABLE',TABLE_PREFIX.'ticket'); - define('TICKET_NOTE_TABLE',TABLE_PREFIX.'ticket_note'); - define('TICKET_MESSAGE_TABLE',TABLE_PREFIX.'ticket_message'); - define('TICKET_RESPONSE_TABLE',TABLE_PREFIX.'ticket_response'); + define('TICKET_THREAD_TABLE',TABLE_PREFIX.'ticket_thread'); define('TICKET_ATTACHMENT_TABLE',TABLE_PREFIX.'ticket_attachment'); define('TICKET_PRIORITY_TABLE',TABLE_PREFIX.'ticket_priority'); define('PRIORITY_TABLE',TICKET_PRIORITY_TABLE); define('TICKET_LOCK_TABLE',TABLE_PREFIX.'ticket_lock'); - define('TICKET_HISTORY_TABLE',TABLE_PREFIX.'ticket_history'); + define('TICKET_EVENT_TABLE',TABLE_PREFIX.'ticket_event'); define('EMAIL_TABLE',TABLE_PREFIX.'email'); define('EMAIL_TEMPLATE_TABLE',TABLE_PREFIX.'email_template'); diff --git a/scp/admin.inc.php b/scp/admin.inc.php index a580fa6986b87661b039419bcf178e5ae46ad12e..5f6f5e7633422251ca7bbf8960f69461a8afbc35 100644 --- a/scp/admin.inc.php +++ b/scp/admin.inc.php @@ -15,34 +15,29 @@ **********************************************************************/ require('staff.inc.php'); //Make sure config is loaded and the staff is set and of admin type -if(!$cfg or !$thisstaff or !$thisstaff->isadmin()){ +if(!$cfg or !$thisstaff or !$thisstaff->isAdmin()){ header('Location: index.php'); require('index.php'); // just in case! exit; } //Some security related warnings - bitch until fixed!!! :) -if(defined('THIS_VERSION') && strcasecmp($cfg->getVersion(),THIS_VERSION)) { - $sysnotice=sprintf('The script is version %s while the database is version %s.',THIS_VERSION,$cfg->getVersion()); - if(file_exists('../setup/')) - $sysnotice.=' Possibly caused by incomplete <a href="../setup/upgrade.php">upgrade</a>.'; - $errors['err']=$sysnotice; -}elseif(!$cfg->isHelpDeskOffline()) { - if(file_exists('../setup/')){ - $sysnotice='Please take a minute to delete <strong>setup/install</strong> directory for security reasons.'; - }else{ - - if(CONFIG_FILE && file_exists(CONFIG_FILE) && is_writable(CONFIG_FILE)) { +if($cfg->isUpgradePending()) { + $errors['err']=$sysnotice='System upgrade is pending <a href="../setup/upgrade.php">Upgrade Now</a>'; +} elseif(!$cfg->isHelpDeskOffline()) { + + if(file_exists('../setup/')) { + $sysnotice='Please take a minute to delete <strong>setup/install</strong> directory (../setup/) for security reasons.'; + } elseif(CONFIG_FILE && file_exists(CONFIG_FILE) && is_writable(CONFIG_FILE)) { //Confirm for real that the file is writable by group or world. clearstatcache(); //clear the cache! $perms = @fileperms(CONFIG_FILE); if(($perms & 0x0002) || ($perms & 0x0010)) { $sysnotice=sprintf('Please change permission of config file (%s) to remove write access. e.g <i>chmod 644 %s</i>', - basename(CONFIG_FILE),basename(CONFIG_FILE)); + basename(CONFIG_FILE), basename(CONFIG_FILE)); } - } - } + if(!$sysnotice && ini_get('register_globals')) $sysnotice='Please consider turning off register globals if possible'; } diff --git a/scp/ajax.php b/scp/ajax.php index 471e9c710d577d662abae098ef2053dbfd702694..2b08168adda9664f710f8b4abaa47cb4c0b78801 100644 --- a/scp/ajax.php +++ b/scp/ajax.php @@ -43,10 +43,13 @@ $dispatcher = patterns('', url_get('^ticket_variables', 'ticket_variables') )), url('^/config/', patterns('ajax.config.php:ConfigAjaxAPI', - url_get('^ui', 'ui') + url_get('^ui', 'scp_ui') )), url_get('^/users$', array('ajax.users.php:UsersAjaxAPI', 'search')), - url_get('^/tickets$', array('ajax.tickets.php:TicketsAjaxAPI', 'search')), + url('^/tickets', patterns('ajax.tickets.php:TicketsAjaxAPI', + url_get('^/lookup', 'lookup'), + url_get('^$', 'search') + )), url('^/ticket/', patterns('ajax.tickets.php:TicketsAjaxAPI', url_get('^(?P<tid>\d+)/preview', 'previewTicket'), url_get('^(?P<tid>\d+)/lock', 'acquireLock'), diff --git a/scp/banlist.php b/scp/banlist.php index 1ef580a5746e7666c7aebf4f72e364acb30456ea..b56d05c6d07b28b2536127abe9a5b3be6330cb69 100644 --- a/scp/banlist.php +++ b/scp/banlist.php @@ -68,7 +68,7 @@ if($_POST && !$errors && $filter){ }else{ $count=count($_POST['ids']); if($_POST['enable']){ - $sql='UPDATE '.EMAIL_FILTER_RULE_TABLE.' SET isactive=1 WHERE filter_id='.db_input($filter->getID()). + $sql='UPDATE '.EMAIL_FILTER_RULE_TABLE.' SET isactive=1 WHERE filter_id='.db_input($filter->getId()). ' AND id IN ('.implode(',',$_POST['ids']).')'; if(db_query($sql) && ($num=db_affected_rows())){ if($num==$count) @@ -79,7 +79,7 @@ if($_POST && !$errors && $filter){ $errors['err']='Unable to enable selected emails'; } }elseif($_POST['disable']){ - $sql='UPDATE '.EMAIL_FILTER_RULE_TABLE.' SET isactive=0 WHERE filter_id='.db_input($filter->getID()). + $sql='UPDATE '.EMAIL_FILTER_RULE_TABLE.' SET isactive=0 WHERE filter_id='.db_input($filter->getId()). ' AND id IN ('.implode(',',$_POST['ids']).')'; if(db_query($sql) && ($num=db_affected_rows())) { if($num==$count) diff --git a/scp/css/scp.css b/scp/css/scp.css index 0cebe40955eafd0d6cd36ab9d471dc2f6243afcc..c5eb222ba8bb06f9111b068fffb23cd7a9cb17c3 100644 --- a/scp/css/scp.css +++ b/scp/css/scp.css @@ -1,1309 +1,1308 @@ -body { - background:#eee; - font-family:arial, helvetica, sans-serif; - font-size:10pt; - color:#000; - margin:0; - padding:0; -} - -a { - color:#E65524; - text-decoration:none; -} - -.centered { - text-align:center; -} - -.clear { - clear:both; -} - -.faded { - color:#666; -} - -.strike { text-decoration:line-through; color:red; } - -#canned_attachments label { padding:3px; padding-right:10px; } - - -#breadcrumbs { - color: #333; - margin-bottom: 15px; -} - -#breadcrumbs a { - color: #555; -} - -#msg_notice { margin: 0; padding: 5px 10px 5px 36px; height: 16px; line-height: 16px; margin-bottom: 10px; border: 1px solid #0a0; background: url('../images/icons/ok.png?1300763726') 10px 50% no-repeat #e0ffe0; } - -#msg_warning { margin: 0; padding: 5px 10px 5px 36px; height: 16px; line-height: 16px; margin-bottom: 10px; border: 1px solid #f26522; background: url('../images/icons/alert.png?1307823786') 10px 50% no-repeat #ffffdd; } - -#msg_error { margin: 0; padding: 5px 10px 5px 36px; height: 16px; line-height: 16px; margin-bottom: 10px; border: 1px solid #a00; background: url('../images/icons/error.png') 10px 50% no-repeat #fff0f0; } - - -#container { - width:960px; - margin:0 auto 20px auto; -} - -#header { - height:76px; - background:url(../images/header-bg.png) top left repeat-x; - border-left:1px solid #aaa; - border-right:1px solid #aaa; -} - -#logo { - display:block; - float:left; - width:190px; - height:76px; - text-decoration:none; - outline:none; - text-indent:-9999px; - background:url(../images/ost-logo.png) top left no-repeat; -} - -#header p { - display:block; - width:430px; - float:right; - margin:10px; - background:#eee; - border:1px solid #ccc; - padding:8px; - text-align:center; -} - -#nav, #sub_nav { - clear:both; - margin:0; - padding:0 20px; - height:26px; - line-height:26px; - border-left:1px solid #aaa; - border-right:1px solid #aaa; -} - -#nav .active, #sub_nav li { - margin:0; - padding:0; - list-style:none; - display:inline; -} - -#nav { - background:#eee; - padding-top:4px; - z-index:200; - border-top:1px solid #ddd; - border-bottom:1px solid #c5d9ec; -} - -#nav .active a, #nav .inactive { - display:block; - float:left; - width:115px; - height:26px; - color:#555; - text-align:center; - font-weight:bold; - margin-top:1px; - margin-right:5px; - position:relative; -} - -#nav .inactive a { - color:#555; - display:block; -} - -#nav .active a { - background:url(../images/tab-bg.png) top left no-repeat; - color:#004a80; -} - -#nav .inactive ul { - display:none; - width:230px; - background:#fbfbfb; - margin:0; - padding:0; - position:relative; - z-index:500; - border-bottom:1px solid #ccc; - border-left:1px solid #ccc; - border-right:1px solid #ccc; -} - -#nav .inactive li { - display:block; - margin:0; - padding:0 5px; - list-style:none; - text-align:left; -} - -#nav .inactive:hover { - background:url(../images/tab-bg.png) bottom left no-repeat; -} - -#nav .inactive:hover ul { - display:block; - -moz-box-shadow: 3px 3px 3px #ccc; - -webkit-box-shadow: 3px 3px 3px #ccc; - box-shadow: 3px 3px 3px #ccc; -} - -.ieshadow { - width:230px; - background:#000; - filter: progid:DXImageTransform.Microsoft.Blur(PixelRadius=3,MakeShadow=true,ShadowOpacity=0.30); - -ms-filter: "progid:DXImageTransform.Microsoft.Blur(PixelRadius=3,MakeShadow=true,ShadowOpacity=0.30)"; - zoom: 1; - z-index:300; - position:absolute; - top:24px; - left:0; -} - -#nav .inactive li { - background:#fbfbfb; -} - -#nav .inactive li a { - padding-left:24px; - background-position:0 50%; - background-repeat:no-repeat; - font-weight:normal; - background-color:#fbfbfb; -} - -#nav .inactive li a:hover { - color:#E65524; -} - -#sub_nav { - background:#f7f7f7; - border-bottom:1px solid #bebebe; -} - -#sub_nav a { - display:block; - float:left; - margin-right:10px; - padding:0 10px 0 21px; - background-position:0 50%; - background-repeat:no-repeat; - color:#000; -} - -#sub_nav a:hover { - color:#E65524; -} - -#sub_nav a.active { - font-weight:bold; -} - -#sub_nav .open { background-image:url(../images/icons/open.gif) } -#sub_nav .answered { background-image:url(../images/icons/answered.gif) } -#sub_nav .mine { background-image:url(../images/icons/mine.gif) } -#sub_nav .closed { background-image:url(../images/icons/closed.gif) } -#sub_nav .new { background-image:url(../images/icons/new.gif) } - -a.test { background-image:url(../images/icons/open.gif) } - -a.Ticket { background:url(../images/icons/open_tickets.gif) } -a.assignedTickets { background:url(../images/icons/assigned_tickets.gif) } -a.overdueTickets { background:url(../images/icons/overdue_tickets.gif) } -a.answeredTickets { background:url(../images/icons/answered_tickets.gif) } -a.closedTickets { background:url(../images/icons/closed_tickets.gif) } -a.newTicket { background:url(../images/icons/new_ticket.gif) } - -a.premade { background:url(../images/icons/premade_reply.gif) } -a.newPremade { background:url(../images/icons/new_premade_reply.gif) } - -a.kb { background:url(../images/icons/kb.gif) } -a.kb-categories { background:url(../images/icons/kb-categories.gif) } -a.canned { background:url(../images/icons/canned.gif) } - -a.staff { background:url(../images/icons/list_groups.gif) } -a.user { background:url(../images/icons/list_users.gif) } -a.userPref { background:url(../images/icons/user_preferences.gif) } -a.userPasswd { background:url(../images/icons/change_password.gif) } - -a.preferences { background:url(../images/icons/settings.gif) } -a.attachment { background:url(../images/icons/attachment.gif ) } -a.api { background:url(../images/icons/api.png) } -a.newapi { background:url(../images/icons/new_api.png) } - -a.sla { background:url(../images/icons/slas.png) } -a.newsla { background:url(../images/icons/new_sla.png) } - -a.logs { background:url(../images/icons/logs.gif) } - -a.emails { background:url(../images/icons/emails.png) } -a.newEmail { background:url(../images/icons/new_email.png) } - -a.emailTemplates { background:url(../images/icons/email_templates.png) } -a.newEmailTemplate { background:url(../images/icons/new_email_template.png) } - -a.emailFilters { background:url(../images/icons/email_filters.png) } -a.newEmailFilter { background:url(../images/icons/new_email_filter.png) } - -a.emailSettings { background:url(../images/icons/emails.png) } -a.emailDiagnostic { background:url(../images/icons/email_diagnostic.gif) } -a.banList { background:url(../images/icons/ban_list.gif) } - -a.users { background:url(../images/icons/list_users.gif) } -a.newuser { background:url(../images/icons/new_user.gif) } -a.groups { background:url(../images/icons/list_groups.gif) } -a.teams { background:url(../images/icons/teams.gif) } -a.newgroup { background:url(../images/icons/new_group.gif) } - -a.helpTopics { background:url(../images/icons/help_topics.png) } -a.newHelpTopic { background:url(../images/icons/new_help_topic.png) } - -a.departments { background:url(../images/icons/list_departments.gif) } -a.newDepartment { background:url(../images/icons/new_department.gif) } - - -/* Generic CSS based Icons. use=> <tag class="Icon iconname">text</tag> */ - -.Icon { - width: auto; - padding-left:20px; - background-position: left center; - background-repeat: no-repeat; -} - - -a.Icon { background-repeat: no-repeat;} - - -a.Icon:hover { - text-decoration: underline; -} - - -.Icon.newstaff { background:url(../images/icons/new_user.gif) 0 0 no-repeat; } -.Icon.newteam { background:url(../images/icons/new_team.gif) 0 0 no-repeat; } - -.Icon.Ticket { background:url(../images/icons/ticket.gif) 0 2px no-repeat; } -.Icon.webTicket { background:url(../images/icons/ticket_source_web.gif) 0 0 no-repeat; } -.Icon.emailTicket { background:url(../images/icons/ticket_source_email.gif) 0 0 no-repeat; } -.Icon.phoneTicket { background:url(../images/icons/ticket_source_phone.gif) 0 0 no-repeat; } -.Icon.otherTicket { background:url(../images/icons/ticket_source_other.gif) 0 0 no-repeat; } -.Icon.overdueTicket { background:url(../images/icons/overdue_ticket.gif) 0 0 no-repeat; } -.Icon.assignedTicket { background:url(../images/icons/assigned_ticket.gif) 0 0 no-repeat; } -.Icon.lockedTicket { background:url(../images/icons/locked_ticket.gif) 0 0 no-repeat; } -.Icon.editTicket { background-image: url(../images/icons/edit_ticket.png); } - -.Icon.newCategory { background-image: url(../images/icons/new_category.png); } -.Icon.editCategory { background-image: url(../images/icons/edit_category.png); } -.Icon.deleteCategory { background-image: url(../images/icons/delete_category.png); } -.Icon.newFAQ { background-image: url(../images/icons/new_faq.png); } -.Icon.newReply { background-image: url(../images/icons/new_reply.png); } - -.Icon.file { background-image: url(../images/icons/file.gif); } -.Icon.refresh { background-image: url(../images/icons/refresh.gif); } -.Icon.note { - font-weight: bold; - font-size: 1em; - background-image: url(../images/icons/note.gif); -} - -.Icon.thread { - font-weight: bold; - font-size: 1em; - background-image: url(../images/icons/thread.gif); -} - - -.Icon.debugLog { background:url(../images/icons/log_debug.gif) 0 2px no-repeat; } -.Icon.alertLog { background:url(../images/icons/log_alert.gif) 0 2px no-repeat; } -.Icon.errorLog { background:url(../images/icons/log_error.gif) 0 2px no-repeat; } - - - -#content { - clear:both; - border:1px solid #aaa; - border-top:none; - border-bottom:3px solid #bbb; - padding:10px 10px 20px 10px; - background:#fff; -} - -#content a { - color:#184E81; -} - -#footer { - clear:both; - padding:10px; - text-align:center; - font-size:9pt; -} - -table { vertical-align:top; } - -table.list { - clear:both; - background:#ccc; - margin: 2px 0; - border-bottom: 1px solid #ccc; - font-family:arial, helvetica, sans-serif; - font-size:10pt; -} - -table.list caption { - text-align:left; - padding:5px; - background:#929292; - color:#fff; - font-weight:bold; -} - -table.list thead th { - background-color:#eee; - color:#000; - text-align:left; - vertical-align:top; -} - -table.list th a { - - text-decoration:none; - color:#000; -} - -table.list thead th a { padding: 3px; display: block; color: #000; background: url('../images/asc_desc.gif') 100% 50% no-repeat; } - -table.list thead th a.asc { background: url('../images/asc.gif') 100% 50% no-repeat #cfe6ff; } -table.list thead th a.desc { background: url('../images/desc.gif') 100% 50% no-repeat #cfe6ff; } -table.list tbody td { - background:#fff; - border:1px solid #fff; - padding:1px; - vertical-align:top; -} - -table.list tbody td { background: #fff; padding: 1px; padding-left:2px; vertical-align: top; } -table.list tbody tr.odd td { background-color: #f0faff; } -table.list tbody tr:hover td { background: #ffe; } -table.list tbody tr.odd:hover td { background: #ffd; } - -table.list tfoot td { - background:#eee; - padding: 2px; -} - -table.list tbody td.webticket, table.list tbody tr.row1 td.webticket { - text-indent:20px; - background:url(../images/icons/ticket_source_web.gif) 0 50% no-repeat #fff; -} - -table.list tbody td.emailticket, table.list tbody tr.row1 td.emailticket { - text-indent:20px; - background:url(../images/icons/ticket_source_email.gif) 0 50% no-repeat; -} - -table.list tbody td.phoneticket, table.list tbody tr.row1 td.phoneticket { - text-indent:20px; - background:url(../images/icons/ticket_source_phone.gif) 0 50% no-repeat; -} - -table.list tbody td.otherticket, table.list tbody tr.row1 td.otherticket { - text-indent:20px; - background:url(../images/icons/ticket_source_other.gif) 0 50% no-repeat; -} - -a.refresh { - display:block; - float:right; - width:auto; - height:16px; - line-height:16px; - padding:2px 5px 2px 2px; - background-position:2px 50%; - background-repeat:no-repeat; - padding-left:24px; - margin-left:10px; - margin-bottom: 2px; - border:1px solid #aaa; - background-image:url(../images/icons/refresh.gif); -} - -a.edit, a.print { - display:block; - float:right; - width:auto; - height:16px; - line-height:16px; - padding:2px 5px 2px 2px; - background-position:2px 50%; - background-repeat:no-repeat; - padding-left:24px; - margin-left:10px; - border:1px solid #aaa; - background-image:url(../images/icons/edit_ticket.png); -} - -a.print { - background-image:url(../images/icons/printer.gif); -} - -.btn { - padding:3px 10px; - background:url(../images/btn_bg.png) top left repeat-x #ccc; - border:1px solid #777; - color:#000; -} - -.button { padding:1px 5px; margin-right:10px; color:#777; font-weight:bold;} - -.btn_sm { - padding:2px 5px; - font-size:9pt; - background:url(../images/btn_sm_bg.png) top left repeat-x #f90; - border:1px solid #777; - color:#fff; - font-weight:bold; -} - -.btn:hover, .btn_sm:hover { - background-position: bottom left; -} - -.search label { - display:block; - line-height:25px; - height:25px; -} - -.search input[type=text] { - height:23px; - line-height:23px; - border:1px solid #aaa; - background:#fff; - padding:2px; -} - -.form_table { - margin-top:3px; - border-left:1px solid #ddd; - border-right:1px solid #ddd; -} - -.form_table td { - border-bottom:1px solid #ddd; -} - - -.form_table td.multi-line { - vertical-align:top; -} - -.form_table input[type=text], .form_table input[type=password], .form_table textarea { - background:#fff; - border:1px solid #aaa; -} - -.form_table input[type=radio], .form_table input[type=checkbox] { - position:relative; - top:3px; - margin-left:0; - padding-left:0; -} - -.form_table .required { - font-weight:bold; -} - -.form_table em { - font-weight:normal; - color:#666; -} - -.error { - color:#f00; -} - -.form_table .error input { - border:1px solid #f00; -} - -.form_table th { - text-align:left; - border:1px solid #ccc; - background:#eee; - padding:0; -} - -.form_table th h4 { - margin:0; - padding:5px; - color:#fff; - background:#929292; -} - -.form_table th em { - display:block; - padding:5px; - color:#000; -} - -.settings_table { - margin-top:2px; - border-left:1px solid #ddd; - border-right:1px solid #ddd; -} - -.settings_table td { - border-bottom:1px solid #ddd; -} - -.settings_table input[type=radio], .settings_table input[type=checkbox] { - margin-left:0; - padding-left:0; -} - -#content .settings_table th h4 a { - display:block; - color:#fff; -} - -.settings_table h4 a span { - font-size:12pt; - line-height:14px; - display:inline-block; - width:14px; - height:14px; - overflow:hidden; - text-align:center; - color:#444; - background:#ccc; - position:relative; - top:2px; -} - -h2 { - margin:0; - padding:0; - font-size:12pt; - color:#0A568E; -} - -h2 span { color:#000; } - -h3 { - margin:10px 0 0 0; - padding:5px 0; - font-size:10pt; - color:#444; -} - -.ticket_info th { - text-align:left; -} - -.ticket_info { - background:#F4FAFF; -} - -.right_align { text-align:right; } - -h2 .reload { - display:inline-block; - width:16px; - height:16px; - background:url(../images/icons/refresh.gif) top left no-repeat; - outline:none; - text-indent:-9999px; -} - -#assigned_message { - margin:10px 0; - padding:5px 5px 5px 30px; - background:url(../images/icons/assigned_ticket.gif) 5px 50% no-repeat #ffd; - border:1px solid #f90; -} - - - - -#ticket_actions { - padding:5px; - background:#eee; - border:1px solid #aaa; - border-bottom:none; - margin:0; -} - -#threads { - margin:0; - padding:5px 10px 0 10px; - border:1px solid #aaa; - background:#F4FAFF; - height:30px; -} - -#threads li { - list-style:none; - margin:0; - padding:0; - display:inline; -} - -#threads li a { - display:block; - width:auto; - float:left; - height:30px; - line-height:30px; - border-top:1px solid #F4FAFF; - padding:0 10px 0 32px; - margin-right:10px; -} - -#threads li a.active { - height:29px; - background-color:#fff; - border:1px solid #aaa; - border-bottom:none; - border-top:2px solid #ed9100; - font-weight:bold; -} - -#toggle_ticket_thread { - background:url(../images/icons/open.gif) 10px 50% no-repeat; -} - -#toggle_notes { - background:url(../images/icons/note.gif) 10px 50% no-repeat; -} - -#latest_notes { - margin:10px 0; - padding:10px; - background:#ffe; - border:1px solid #e7e765; -} - -#latest_notes h3 { - margin:0 0 10px 0; - padding:0; - font-size:11pt; -} - -#latest_notes h3 span, #latest_notes h3 a { - color:#777; - font-weight:normal; - text-decoration:none; - font-size:10pt; -} - -#latest_notes ul { - margin:0 20px; - padding:0; -} - -#latest_notes ul li { - margin:0; - padding:0 0 10px 0; - list-style:none; -} - -#latest_notes em { - color:#777; -} - -#ticket_thread table { - margin-top:10px; - border:1px solid #aaa; - border-bottom:2px solid #aaa; -} - -#ticket_notes table { - margin-top:10px; - border:1px solid #ddd; - border-bottom:2px solid #ddd; -} - -#ticket_thread table th, #ticket_notes table th { - text-align:left; - border-bottom:1px solid #aaa; - font-size:10pt; - padding:5px; -} - -#ticket_notes table th { - text-align:left; - border-bottom:1px solid #ddd; - font-size:10pt; - padding:5px; - background:#F4FAFF; -} - -#ticket_notes table th em { - font-weight:normal; - font-size:10pt; - color:#666; -} - -#ticket_thread .message th { - background:#C3D9FF; -} - -#ticket_notes .date { - font-weight:normal; - font-size:10pt; - color:#888; - text-align:right; -} - -#ticket_thread .response th { - background:#FFE0B3; -} - -#ticket_thread table td, #ticket_notes table td { - padding:5px; -} - -#ticket_notes td { - background:#f9f9f9; -} - -#ticket_thread .info, #ticket_notes .info { - padding:5px; - background:#F4FAFF; - height:16px; - line-height:16px; -} - -#ticket_notes .info { - background:#f9f9f9; -} - -#response_options { - margin-top:30px; -} - -#response_options form { - padding:0 10px; -} - -#response_options ul { - padding:4px 0 0 190px; - margin:0; - text-align:center; - height:29px; - border-bottom:1px solid #aaa; - background:#eef3f8; -} - -#response_options li { - margin:0; - padding:0; - display:inline; - list-style:none; -} - -#response_options li a { - width:130px; - font-weight:bold; - padding:5px; - height:18px; - line-height:20px; - color:#444; - display:block; - float:left; - outline:none; - position:relative; - top:0; - background:#fbfbfb; - border:1px solid #eee; - border-bottom:none; -} - -#response_options .reply_tab.tell { - color:#a00 !important; - background-image:url(../images/reminder.png); - background-position:12px 50%; - background-repeat:no-repeat; -} - -#response_options li a.active { - height:18px; - color:#184E81; - background-color:#f9f9f9; - border:1px solid #aaa; - border-top:2px solid #81a9d7; - border-bottom:none; -} - -#response_options form { - padding:10px 5px; - background:#f9f9f9; - border:1px solid #aaa; - border-top:none; -} - -#response_options table { - width:928px; -} - -#response_options td { - vertical-align:top; -} - -#response_options textarea { - width:760px !important; -} - -#response_options input[type=text], #response_options textarea { - border:1px solid #aaa; - background:#fff; -} - -.attachments .uploads div { - display:inline-block; - padding-right:20px; -} - - - -.file { - display:inline-block; - padding-left:20px; - margin-right:20px; - background:url(../images/icons/file.gif) 0 50% no-repeat; -} - -.expander { - line-height:14px; - display:inline-block; - width:12px; - height:12px; - overflow:hidden; - text-align:center; - color:#aaa; - position:relative; -} - -/** Popup Tool Tips and Content **/ - -.tip_box { - display:block; - height:30px; - position:absolute; - z-index:1000; -} - -.tip_arrow { - display:block; - position:absolute; - top:5px; - left:-11px; - width:12px; - z-index:700; -} - -.tip_content { - height:auto !important; - height:20px; - min-height:20px; - padding:10px 5px 5px 5px; - border:1px solid #666; - background:#fff; - -moz-border-radius:5px; - -webkit-border-radius:5px; - border-radius:5px; - -moz-box-shadow: 3px 3px 3px #666; - -webkit-box-shadow: 3px 3px 3px #666; - box-shadow: 3px 3px 3px #666; - z-index:500; - position:absolute; - top:0; - left:-1px; - width:auto !important; - width:300px; -} - -.tip_content hr { - - color: #ddd; - background-color: #ddd; - height: 1px; - border: 0; - padding: 0; - margin: 0.2em 0; - width: 100%; -} - -.tip_close { - position:absolute; - left:100%; - top:0; - margin-left:-12px; -} - -.tip_shadow { - display:none; - background:#000; - filter: progid:DXImageTransform.Microsoft.Blur(PixelRadius=3,MakeShadow=true,ShadowOpacity=0.60); - -ms-filter: "progid:DXImageTransform.Microsoft.Blur(PixelRadius=3,MakeShadow=true,ShadowOpacity=0.60)"; - zoom: 1; - position:absolute; - z-index:200; - top:0; - left:0; - width:auto !important; - width:310px; -} - -.tip_menu { - margin:10px 0 0 0; - padding:5px 0; - border-top:1px solid #aaa; - height:16px; - font-size:9pt; -} - -.tip_menu li { - display:inline; - list-style:none; - margin:0; - padding:0; -} - -.tip_menu li a { - display:block; - width:auto; - _width:0; - float:left; - padding:0 10px; - border-right:1px solid #ddd; - color:#666; -} - -.tip_menu li a:hover { - color:#E76C74; -} - -.tip_content form { - display:none; - line-height:24px; -} - -.tip_content select, .tip_content textarea { - width:295px; -} - -.tip_content textarea { - padding:0; - border:1px solid #aaa; - background:#fff; -} - -.tip_content form p { - margin:0; - width:auto !important; - width:295px; - text-align:right; - line-height:24px; -} - -/* Knowledgebase */ -/* Knowledgebase */ -#kb { - margin: 2px 0; - padding: 5px; - overflow: hidden; -} - -#kb li { - padding:10px 10px 10px 46px; - height:auto !important; - overflow:hidden; - margin:0; - background-image:url(../images/kb_large_folder.png), url(../images/kb_category_bg.png); - background-position:0 50%, bottom left; - background-repeat:no-repeat, repeat-x; - border-bottom:1px solid #ddd; -} - - -#kb li h4 { - padding-bottom:3px; - margin:0 0 3px 0; -} - -#kb li h4 span { - color:#666; - font-weight:normal; -} - -#kb li h4 a { - font-size: 14px; -} - -#kbSearch { - padding:10px 0; - overflow:hidden; -} - -#kbSearch div { - clear:both; - overflow:hidden; - padding-top:5px; -} - -#kbSearch #query { - margin:0; - display:inline-block; - float:left; - width:200px; - margin-right:5px; -} - -#kbSearch #cid { - margin:0; - display:inline-block; - float:left; - width:200px; - margin-right:5px; - position:relative; - top:2px; -} - -#kbSearch #topic-id { - margin:0; - display:inline-block; - float:left; - width:410px; -} - -#kbSearch #searchSubmit { - margin:0; - display:inline-block; - float:left; - position:relative; - top:2px; -} - -#faq { - clear: both; - margin: 0; - padding: 5 0 10px 5px; -} -#faq ol { - font-size: 15px; - margin-left: 0; - padding-left: 0; -} -#faq ol li { - list-style: none; - margin: 0; - padding:5px 0; - color: #999; - border-bottom:1px solid #ddd; -} - -#faq ol li a { - display: inline; - height: 16px; - font-size:13px; - line-height: 16px; - padding-left: 24px; - background: url('../images/icons/page.png') 0 50% no-repeat; -} - -#faq ol li a span { - font-weight:normal; - color:#777; -} - -#faq ol li:hover { - background-color:#e9f5ff; -} - -time { - display:inline-block; - float:right; - color:#777; -} - -.cat-desc { - padding-top:5px; - padding-bottom:25px; -} - -.cat-manage-bar { - background:#e3f5ff; - padding:5px; - border-bottom:1px solid #777; -} - -.cat-manage-bar a { - display:inline-block; - margin-right:20px; -} - -/* Advanced Ticket Search */ - -#overlay { - background:#000; - position:absolute; - display:none; - z-index:1000; -} - -#advanced-search, #advanced-search * { - box-sizing: border-box; - -moz-box-sizing: border-box; - -webkit-box-sizing: border-box; -} - -#advanced-search { - position:absolute; - padding:1em; - width:640px; - height:360px; - background:#fff; - border:1px solid #2a67ac; - display:none; - z-index:1200; -} - -#advanced-search h3 { - color:#2a67ac; - font-size:20px; - margin:0; - padding:0; - display:inline-block; -} - -#advanced-search a.close { - display:inline-block; - float:right; - font-size:16px; - color:#777; -} - -#advanced-search form { - clear:both; - padding:2em 0 1em 0; - width:100%; -} - -#advanced-search div.closed_by, #advanced-search span.spinner { - display:none; -} - -#advanced-search fieldset { - margin:0; - padding:0.25em 0; - border:none; - overflow:hidden; -} - -#advanced-search label { - width:100px; - display:inline-block; - text-align:right; - padding:10px; -} - -#advanced-search fieldset input { - border:1px solid #ccc; - background:#fff; -} - -#advanced-search fieldset select { - width:170px; - display:inline-block; -} - -#advanced-search fieldset span { - width:50px; - display:inline-block; - text-align:center; - color:#777; - font-size:0.75em; -} - -#advanced-search .query input { - width:350px; -} - -#advanced-search .date_range input { - width:175px; -} - -#advanced-search .date_range i { - display:inline-block; - margin-left:3px; - position:relative; - top:5px; - width:16px; - height:16px; - background:url(../images/cal.png) bottom left no-repeat; -} - -#advanced-search fieldset.sorting select { - width:130px; -} - -#advanced-search p { - text-align:center; -} - -#advanced-search input[type="submit"], -#advanced-search input[type="reset"], -#advanced-search input[type="button"] -{ - display:inline-block; - margin:0; - height:24px; - line-height:24px; - font-weight:bold; - border:1px solid #666666; - padding:0 10px; - background: url('../images/grey_btn_bg.png?1312910883') top left repeat-x; - color: #333; -} - -#advanced-search input[type="reset"], #advanced-search input[type="button"] { - opacity:0.7; -} - -#advanced-search input[type=submit]:hover, #advanced-search input[type=submit]:active, -#advanced-search input[type=reset]:hover, #advanced-search input[type=reset]:active { - background-position:bottom left; -} - -#result-count div { - padding:5px 10px; - text-align:left; - font-weight:bold; - width:100%; - margin:0 auto; -} - -#result-count .success { - background:#e3ffd8; - border:1px solid #0a0; -} - -#result-count .fail { - background:#ffd8d8; - border:1px solid #a00; -} - +body { + background:#eee; + font-family:arial, helvetica, sans-serif; + font-size:10pt; + color:#000; + margin:0; + padding:0; +} + +a { + color:#E65524; + text-decoration:none; +} + +.centered { + text-align:center; +} + +.clear { + clear:both; +} + +.faded { + color:#666; +} + +.strike { text-decoration:line-through; color:red; } + +#canned_attachments label { padding:3px; padding-right:10px; } + + +#breadcrumbs { + color: #333; + margin-bottom: 15px; +} + +#breadcrumbs a { + color: #555; +} + +#msg_notice { margin: 0; padding: 5px 10px 5px 36px; height: 16px; line-height: 16px; margin-bottom: 10px; border: 1px solid #0a0; background: url('../images/icons/ok.png?1300763726') 10px 50% no-repeat #e0ffe0; } + +#msg_warning { margin: 0; padding: 5px 10px 5px 36px; height: 16px; line-height: 16px; margin-bottom: 10px; border: 1px solid #f26522; background: url('../images/icons/alert.png?1307823786') 10px 50% no-repeat #ffffdd; } + +#msg_error { margin: 0; padding: 5px 10px 5px 36px; height: 16px; line-height: 16px; margin-bottom: 10px; border: 1px solid #a00; background: url('../images/icons/error.png') 10px 50% no-repeat #fff0f0; } + + +#container { + width:960px; + margin:0 auto 20px auto; +} + +#header { + height:76px; + background:url(../images/header-bg.png) top left repeat-x; + border-left:1px solid #aaa; + border-right:1px solid #aaa; +} + +#logo { + display:block; + float:left; + width:190px; + height:76px; + text-decoration:none; + outline:none; + text-indent:-9999px; + background:url(../images/ost-logo.png) top left no-repeat; +} + +#header p { + display:block; + width:430px; + float:right; + margin:10px; + background:#eee; + border:1px solid #ccc; + padding:8px; + text-align:center; +} + +#nav, #sub_nav { + clear:both; + margin:0; + padding:0 20px; + height:26px; + line-height:26px; + border-left:1px solid #aaa; + border-right:1px solid #aaa; +} + +#nav .active, #sub_nav li { + margin:0; + padding:0; + list-style:none; + display:inline; +} + +#nav { + background:#eee; + padding-top:4px; + z-index:200; + border-top:1px solid #ddd; + border-bottom:1px solid #c5d9ec; +} + +#nav .active a, #nav .inactive { + display:block; + float:left; + width:115px; + height:26px; + color:#555; + text-align:center; + font-weight:bold; + margin-top:1px; + margin-right:5px; + position:relative; +} + +#nav .inactive a { + color:#555; + display:block; +} + +#nav .active a { + background:url(../images/tab-bg.png) top left no-repeat; + color:#004a80; +} + +#nav .inactive ul { + display:none; + width:230px; + background:#fbfbfb; + margin:0; + padding:0; + position:relative; + z-index:500; + border-bottom:1px solid #ccc; + border-left:1px solid #ccc; + border-right:1px solid #ccc; +} + +#nav .inactive li { + display:block; + margin:0; + padding:0 5px; + list-style:none; + text-align:left; +} + +#nav .inactive:hover { + background:url(../images/tab-bg.png) bottom left no-repeat; +} + +#nav .inactive:hover ul { + display:block; + -moz-box-shadow: 3px 3px 3px #ccc; + -webkit-box-shadow: 3px 3px 3px #ccc; + box-shadow: 3px 3px 3px #ccc; +} + +.ieshadow { + width:230px; + background:#000; + filter: progid:DXImageTransform.Microsoft.Blur(PixelRadius=3,MakeShadow=true,ShadowOpacity=0.30); + -ms-filter: "progid:DXImageTransform.Microsoft.Blur(PixelRadius=3,MakeShadow=true,ShadowOpacity=0.30)"; + zoom: 1; + z-index:300; + position:absolute; + top:24px; + left:0; +} + +#nav .inactive li { + background:#fbfbfb; +} + +#nav .inactive li a { + padding-left:24px; + background-position:0 50%; + background-repeat:no-repeat; + font-weight:normal; + background-color:#fbfbfb; +} + +#nav .inactive li a:hover { + color:#E65524; +} + +#sub_nav { + background:#f7f7f7; + border-bottom:1px solid #bebebe; +} + +#sub_nav a { + display:block; + float:left; + margin-right:10px; + padding:0 10px 0 21px; + background-position:0 50%; + background-repeat:no-repeat; + color:#000; +} + +#sub_nav a:hover { + color:#E65524; +} + +#sub_nav a.active { + font-weight:bold; +} + +#sub_nav .open { background-image:url(../images/icons/open.gif) } +#sub_nav .answered { background-image:url(../images/icons/answered.gif) } +#sub_nav .mine { background-image:url(../images/icons/mine.gif) } +#sub_nav .closed { background-image:url(../images/icons/closed.gif) } +#sub_nav .new { background-image:url(../images/icons/new.gif) } + +a.test { background-image:url(../images/icons/open.gif) } + +a.Ticket { background:url(../images/icons/open_tickets.gif) } +a.assignedTickets { background:url(../images/icons/assigned_tickets.gif) } +a.overdueTickets { background:url(../images/icons/overdue_tickets.gif) } +a.answeredTickets { background:url(../images/icons/answered_tickets.gif) } +a.closedTickets { background:url(../images/icons/closed_tickets.gif) } +a.newTicket { background:url(../images/icons/new_ticket.gif) } + +a.premade { background:url(../images/icons/premade_reply.gif) } +a.newPremade { background:url(../images/icons/new_premade_reply.gif) } + +a.kb { background:url(../images/icons/kb.gif) } +a.kb-categories { background:url(../images/icons/kb-categories.gif) } +a.canned { background:url(../images/icons/canned.gif) } + +a.staff { background:url(../images/icons/list_groups.gif) } +a.user { background:url(../images/icons/list_users.gif) } +a.userPref { background:url(../images/icons/user_preferences.gif) } +a.userPasswd { background:url(../images/icons/change_password.gif) } + +a.preferences { background:url(../images/icons/settings.gif) } +a.attachment { background:url(../images/icons/attachment.gif ) } +a.api { background:url(../images/icons/api.png) } +a.newapi { background:url(../images/icons/new_api.png) } + +a.sla { background:url(../images/icons/slas.png) } +a.newsla { background:url(../images/icons/new_sla.png) } + +a.logs { background:url(../images/icons/logs.gif) } + +a.emails { background:url(../images/icons/emails.png) } +a.newEmail { background:url(../images/icons/new_email.png) } + +a.emailTemplates { background:url(../images/icons/email_templates.png) } +a.newEmailTemplate { background:url(../images/icons/new_email_template.png) } + +a.emailFilters { background:url(../images/icons/email_filters.png) } +a.newEmailFilter { background:url(../images/icons/new_email_filter.png) } + +a.emailSettings { background:url(../images/icons/emails.png) } +a.emailDiagnostic { background:url(../images/icons/email_diagnostic.gif) } +a.banList { background:url(../images/icons/ban_list.gif) } + +a.users { background:url(../images/icons/list_users.gif) } +a.newuser { background:url(../images/icons/new_user.gif) } +a.groups { background:url(../images/icons/list_groups.gif) } +a.teams { background:url(../images/icons/teams.gif) } +a.newgroup { background:url(../images/icons/new_group.gif) } + +a.helpTopics { background:url(../images/icons/help_topics.png) } +a.newHelpTopic { background:url(../images/icons/new_help_topic.png) } + +a.departments { background:url(../images/icons/list_departments.gif) } +a.newDepartment { background:url(../images/icons/new_department.gif) } + + +/* Generic CSS based Icons. use=> <tag class="Icon iconname">text</tag> */ + +.Icon { + width: auto; + padding-left:20px; + background-position: left center; + background-repeat: no-repeat; +} + + +a.Icon { background-repeat: no-repeat;} + + +a.Icon:hover { + text-decoration: underline; +} + + +.Icon.newstaff { background:url(../images/icons/new_user.gif) 0 0 no-repeat; } +.Icon.newteam { background:url(../images/icons/new_team.gif) 0 0 no-repeat; } + +.Icon.Ticket { background:url(../images/icons/ticket.gif) 0 2px no-repeat; } +.Icon.webTicket { background:url(../images/icons/ticket_source_web.gif) 0 0 no-repeat; } +.Icon.emailTicket { background:url(../images/icons/ticket_source_email.gif) 0 0 no-repeat; } +.Icon.phoneTicket { background:url(../images/icons/ticket_source_phone.gif) 0 0 no-repeat; } +.Icon.otherTicket { background:url(../images/icons/ticket_source_other.gif) 0 0 no-repeat; } +.Icon.overdueTicket { background:url(../images/icons/overdue_ticket.gif) 0 0 no-repeat; } +.Icon.assignedTicket { background:url(../images/icons/assigned_ticket.gif) 0 0 no-repeat; } +.Icon.lockedTicket { background:url(../images/icons/locked_ticket.gif) 0 0 no-repeat; } +.Icon.editTicket { background-image: url(../images/icons/edit_ticket.png); } + +.Icon.newCategory { background-image: url(../images/icons/new_category.png); } +.Icon.editCategory { background-image: url(../images/icons/edit_category.png); } +.Icon.deleteCategory { background-image: url(../images/icons/delete_category.png); } +.Icon.newFAQ { background-image: url(../images/icons/new_faq.png); } +.Icon.newReply { background-image: url(../images/icons/new_reply.png); } + +.Icon.file { background-image: url(../images/icons/file.gif); } +.Icon.refresh { background-image: url(../images/icons/refresh.gif); } +.Icon.note { + font-weight: bold; + font-size: 1em; + background-image: url(../images/icons/note.gif); +} + +.Icon.thread { + font-weight: bold; + font-size: 1em; + background-image: url(../images/icons/thread.gif); +} + + +.Icon.debugLog { background:url(../images/icons/log_debug.gif) 0 2px no-repeat; } +.Icon.alertLog { background:url(../images/icons/log_alert.gif) 0 2px no-repeat; } +.Icon.errorLog { background:url(../images/icons/log_error.gif) 0 2px no-repeat; } + + + +#content { + clear:both; + border:1px solid #aaa; + border-top:none; + border-bottom:3px solid #bbb; + padding:10px 10px 20px 10px; + background:#fff; +} + +#content a { + color:#184E81; +} + +#footer { + clear:both; + padding:10px; + text-align:center; + font-size:9pt; +} + +table { vertical-align:top; } + +table.list { + clear:both; + background:#ccc; + margin: 2px 0; + border-bottom: 1px solid #ccc; + font-family:arial, helvetica, sans-serif; + font-size:10pt; +} + +table.list caption { + text-align:left; + padding:5px; + background:#929292; + color:#fff; + font-weight:bold; +} + +table.list thead th { + background-color:#eee; + color:#000; + text-align:left; + vertical-align:top; +} + +table.list th a { + + text-decoration:none; + color:#000; +} + +table.list thead th a { padding: 3px; display: block; color: #000; background: url('../images/asc_desc.gif') 100% 50% no-repeat; } + +table.list thead th a.asc { background: url('../images/asc.gif') 100% 50% no-repeat #cfe6ff; } +table.list thead th a.desc { background: url('../images/desc.gif') 100% 50% no-repeat #cfe6ff; } +table.list tbody td { + background:#fff; + border:1px solid #fff; + padding:1px; + vertical-align:top; +} + +table.list tbody td { background: #fff; padding: 1px; padding-left:2px; vertical-align: top; } +table.list tbody tr.odd td { background-color: #f0faff; } +table.list tbody tr:hover td { background: #ffe; } +table.list tbody tr.odd:hover td { background: #ffd; } + +table.list tfoot td { + background:#eee; + padding: 2px; +} + +table.list tbody td.webticket, table.list tbody tr.row1 td.webticket { + text-indent:20px; + background:url(../images/icons/ticket_source_web.gif) 0 50% no-repeat #fff; +} + +table.list tbody td.emailticket, table.list tbody tr.row1 td.emailticket { + text-indent:20px; + background:url(../images/icons/ticket_source_email.gif) 0 50% no-repeat; +} + +table.list tbody td.phoneticket, table.list tbody tr.row1 td.phoneticket { + text-indent:20px; + background:url(../images/icons/ticket_source_phone.gif) 0 50% no-repeat; +} + +table.list tbody td.otherticket, table.list tbody tr.row1 td.otherticket { + text-indent:20px; + background:url(../images/icons/ticket_source_other.gif) 0 50% no-repeat; +} + +a.refresh { + display:block; + float:right; + width:auto; + height:16px; + line-height:16px; + padding:2px 5px 2px 2px; + background-position:2px 50%; + background-repeat:no-repeat; + padding-left:24px; + margin-left:10px; + margin-bottom: 2px; + border:1px solid #aaa; + background-image:url(../images/icons/refresh.gif); +} + +a.edit, a.print { + display:block; + float:right; + width:auto; + height:16px; + line-height:16px; + padding:2px 5px 2px 2px; + background-position:2px 50%; + background-repeat:no-repeat; + padding-left:24px; + margin-left:10px; + border:1px solid #aaa; + background-image:url(../images/icons/edit_ticket.png); +} + +a.print { + background-image:url(../images/icons/printer.gif); +} + +.btn { + padding:3px 10px; + background:url(../images/btn_bg.png) top left repeat-x #ccc; + border:1px solid #777; + color:#000; +} + +.button { padding:1px 5px; margin-right:10px; color:#777; font-weight:bold;} + +.btn_sm { + padding:2px 5px; + font-size:9pt; + background:url(../images/btn_sm_bg.png) top left repeat-x #f90; + border:1px solid #777; + color:#fff; + font-weight:bold; +} + +.btn:hover, .btn_sm:hover { + background-position: bottom left; +} + +.search label { + display:block; + line-height:25px; + height:25px; +} + +.search input[type=text] { + height:23px; + line-height:23px; + border:1px solid #aaa; + background:#fff; + padding:2px; +} + +.form_table { + margin-top:3px; + border-left:1px solid #ddd; + border-right:1px solid #ddd; +} + +.form_table td { + border-bottom:1px solid #ddd; +} + + +.form_table td.multi-line { + vertical-align:top; +} + +.form_table input[type=text], .form_table input[type=password], .form_table textarea { + background:#fff; + border:1px solid #aaa; +} + +.form_table input[type=radio], .form_table input[type=checkbox] { + position:relative; + top:3px; + margin-left:0; + padding-left:0; +} + +.form_table .required { + font-weight:bold; +} + +.form_table em { + font-weight:normal; + color:#666; +} + +.error { + color:#f00; +} + +.form_table .error input { + border:1px solid #f00; +} + +.form_table th { + text-align:left; + border:1px solid #ccc; + background:#eee; + padding:0; +} + +.form_table th h4 { + margin:0; + padding:5px; + color:#fff; + background:#929292; +} + +.form_table th em { + display:block; + padding:5px; + color:#000; +} + +.settings_table { + margin-top:2px; + border-left:1px solid #ddd; + border-right:1px solid #ddd; +} + +.settings_table td { + border-bottom:1px solid #ddd; +} + +.settings_table input[type=radio], .settings_table input[type=checkbox] { + margin-left:0; + padding-left:0; +} + +#content .settings_table th h4 a { + display:block; + color:#fff; +} + +.settings_table h4 a span { + font-size:12pt; + line-height:14px; + display:inline-block; + width:14px; + height:14px; + overflow:hidden; + text-align:center; + color:#444; + background:#ccc; + position:relative; + top:2px; +} + +h2 { + margin:0; + padding:0; + font-size:12pt; + color:#0A568E; +} + +h2 span { color:#000; } + +h3 { + margin:10px 0 0 0; + padding:5px 0; + font-size:10pt; + color:#444; +} + +.ticket_info th { + text-align:left; +} + +.ticket_info { + background:#F4FAFF; +} + +.right_align { text-align:right; } + +h2 .reload { + display:inline-block; + width:16px; + height:16px; + background:url(../images/icons/refresh.gif) top left no-repeat; + outline:none; + text-indent:-9999px; +} + +#assigned_message { + margin:10px 0; + padding:5px 5px 5px 30px; + background:url(../images/icons/assigned_ticket.gif) 5px 50% no-repeat #ffd; + border:1px solid #f90; +} + + + + +#ticket_actions { + padding:5px; + background:#eee; + border:1px solid #aaa; + border-bottom:none; + margin:0; +} + +#threads { + margin:0; + padding:5px 10px 0 10px; + border:1px solid #aaa; + background:#F4FAFF; + height:30px; +} + +#threads li { + list-style:none; + margin:0; + padding:0; + display:inline; +} + +#threads li a { + display:block; + width:auto; + float:left; + height:30px; + line-height:30px; + border-top:1px solid #F4FAFF; + padding:0 10px 0 32px; + margin-right:10px; +} + +#threads li a.active { + height:29px; + background-color:#fff; + border:1px solid #aaa; + border-bottom:none; + border-top:2px solid #ed9100; + font-weight:bold; +} + +#toggle_ticket_thread { + background:url(../images/icons/open.gif) 10px 50% no-repeat; +} + +#toggle_notes { + background:url(../images/icons/note.gif) 10px 50% no-repeat; +} + +#latest_notes { + margin:10px 0; + padding:10px; + background:#ffe; + border:1px solid #e7e765; +} + +#latest_notes h3 { + margin:0 0 10px 0; + padding:0; + font-size:11pt; +} + +#latest_notes h3 span, #latest_notes h3 a { + color:#777; + font-weight:normal; + text-decoration:none; + font-size:10pt; +} + +#latest_notes ul { + margin:0 20px; + padding:0; +} + +#latest_notes ul li { + margin:0; + padding:0 0 10px 0; + list-style:none; +} + +#latest_notes em { + color:#777; +} + +#ticket_thread table { + margin-top:10px; + border:1px solid #aaa; + border-bottom:2px solid #aaa; +} + +#ticket_notes table { + margin-top:10px; + border:1px solid #ddd; + border-bottom:2px solid #ddd; +} + +#ticket_thread table th, #ticket_notes table th { + text-align:left; + border-bottom:1px solid #aaa; + font-size:10pt; + padding:5px; +} + +#ticket_notes table th { + text-align:left; + border-bottom:1px solid #ddd; + font-size:10pt; + padding:5px; + background:#F4FAFF; +} + +#ticket_notes table th em { + font-weight:normal; + font-size:10pt; + color:#666; +} + +#ticket_thread .message th { + background:#C3D9FF; +} + +#ticket_notes .date { + font-weight:normal; + font-size:10pt; + color:#888; + text-align:right; +} + +#ticket_thread .response th { + background:#FFE0B3; +} + +#ticket_thread table td, #ticket_notes table td { + padding:5px; +} + +#ticket_notes td { + background:#f9f9f9; +} + +#ticket_thread .info, #ticket_notes .info { + padding:5px; + background:#F4FAFF; + height:16px; + line-height:16px; +} + +#ticket_notes .info { + background:#f9f9f9; +} + +#response_options { + margin-top:30px; +} + +#response_options form { + padding:0 10px; +} + +#response_options ul { + padding:4px 0 0 190px; + margin:0; + text-align:center; + height:29px; + border-bottom:1px solid #aaa; + background:#eef3f8; +} + +#response_options li { + margin:0; + padding:0; + display:inline; + list-style:none; +} + +#response_options li a { + width:130px; + font-weight:bold; + padding:5px; + height:18px; + line-height:20px; + color:#444; + display:block; + float:left; + outline:none; + position:relative; + top:0; + background:#fbfbfb; + border:1px solid #eee; + border-bottom:none; +} + +#response_options .reply_tab.tell { + color:#a00 !important; + background-image:url(../images/reminder.png); + background-position:12px 50%; + background-repeat:no-repeat; +} + +#response_options li a.active { + height:18px; + color:#184E81; + background-color:#f9f9f9; + border:1px solid #aaa; + border-top:2px solid #81a9d7; + border-bottom:none; +} + +#response_options form { + padding:10px 5px; + background:#f9f9f9; + border:1px solid #aaa; + border-top:none; +} + +#response_options table { + width:928px; +} + +#response_options td { + vertical-align:top; +} + +#response_options textarea { + width:760px !important; +} + +#response_options input[type=text], #response_options textarea { + border:1px solid #aaa; + background:#fff; +} + +.attachments .uploads div { + display:inline-block; + padding-right:20px; +} + + + +.file { + display:inline-block; + padding-left:20px; + margin-right:20px; + background:url(../images/icons/file.gif) 0 50% no-repeat; +} + +.expander { + line-height:14px; + display:inline-block; + width:12px; + height:12px; + overflow:hidden; + text-align:center; + color:#aaa; + position:relative; +} + +/** Popup Tool Tips and Content **/ + +.tip_box { + display:block; + height:30px; + position:absolute; + z-index:1000; +} + +.tip_arrow { + display:block; + position:absolute; + top:5px; + left:-11px; + width:12px; + z-index:700; +} + +.tip_content { + height:auto !important; + height:20px; + min-height:20px; + padding:10px 5px 5px 5px; + border:1px solid #666; + background:#fff; + -moz-border-radius:5px; + -webkit-border-radius:5px; + border-radius:5px; + -moz-box-shadow: 3px 3px 3px #666; + -webkit-box-shadow: 3px 3px 3px #666; + box-shadow: 3px 3px 3px #666; + z-index:500; + position:absolute; + top:0; + left:-1px; + width:auto !important; + width:300px; +} + +.tip_content hr { + + color: #ddd; + background-color: #ddd; + height: 1px; + border: 0; + padding: 0; + margin: 0.2em 0; + width: 100%; +} + +.tip_close { + position:absolute; + left:100%; + top:0; + margin-left:-12px; +} + +.tip_shadow { + display:none; + background:#000; + filter: progid:DXImageTransform.Microsoft.Blur(PixelRadius=3,MakeShadow=true,ShadowOpacity=0.60); + -ms-filter: "progid:DXImageTransform.Microsoft.Blur(PixelRadius=3,MakeShadow=true,ShadowOpacity=0.60)"; + zoom: 1; + position:absolute; + z-index:200; + top:0; + left:0; + width:auto !important; + width:310px; +} + +.tip_menu { + margin:10px 0 0 0; + padding:5px 0; + border-top:1px solid #aaa; + height:16px; + font-size:9pt; +} + +.tip_menu li { + display:inline; + list-style:none; + margin:0; + padding:0; +} + +.tip_menu li a { + display:block; + width:auto; + _width:0; + float:left; + padding:0 10px; + border-right:1px solid #ddd; + color:#666; +} + +.tip_menu li a:hover { + color:#E76C74; +} + +.tip_content form { + display:none; + line-height:24px; +} + +.tip_content select, .tip_content textarea { + width:295px; +} + +.tip_content textarea { + padding:0; + border:1px solid #aaa; + background:#fff; +} + +.tip_content form p { + margin:0; + width:auto !important; + width:295px; + text-align:right; + line-height:24px; +} + +/* Knowledgebase */ +/* Knowledgebase */ +#kb { + margin: 2px 0; + padding: 5px; + overflow: hidden; +} + +#kb li { + padding:10px 10px 10px 46px; + height:auto !important; + overflow:hidden; + margin:0; + background-image:url(../images/kb_large_folder.png), url(../images/kb_category_bg.png); + background-position:0 50%, bottom left; + background-repeat:no-repeat, repeat-x; + border-bottom:1px solid #ddd; +} + + +#kb li h4 { + padding-bottom:3px; + margin:0 0 3px 0; +} + +#kb li h4 span { + color:#666; + font-weight:normal; +} + +#kb li h4 a { + font-size: 14px; +} + +#kbSearch { + padding:10px 0; + overflow:hidden; +} + +#kbSearch div { + clear:both; + overflow:hidden; + padding-top:5px; +} + +#kbSearch #query { + margin:0; + display:inline-block; + float:left; + width:200px; + margin-right:5px; +} + +#kbSearch #cid { + margin:0; + display:inline-block; + float:left; + width:200px; + margin-right:5px; + position:relative; + top:2px; +} + +#kbSearch #topic-id { + margin:0; + display:inline-block; + float:left; + width:410px; +} + +#kbSearch #searchSubmit { + margin:0; + display:inline-block; + float:left; + position:relative; + top:2px; +} + +#faq { + clear: both; + margin: 0; + padding: 5 0 10px 5px; +} +#faq ol { + font-size: 15px; + margin-left: 0; + padding-left: 0; +} +#faq ol li { + list-style: none; + margin: 0; + padding:5px 0; + color: #999; + border-bottom:1px solid #ddd; +} + +#faq ol li a { + display: inline; + height: 16px; + font-size:13px; + line-height: 16px; + padding-left: 24px; + background: url('../images/icons/page.png') 0 50% no-repeat; +} + +#faq ol li a span { + font-weight:normal; + color:#777; +} + +#faq ol li:hover { + background-color:#e9f5ff; +} + +time { + display:inline-block; + float:right; + color:#777; +} + +.cat-desc { + padding-top:5px; + padding-bottom:25px; +} + +.cat-manage-bar { + background:#e3f5ff; + padding:5px; + border-bottom:1px solid #777; +} + +.cat-manage-bar a { + display:inline-block; + margin-right:20px; +} + +/* Advanced Ticket Search */ + +#overlay { + background:#000; + position:absolute; + display:none; + z-index:1000; +} + +#advanced-search, #advanced-search * { + box-sizing: border-box; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; +} + +#advanced-search { + position:absolute; + padding:1em; + width:640px; + height:360px; + background:#fff; + border:1px solid #2a67ac; + display:none; + z-index:1200; +} + +#advanced-search h3 { + color:#2a67ac; + font-size:20px; + margin:0; + padding:0; + display:inline-block; +} + +#advanced-search a.close { + display:inline-block; + float:right; + font-size:16px; + color:#777; +} + +#advanced-search form { + clear:both; + padding:2em 0 1em 0; + width:100%; +} + +#advanced-search div.closed_by, #advanced-search span.spinner { + display:none; +} + +#advanced-search fieldset { + margin:0; + padding:0.25em 0; + border:none; + overflow:hidden; +} + +#advanced-search label { + width:100px; + display:inline-block; + text-align:right; + padding:10px; +} + +#advanced-search fieldset input { + border:1px solid #ccc; + background:#fff; +} + +#advanced-search fieldset select { + width:170px; + display:inline-block; +} + +#advanced-search fieldset span { + width:50px; + display:inline-block; + text-align:center; + color:#777; + font-size:0.75em; +} + +#advanced-search .query input { + width:350px; +} + +#advanced-search .date_range input { + width:175px; +} + +#advanced-search .date_range i { + display:inline-block; + margin-left:3px; + position:relative; + top:5px; + width:16px; + height:16px; + background:url(../images/cal.png) bottom left no-repeat; +} + +#advanced-search fieldset.sorting select { + width:130px; +} + +#advanced-search p { + text-align:center; +} + +#advanced-search input[type="submit"], +#advanced-search input[type="reset"], +#advanced-search input[type="button"] +{ + display:inline-block; + margin:0; + height:24px; + line-height:24px; + font-weight:bold; + border:1px solid #666666; + padding:0 10px; + background: url('../images/grey_btn_bg.png?1312910883') top left repeat-x; + color: #333; +} + +#advanced-search input[type="reset"], #advanced-search input[type="button"] { + opacity:0.7; +} + +#advanced-search input[type=submit]:hover, #advanced-search input[type=submit]:active, +#advanced-search input[type=reset]:hover, #advanced-search input[type=reset]:active { + background-position:bottom left; +} + +#result-count div { + padding:5px 10px; + text-align:left; + font-weight:bold; + width:100%; + margin:0 auto; +} + +#result-count .success { + background:#e3ffd8; + border:1px solid #0a0; +} + +#result-count .fail { + background:#ffd8d8; + border:1px solid #a00; +} diff --git a/scp/images/ajax-loader.gif b/scp/images/ajax-loader.gif new file mode 100644 index 0000000000000000000000000000000000000000..d42f72c723644bbf8cf8d6e1b7ff0bea7ddd305a Binary files /dev/null and b/scp/images/ajax-loader.gif differ diff --git a/scp/js/scp.js b/scp/js/scp.js index 7a9e0e218d1da97b3ec4b2860f307dd1c1769d1f..56f776ed6ff4ef0a6a20a54ef3837d957a487949 100644 --- a/scp/js/scp.js +++ b/scp/js/scp.js @@ -198,11 +198,11 @@ $(document).ready(function(){ } } - /* Typeahead init */ + /* Typeahead tickets lookup */ $('#basic-ticket-search').typeahead({ source: function (typeahead, query) { $.ajax({ - url: "ajax.php/tickets?q="+query, + url: "ajax.php/tickets/lookup?q="+query, dataType: 'json', success: function (data) { typeahead.process(data); @@ -215,6 +215,7 @@ $(document).ready(function(){ property: "value" }); + /* Typeahead user lookup */ $('#email.typeahead').typeahead({ source: function (typeahead, query) { if(query.length > 2) { @@ -235,5 +236,84 @@ $(document).ready(function(){ property: "email" }); + /* advanced search */ + $("#overlay").css({ + opacity : 0.3, + top : 0, + left : 0, + width : $(window).width(), + height : $(window).height() + }); + + $("#advanced-search").css({ + top : ($(window).height() / 6), + left : ($(window).width() / 2 - 300) + }); + + $('#go-advanced').click(function(e) { + e.preventDefault(); + $('#result-count').html(''); + $('#overlay').show(); + $('#advanced-search').show(); + }); + + $('#advanced-search').delegate('a.close, input.close', 'click', function(e) { + e.preventDefault(); + $('#advanced-search').hide() + $('#overlay').hide(); + }).delegate('#status', 'change', function() { + switch($(this).val()) { + case 'closed': + $('select#assignee').find('option:first').attr('selected', 'selected').parent('select'); + $('select#assignee').attr('disabled','disabled'); + $('select#staffId').removeAttr('disabled'); + break; + case 'open': + case 'overdue': + $('select#staffId').find('option:first').attr('selected', 'selected').parent('select'); + $('select#staffId').attr('disabled','disabled'); + $('select#assignee').removeAttr('disabled'); + break; + default: + $('select#staffId').removeAttr('disabled'); + $('select#assignee').removeAttr('disabled'); + } + }); + + $('#advanced-search form#search').submit(function(e) { + e.preventDefault(); + var fObj = $(this); + var elem = $('#advanced-search'); + $('#result-count').html(''); + $.ajax({ + url: "ajax.php/tickets", + data: fObj.serialize(), + dataType: 'json', + beforeSend: function ( xhr ) { + $('.buttons', elem).hide(); + $('.spinner', elem).show(); + return true; + }, + success: function (resp) { + + if(resp.success) { + $('#result-count').html('<div class="success">' + resp.success +'</div>'); + } else if (resp.fail) { + $('#result-count').html('<div class="fail">' + resp.fail +'</div>'); + } else { + $('#result-count').html('<div class="fail">Unknown error</div>'); + } + } + }) + .done( function () { + }) + .fail( function () { + $('#result-count').html('<div class="fail">Advanced search failed - try again!</div>'); + }) + .always( function () { + $('.spinner', elem).hide(); + $('.buttons', elem).show(); + }); + }); }); diff --git a/scp/staff.inc.php b/scp/staff.inc.php index b3ee30a4ec3a555c2fd8c3c86ed6e72b2c6517ca..7a4dfb9e3a596fcc480894c60ecf2bede2304181 100644 --- a/scp/staff.inc.php +++ b/scp/staff.inc.php @@ -63,19 +63,19 @@ if(!$thisstaff || !is_object($thisstaff) || !$thisstaff->getId() || !$thisstaff- exit; } //2) if not super admin..check system status and group status -if(!$thisstaff->isadmin()){ - //Staff are not allowed to login in offline mode!! - if($cfg->isHelpDeskOffline()){ - staffLoginPage('System Offline'); - exit; - } +if(!$thisstaff->isAdmin()) { //Check for disabled staff or group! if(!$thisstaff->isactive() || !$thisstaff->isGroupActive()) { staffLoginPage('Access Denied. Contact Admin'); exit; } -} + //Staff are not allowed to login in offline mode!! + if($cfg->isHelpDeskOffline() || $cfg->isUpgradePending()) { + staffLoginPage('System Offline'); + exit; + } +} //Keep the session activity alive $thisstaff->refreshSession(); @@ -93,10 +93,9 @@ $errors=array(); $msg=$warn=$sysnotice=''; $tabs=array(); $submenu=array(); - -if(defined('THIS_VERSION') && strcasecmp($cfg->getVersion(),THIS_VERSION)) { - $errors['err']=$sysnotice=sprintf('The script is version %s while the database is version %s',THIS_VERSION,$cfg->getVersion()); -}elseif($cfg->isHelpDeskOffline()){ +if($cfg->isUpgradePending()) { + $errors['err']=$sysnotice='System upgrade is pending <a href="../setup/upgrade.php">Upgrade Now</a>'; +} elseif($cfg->isHelpDeskOffline()) { $sysnotice='<strong>System is set to offline mode</strong> - Client interface is disabled and ONLY admins can access staff control panel.'; $sysnotice.=' <a href="settings.php">Enable</a>.'; } diff --git a/scp/tickets.php b/scp/tickets.php index c881381e0d9ff9613b1e26e1df6c410157df664b..567c3f69755525aca1146ce8433a44e2485c6fc3 100644 --- a/scp/tickets.php +++ b/scp/tickets.php @@ -55,7 +55,7 @@ if($_POST && !$errors): if(!$errors['err'] && EmailFilter::isBanned($ticket->getEmail())) $errors['err']='Email is in banlist. Must be removed to reply.'; - $wasOpen =($ticket->isopen()); + $wasOpen =($ticket->isOpen()); //If no error...do the do. if(!$errors && ($respId=$ticket->postReply($_POST,$_FILES['attachments'],$errors))) { $msg='Reply posted successfully'; @@ -189,7 +189,7 @@ if($_POST && !$errors): } break; case 'close': - if(!$thisstaff->isadmin() && !$thisstaff->canCloseTickets()){ + if(!$thisstaff->isAdmin() && !$thisstaff->canCloseTickets()){ $errors['err']='Perm. Denied. You are not allowed to close tickets.'; }else{ if($ticket->close()){ @@ -204,7 +204,7 @@ if($_POST && !$errors): break; case 'reopen': //if they can close...then assume they can reopen. - if(!$thisstaff->isadmin() && !$thisstaff->canCloseTickets()){ + if(!$thisstaff->isAdmin() && !$thisstaff->canCloseTickets()){ $errors['err']='Perm. Denied. You are not allowed to reopen tickets.'; }else{ if($ticket->reopen()){ @@ -233,7 +233,7 @@ if($_POST && !$errors): break; case 'overdue': //Mark the ticket as overdue - if(!$thisstaff->isadmin() && !$thisstaff->isManager()){ + if(!$thisstaff->isAdmin() && !$thisstaff->isManager()){ $errors['err']='Perm. Denied. You are not allowed to flag tickets overdue'; }else{ if($ticket->markOverdue()){ @@ -252,7 +252,7 @@ if($_POST && !$errors): } break; case 'banemail': - if(!$thisstaff->isadmin() && !$thisstaff->canManageBanList()){ + if(!$thisstaff->isAdmin() && !$thisstaff->canBanEmails()){ $errors['err']='Perm. Denied. You are not allowed to ban emails'; }elseif(Banlist::add($ticket->getEmail(),$thisstaff->getName())){ $msg='Email ('.$ticket->getEmail().') added to banlist'; @@ -266,7 +266,7 @@ if($_POST && !$errors): } break; case 'unbanemail': - if(!$thisstaff->isadmin() && !$thisstaff->canManageBanList()){ + if(!$thisstaff->isAdmin() && !$thisstaff->canBanEmails()){ $errors['err']='Perm. Denied. You are not allowed to remove emails from banlist.'; }elseif(Banlist::remove($ticket->getEmail())){ $msg='Email removed from banlist'; @@ -275,7 +275,7 @@ if($_POST && !$errors): } break; case 'delete': // Dude what are you trying to hide? bad customer support?? - if(!$thisstaff->isadmin() && !$thisstaff->canDeleteTickets()){ + if(!$thisstaff->isAdmin() && !$thisstaff->canDeleteTickets()){ $errors['err']='Perm. Denied. You are not allowed to DELETE tickets!!'; }else{ if($ticket->delete()){ @@ -339,7 +339,7 @@ if($_POST && !$errors): $note='Ticket flagged as overdue by '.$thisstaff->getName(); foreach($_POST['tids'] as $k=>$v) { $t = new Ticket($v); - if($t && !$t->isoverdue()) + if($t && !$t->isOverdue()) if($t->markOverdue()) { $i++; $t->logActivity('Ticket Marked Overdue',$note,false,'System'); diff --git a/setup/cleanup.php b/setup/cleanup.php deleted file mode 100644 index 1309228eb6c64eaaee6f16926ec98b06d91d0221..0000000000000000000000000000000000000000 --- a/setup/cleanup.php +++ /dev/null @@ -1,24 +0,0 @@ -<?php -/********************************************************************* - cleanup.php - - Cleanup script called via ajax to migrate attachments. - - Peter Rotich <peter@osticket.com> - Copyright (c) 2006-2012 osTicket - http://www.osticket.com - - Released under the GNU General Public License WITHOUT ANY WARRANTY. - See LICENSE.TXT for details. - - vim: expandtab sw=4 ts=4 sts=4: -**********************************************************************/ -session_start(); -if($_GET['c']>10) { //When Done send 304 - nothing else to do. - $_SESSION['s']='done'; - session_write_close(); - header("HTTP/1.1 304 Not Modified"); - exit; -} -echo "Cleaning up...".time(); -?> diff --git a/setup/css/wizard.css b/setup/css/wizard.css index 6fd18e17854f65a30a2947460a955ca4c403541c..c92b05447a6acb9992ea21be3ce13581840784a9 100644 --- a/setup/css/wizard.css +++ b/setup/css/wizard.css @@ -70,7 +70,7 @@ form .row span { width: 600px; color: #666666; } #overlay { display: none; position: fixed; background: #000; z-index: 2000; } -#loading { padding: 10px 10px 10px 60px; width: 300px; height: 100px; background: url('../images/ajax-loader.gif?1312925608') 10px 50% no-repeat white; position: fixed; display: none; z-index: 3000; } +#loading { padding: 10px 10px 10px 60px; width: 400px; height: 150px; background: url('../images/ajax-loader.gif?1312925608') 10px 50% no-repeat white; position: fixed; display: none; z-index: 3000; } #loading h4 { margin: 3px 0 0 0; padding: 0; color: #d80; } .tip { display: inline-block; width: 16px; height: 16px; outline: none; text-decoration: none; color: #d80; } diff --git a/setup/inc/class.installer.php b/setup/inc/class.installer.php new file mode 100644 index 0000000000000000000000000000000000000000..75ebdc7cdef148a89fd9016e1d1eb62e278f8e39 --- /dev/null +++ b/setup/inc/class.installer.php @@ -0,0 +1,202 @@ +<?php +/********************************************************************* + class.installer.php + + osTicket Intaller - installs the latest version. + + Peter Rotich <peter@osticket.com> + Copyright (c) 2006-2012 osTicket + http://www.osticket.com + + Released under the GNU General Public License WITHOUT ANY WARRANTY. + See LICENSE.TXT for details. + + vim: expandtab sw=4 ts=4 sts=4: +**********************************************************************/ +require_once INC_DIR.'class.setup.php'; + +class Installer extends SetupWizard { + + var $config; + + function Installer($configfile) { + $this->config =$configfile; + $this->errors=array(); + } + + function getConfigFile() { + return $this->config; + } + + function config_exists() { + return ($this->getConfigFile() && file_exists($this->getConfigFile())); + } + + function config_writable() { + return ($this->getConfigFile() && is_writable($this->getConfigFile())); + } + + function check_config() { + return ($this->config_exists() && $this->config_writable()); + } + + //XXX: Latest version insall logic...no carry over. + function install($vars) { + + $this->errors=$f=array(); + + $f['name'] = array('type'=>'string', 'required'=>1, 'error'=>'Name required'); + $f['email'] = array('type'=>'email', 'required'=>1, 'error'=>'Valid email required'); + $f['fname'] = array('type'=>'string', 'required'=>1, 'error'=>'First name required'); + $f['lname'] = array('type'=>'string', 'required'=>1, 'error'=>'Last name required'); + $f['admin_email'] = array('type'=>'email', 'required'=>1, 'error'=>'Valid email required'); + $f['username'] = array('type'=>'username', 'required'=>1, 'error'=>'Username required'); + $f['passwd'] = array('type'=>'password', 'required'=>1, 'error'=>'Password required'); + $f['passwd2'] = array('type'=>'string', 'required'=>1, 'error'=>'Confirm password'); + $f['prefix'] = array('type'=>'string', 'required'=>1, 'error'=>'Table prefix required'); + $f['dbhost'] = array('type'=>'string', 'required'=>1, 'error'=>'Hostname required'); + $f['dbname'] = array('type'=>'string', 'required'=>1, 'error'=>'Database name required'); + $f['dbuser'] = array('type'=>'string', 'required'=>1, 'error'=>'Username required'); + $f['dbpass'] = array('type'=>'string', 'required'=>1, 'error'=>'password required'); + + + if(!Validator::process($f,$vars,$this->errors) && !$this->errors['err']) + $this->errors['err']='Missing or invalid data - correct the errors and try again.'; + + + //Staff's email can't be same as system emails. + if($vars['admin_email'] && $vars['email'] && !strcasecmp($vars['admin_email'],$vars['email'])) + $this->errors['admin_email']='Conflicts with system email above'; + //Admin's pass confirmation. + if(!$this->errors && strcasecmp($vars['passwd'],$vars['passwd2'])) + $this->errors['passwd2']='passwords to not match!'; + //Check table prefix underscore required at the end! + if($vars['prefix'] && substr($vars['prefix'], -1)!='_') + $this->errors['prefix']='Bad prefix. Must have underscore (_) at the end. e.g \'ost_\''; + + //Make sure admin username is not very predictable. XXX: feels dirty but necessary + if(!$this->errors['username'] && in_array(strtolower($vars['username']),array('admin','admins','username','osticket'))) + $this->errors['username']='Bad username'; + + //MYSQL: Connect to the DB and check the version & database (create database if it doesn't exist!) + if(!$this->errors) { + if(!db_connect($vars['dbhost'],$vars['dbuser'],$vars['dbpass'])) + $this->errors['db']='Unable to connect to MySQL server. Possibly invalid login info.'; + elseif(db_version()< $this->getMySQLVersion()) + $this->errors['db']=sprintf('osTicket requires MySQL %s or better!',$this->getMySQLVersion()); + elseif(!db_select_database($vars['dbname']) && !db_create_database($vars['dbname'])) { + $this->errors['dbname']='Database doesn\'t exist'; + $this->errors['db']='Unable to create the database.'; + } elseif(!db_select_database($vars['dbname'])) { + $this->errors['dbname']='Unable to select the database'; + } + } + + //bailout on errors. + if($this->errors) return false; + + /*************** We're ready to install ************************/ + define('ADMIN_EMAIL',$vars['admin_email']); //Needed to report SQL errors during install. + define('PREFIX',$vars['prefix']); //Table prefix + + $schemaFile =INC_DIR.'sql/osticket-v1.7-mysql.sql'; //DB dump. + $debug = true; //XXX:Change it to true to show SQL errors. + + //Last minute checks. + if(!file_exists($schemaFile)) + $this->errors['err']='Internal Error - please make sure your download is the latest (#1)'; + elseif(!file_exists($this->getConfigFile()) || !($configFile=file_get_contents($this->getConfigFile()))) + $this->errors['err']='Unable to read config file. Permission denied! (#2)'; + elseif(!($fp = @fopen($this->getConfigFile(),'r+'))) + $this->errors['err']='Unable to open config file for writing. Permission denied! (#3)'; + elseif(!$this->load_sql_file($schemaFile,$vars['prefix'], true, $debug)) + $this->errors['err']='Error parsing SQL schema! Get help from developers (#4)'; + + if(!$this->errors) { + //Create admin user. + $sql='INSERT INTO '.PREFIX.'staff SET created=NOW() ' + .', isactive=1, isadmin=1, group_id=1, dept_id=1, timezone_id=8, max_page_size=25 ' + .', email='.db_input($_POST['admin_email']) + .', firstname='.db_input($vars['fname']) + .', lastname='.db_input($vars['lname']) + .', username='.db_input($vars['username']) + .', passwd='.db_input(Passwd::hash($vars['passwd'])); + if(!mysql_query($sql) || !($uid=mysql_insert_id())) + $this->errors['err']='Unable to create admin user (#6)'; + } + + if(!$this->errors) { + //Create config settings---default settings! + //XXX: rename ostversion helpdesk_* ?? + $sql='INSERT INTO '.PREFIX.'config SET updated=NOW(), isonline=0 ' + .', default_email_id=1, alert_email_id=2, default_dept_id=1 ' + .', default_sla_id=1, default_timezone_id=8, default_template_id=1 ' + .', admin_email='.db_input($vars['admin_email']) + .', schema_signature='.db_input(md5_file($schemaFile)) + .', helpdesk_url='.db_input(URL) + .', helpdesk_title='.db_input($vars['name']); + if(!mysql_query($sql) || !($cid=mysql_insert_id())) + $this->errors['err']='Unable to create config settings (#7)'; + } + + if($this->errors) return false; //Abort on internal errors. + + + //Rewrite the config file - MUST be done last to allow for installer recovery. + $configFile= str_replace("define('OSTINSTALLED',FALSE);","define('OSTINSTALLED',TRUE);",$configFile); + $configFile= str_replace('%ADMIN-EMAIL',$vars['admin_email'],$configFile); + $configFile= str_replace('%CONFIG-DBHOST',$vars['dbhost'],$configFile); + $configFile= str_replace('%CONFIG-DBNAME',$vars['dbname'],$configFile); + $configFile= str_replace('%CONFIG-DBUSER',$vars['dbuser'],$configFile); + $configFile= str_replace('%CONFIG-DBPASS',$vars['dbpass'],$configFile); + $configFile= str_replace('%CONFIG-PREFIX',$vars['prefix'],$configFile); + $configFile= str_replace('%CONFIG-SIRI',Misc::randcode(32),$configFile); + if(!$fp || !ftruncate($fp,0) || !fwrite($fp,$configFile)) { + $this->errors['err']='Unable to write to config file. Permission denied! (#5)'; + return false; + } + @fclose($fp); + + /************* Make the system happy ***********************/ + //Create default emails! + $email = $vars['email']; + list(,$domain)=explode('@',$vars['email']); + $sql='INSERT INTO '.PREFIX.'email (`email_id`, `dept_id`, `name`,`email`,`created`,`updated`) VALUES ' + ." (1,1,'Support','$email',NOW(),NOW())" + .",(2,1,'osTicket Alerts','alerts@$domain',NOW(),NOW())" + .",(3,1,'','noreply@$domain',NOW(),NOW())"; + @mysql_query($sql); + + //Create a ticket to make the system warm and happy. + $sql='INSERT INTO '.PREFIX.'ticket SET created=NOW(), status="open", source="Web" ' + .' ,priority_id=2, dept_id=1, topic_id=1 ' + .' ,ticketID='.db_input(Misc::randNumber(6)) + .' ,email="support@osticket.com" ' + .' ,name="osTicket Support" ' + .' ,subject="osTicket Installed!"'; + if(mysql_query($sql) && ($tid=mysql_insert_id())) { + if(!($msg=file_get_contents(INC_DIR.'msg/installed.txt'))) + $msg='Congratulations and Thank you for choosing osTicket!'; + + $sql='INSERT INTO '.PREFIX.'ticket_thread SET created=NOW()' + .', source="Web" ' + .', thread_type="M" ' + .', ticket_id='.db_input($tid) + .', title='.db_input('osTicket Installed') + .', body='.db_input($msg); + @mysql_query($sql); + } + //TODO: create another personalized ticket and assign to admin?? + + //Log a message. + $msg="Congratulations osTicket basic installation completed!\n\nThank you for choosing osTicket!"; + $sql='INSERT INTO '.PREFIX.'syslog SET created=NOW(), updated=NOW(), log_type="Debug" ' + .', title="osTicket installed!"' + .', log='.db_input($msg) + .', ip_address='.db_input($_SERVER['REMOTE_ADDR']); + @mysql_query($sql); + + return true; + } +} +?> diff --git a/setup/inc/class.migrater.php b/setup/inc/class.migrater.php new file mode 100644 index 0000000000000000000000000000000000000000..de8a3d9590e97b9d78ecb905528bcbc1bc2c03a5 --- /dev/null +++ b/setup/inc/class.migrater.php @@ -0,0 +1,67 @@ +<?php +/********************************************************************* + class.migrater.php + + SQL database migrater. This provides the engine capable of rolling the + database for an osTicket installation forward (and perhaps even + backward) in time using a set of included migration scripts. Each script + will roll the database between two database checkpoints. Where possible, + the migrater will roll several checkpoint scripts into one to be applied + together. + + Jared Hancock <jared@osticket.com> + Copyright (c) 2006-2012 osTicket + http://www.osticket.com + + Released under the GNU General Public License WITHOUT ANY WARRANTY. + See LICENSE.TXT for details. + + vim: expandtab sw=4 ts=4 sts=4: +**********************************************************************/ + +class DatabaseMigrater { + + var $start; + var $end; + var $sqldir; + + function DatabaseMigrater($start, $end, $sqldir) { + + $this->start = $start; + $this->end = $end; + $this->sqldir = $sqldir; + + } + + function getPatches($stop=null) { + + $start= $this->start; + $stop = $stop?$stop:$this->end; + + $patches = array(); + while (true) { + $next = glob($this->sqldir . substr($start, 0, 8) + . '-*.patch.sql'); + if (count($next) == 1) { + $patches[] = $next[0]; + $start = substr(basename($next[0]), 9, 8); + } elseif (count($next) == 0) { + # There are no patches leaving the current signature. We + # have to assume that we've applied all the available + # patches. + break; + } else { + # Problem -- more than one patch exists from this snapshot. + # We probably need a graph approach to solve this. + break; + } + + # Break if we've reached our target stop. + if(!$start || !strncasecmp($start, $stop, 8)) + break; + } + + return $patches; + } +} +?> diff --git a/setup/inc/class.setup.php b/setup/inc/class.setup.php index c6bf7b6751c9e80236d3cbfe143a37c6d52cf6c5..34bc57486942bca10d9540459dfd8daf37a4f232 100644 --- a/setup/inc/class.setup.php +++ b/setup/inc/class.setup.php @@ -21,8 +21,8 @@ Class SetupWizard { 'mysql' => '4.4'); //Version info - same as the latest version. - var $version ='1.7-rc1'; - var $version_verbose='1.7 RC 1'; + var $version ='1.7-dpr2'; + var $version_verbose='1.7 DPR 2'; //Errors var $errors=array(); @@ -31,18 +31,18 @@ Class SetupWizard { $this->errors=array(); } - function load_sql_file($file, $prefix, $debug=false) { + function load_sql_file($file, $prefix, $abort=true, $debug=false) { if(!file_exists($file) || !($schema=file_get_contents($file))) - return $this->abort('Error accessing SQL file'); + return $this->abort('Error accessing SQL file '.basename($file)); - return $this->load_sql($schema, $prefix, $debug); + return $this->load_sql($schema, $prefix, $abort, $debug); } /* load SQL schema - assumes MySQL && existing connection */ - function load_sql($schema, $prefix, $debug=false) { + function load_sql($schema, $prefix, $abort=true, $debug=false) { # Strip comments and remarks $schema=preg_replace('%^\s*(#|--).*$%m','',$schema); @@ -57,7 +57,8 @@ Class SetupWizard { foreach($statements as $k=>$sql) { if(!mysql_query($sql)) { if($debug) echo "[$sql]=>".mysql_error(); - return $this->abort("[$sql] - ".mysql_error()); + if($abort) + return $this->abort("[$sql] - ".mysql_error()); } } @@ -96,15 +97,18 @@ Class SetupWizard { @error is a mixed var. */ function abort($error) { - + + $this->onError($error); + return false; // Always false... It's an abort. + } + + function setError($error) { + if($error && is_array($error)) $this->errors = array_merge($this->errors,$error); elseif($error) $this->errors[] = $error; - - //Always returns FALSE. - return false; } function getErrors(){ @@ -112,276 +116,8 @@ Class SetupWizard { return $this->errors; } - /* Access and user validation*/ - - function getThisUser() { - - - } -} - -class Upgrader extends SetupWizard { - - var $prefix; - - function Upgrader($prefix) { - $this->prefix = $prefix; - $this->errors = array(); - } - - function getTablePrefix() { - return $this->prefix; - } - - /* upgrade magic related to the given version */ - function upgradeTo($version) { - - $errors = array(); - switch($version) { - case '1.7-RC1': - //TODO: latest upgrade logic. - break; - case '1.6 ST': - //TODO: refactor code from 1.6 ST. - break; - case '1.6 RC5': - //TODO: refactor code from 1.6 ST. - break; - default: - //XXX: escape version - return $this->abort('Trying to upgrade unknown version '.$version); - } - - if($errors) - return $this->abort($errors); - - return true; - } - - /* - Do base upgrade - Does fall-through upgrade until we reach the current version. - We're assumming the user - is upgrading upgradable version of osTicket! - @version - version number to upgrade from! - */ - function upgradeFrom($version) { - - if(!$version || $this->getErrors()) - return false; - - if(!strcasecmp($version,$this->getVersion())) - return true; - - //XXX: Note FALLTHROUGH (we only break on error) and uppercase cases. - switch(strtoupper($version)) { - case 'OLD': //Upgrade old versions to 1.6 ST. - if(!$this->upgradeTo('1.6 RC5')) break; - /* FALLTHROUGH */ - case '1.6 RC5': //Upgrade 1.6 RC5 to 1.6 ST - if(!$this->upgradeTo('1.6 ST')) break; - /* FALLTHROUGH */ - case '1.6 ST': //Upgrade 1.6 ST to to 1.7 RC1 - if(!$this->upgradeTo('1.7-RC1')) break; - /* LAST CASE IS NOT FALLTHROUGH */ - break; - default: //Catch all - Upgrading older versions 1.3+ - return $this->upgradeFrom('OLD'); - } - //XXX: Set errors??? - - return (!$this->getErrors()); - } - - function cleanup() { - //FIXME: cleanup logic here. - sleep(2); - - return true; - } -} - -/* - Installer class - latest version. - */ -class Installer extends SetupWizard { - - var $config; - - function Installer($configfile) { - $this->config =$configfile; - $this->errors=array(); - } - - function getConfigFile() { - return $this->config; - } - - function config_exists() { - return ($this->getConfigFile() && file_exists($this->getConfigFile())); - } - - function config_writable() { - return ($this->getConfigFile() && is_writable($this->getConfigFile())); - } - - function check_config() { - return ($this->config_exists() && $this->config_writable()); - } - - //XXX: Latest version insall logic...no carry over. - function install($vars) { - - $this->errors=$f=array(); - - $f['name'] = array('type'=>'string', 'required'=>1, 'error'=>'Name required'); - $f['email'] = array('type'=>'email', 'required'=>1, 'error'=>'Valid email required'); - $f['fname'] = array('type'=>'string', 'required'=>1, 'error'=>'First name required'); - $f['lname'] = array('type'=>'string', 'required'=>1, 'error'=>'Last name required'); - $f['admin_email'] = array('type'=>'email', 'required'=>1, 'error'=>'Valid email required'); - $f['username'] = array('type'=>'username', 'required'=>1, 'error'=>'Username required'); - $f['passwd'] = array('type'=>'password', 'required'=>1, 'error'=>'Password required'); - $f['passwd2'] = array('type'=>'string', 'required'=>1, 'error'=>'Confirm password'); - $f['prefix'] = array('type'=>'string', 'required'=>1, 'error'=>'Table prefix required'); - $f['dbhost'] = array('type'=>'string', 'required'=>1, 'error'=>'Hostname required'); - $f['dbname'] = array('type'=>'string', 'required'=>1, 'error'=>'Database name required'); - $f['dbuser'] = array('type'=>'string', 'required'=>1, 'error'=>'Username required'); - $f['dbpass'] = array('type'=>'string', 'required'=>1, 'error'=>'password required'); - - - if(!Validator::process($f,$vars,$this->errors) && !$this->errors['err']) - $this->errors['err']='Missing or invalid data - correct the errors and try again.'; - - - //Staff's email can't be same as system emails. - if($vars['admin_email'] && $vars['email'] && !strcasecmp($vars['admin_email'],$vars['email'])) - $this->errors['admin_email']='Conflicts with system email above'; - //Admin's pass confirmation. - if(!$this->errors && strcasecmp($vars['passwd'],$vars['passwd2'])) - $this->errors['passwd2']='passwords to not match!'; - //Check table prefix underscore required at the end! - if($vars['prefix'] && substr($vars['prefix'], -1)!='_') - $this->errors['prefix']='Bad prefix. Must have underscore (_) at the end. e.g \'ost_\''; - - //Make sure admin username is not very predictable. XXX: feels dirty but necessary - if(!$this->errors['username'] && in_array(strtolower($vars['username']),array('admin','admins','username','osticket'))) - $this->errors['username']='Bad username'; - - //MYSQL: Connect to the DB and check the version & database (create database if it doesn't exist!) - if(!$this->errors) { - if(!db_connect($vars['dbhost'],$vars['dbuser'],$vars['dbpass'])) - $this->errors['db']='Unable to connect to MySQL server. Possibly invalid login info.'; - elseif(db_version()< $this->getMySQLVersion()) - $this->errors['db']=sprintf('osTicket requires MySQL %s or better!',$this->getMySQLVersion()); - elseif(!db_select_database($vars['dbname']) && !db_create_database($vars['dbname'])) { - $this->errors['dbname']='Database doesn\'t exist'; - $this->errors['db']='Unable to create the database.'; - } elseif(!db_select_database($vars['dbname'])) { - $this->errors['dbname']='Unable to select the database'; - } - } - - //bailout on errors. - if($this->errors) return false; - - /*************** We're ready to install ************************/ - define('ADMIN_EMAIL',$vars['admin_email']); //Needed to report SQL errors during install. - define('PREFIX',$vars['prefix']); //Table prefix - - $schemaFile =INC_DIR.'sql/osticket-v1.7-mysql.sql'; //DB dump. - $debug = true; //XXX:Change it to true to show SQL errors. - - //Last minute checks. - if(!file_exists($schemaFile)) - $this->errors['err']='Internal Error - please make sure your download is the latest (#1)'; - elseif(!file_exists($this->getConfigFile()) || !($configFile=file_get_contents($this->getConfigFile()))) - $this->errors['err']='Unable to read config file. Permission denied! (#2)'; - elseif(!($fp = @fopen($this->getConfigFile(),'r+'))) - $this->errors['err']='Unable to open config file for writing. Permission denied! (#3)'; - elseif(!$this->load_sql_file($schemaFile,$vars['prefix'],$debug)) - $this->errors['err']='Error parsing SQL schema! Get help from developers (#4)'; - - if(!$this->errors) { - //Create admin user. - $sql='INSERT INTO '.PREFIX.'staff SET created=NOW() ' - .', isactive=1, isadmin=1, group_id=1, dept_id=1, timezone_id=8, max_page_size=25 ' - .', email='.db_input($_POST['admin_email']) - .', firstname='.db_input($vars['fname']) - .', lastname='.db_input($vars['lname']) - .', username='.db_input($vars['username']) - .', passwd='.db_input(Passwd::hash($vars['passwd'])); - if(!mysql_query($sql) || !($uid=mysql_insert_id())) - $this->errors['err']='Unable to create admin user (#6)'; - } - - if(!$this->errors) { - //Create config settings---default settings! - //XXX: rename ostversion helpdesk_* ?? - $sql='INSERT INTO '.PREFIX.'config SET updated=NOW(), isonline=0 ' - .', default_email_id=1, alert_email_id=2, default_dept_id=1 ' - .', default_sla_id=1, default_timezone_id=8, default_template_id=1 ' - .', admin_email='.db_input($vars['admin_email']) - .', schema_signature='.db_input(md5_file($schemaFile)) - .', helpdesk_url='.db_input(URL) - .', helpdesk_title='.db_input($vars['name']); - if(!mysql_query($sql) || !($cid=mysql_insert_id())) - $this->errors['err']='Unable to create config settings (#7)'; - } - - if($this->errors) return false; //Abort on internal errors. - - - //Rewrite the config file - MUST be done last to allow for installer recovery. - $configFile= str_replace("define('OSTINSTALLED',FALSE);","define('OSTINSTALLED',TRUE);",$configFile); - $configFile= str_replace('%ADMIN-EMAIL',$vars['admin_email'],$configFile); - $configFile= str_replace('%CONFIG-DBHOST',$vars['dbhost'],$configFile); - $configFile= str_replace('%CONFIG-DBNAME',$vars['dbname'],$configFile); - $configFile= str_replace('%CONFIG-DBUSER',$vars['dbuser'],$configFile); - $configFile= str_replace('%CONFIG-DBPASS',$vars['dbpass'],$configFile); - $configFile= str_replace('%CONFIG-PREFIX',$vars['prefix'],$configFile); - $configFile= str_replace('%CONFIG-SIRI',Misc::randcode(32),$configFile); - if(!$fp || !ftruncate($fp,0) || !fwrite($fp,$configFile)) { - $this->errors['err']='Unable to write to config file. Permission denied! (#5)'; - return false; - } - @fclose($fp); - - /************* Make the system happy ***********************/ - //Create default emails! - $email = $vars['email']; - list(,$domain)=explode('@',$vars['email']); - $sql='INSERT INTO '.PREFIX.'email (`email_id`, `dept_id`, `name`,`email`,`created`,`updated`) VALUES ' - ." (1,1,'Support','$email',NOW(),NOW())" - .",(2,1,'osTicket Alerts','alerts@$domain',NOW(),NOW())" - .",(3,1,'','noreply@$domain',NOW(),NOW())"; - @mysql_query($sql); - - //Create a ticket to make the system warm and happy. - $sql='INSERT INTO '.PREFIX.'ticket SET created=NOW(), status="open", source="Web" ' - .' ,priority_id=2, dept_id=1, topic_id=1 ' - .' ,ticketID='.db_input(Misc::randNumber(6)) - .' ,email="support@osticket.com" ' - .' ,name="osTicket Support" ' - .' ,subject="osTicket Installed!"'; - if(mysql_query($sql) && ($tid=mysql_insert_id())) { - if(!($msg=file_get_contents(INC_DIR.'msg/installed.txt'))) - $msg='Congratulations and Thank you for choosing osTicket!'; - - $sql='INSERT INTO '.PREFIX.'ticket_message SET created=NOW(),source="Web" ' - .', ticket_id='.db_input($tid) - .', message='.db_input($msg); - @mysql_query($sql); - } - //TODO: create another personalized ticket and assign to admin?? - - //Log a message. - $msg="Congratulations osTicket basic installation completed!\n\nThank you for choosing osTicket!"; - $sql='INSERT INTO '.PREFIX.'syslog SET created=NOW(),updated=NOW(),log_type="Debug" ' - .', title="osTicket installed!"' - .', log='.db_input($msg) - .', ip_address='.db_input($_SERVER['REMOTE_ADDR']); - @mysql_query($sql); - - return true; + function onError($error) { + return $this->setError($error); } } ?> diff --git a/setup/inc/class.upgrader.php b/setup/inc/class.upgrader.php new file mode 100644 index 0000000000000000000000000000000000000000..9e208426fcd9288c9108d847c598ca5112dc6d35 --- /dev/null +++ b/setup/inc/class.upgrader.php @@ -0,0 +1,266 @@ +<?php +/********************************************************************* + class.upgrader.php + + osTicket Upgrader + + Peter Rotich <peter@osticket.com> + Copyright (c) 2006-2012 osTicket + http://www.osticket.com + + Released under the GNU General Public License WITHOUT ANY WARRANTY. + See LICENSE.TXT for details. + + vim: expandtab sw=4 ts=4 sts=4: +**********************************************************************/ + +require_once INC_DIR.'class.setup.php'; +require_once INC_DIR.'class.migrater.php'; + +class Upgrader extends SetupWizard { + + var $prefix; + var $sqldir; + var $signature; + + function Upgrader($signature, $prefix, $sqldir) { + + $this->signature = $signature; + $this->shash = substr($signature, 0, 8); + $this->prefix = $prefix; + $this->sqldir = $sqldir; + $this->errors = array(); + + //Init persistent state of upgrade. + $this->state = &$_SESSION['ost_upgrader'][$this->getShash()]['state']; + + //Init the task Manager. + if(!isset($_SESSION['ost_upgrader'][$this->getShash()])) + $_SESSION['ost_upgrader'][$this->getShash()]['tasks']=array(); + + //Tasks to perform - saved on the session. + $this->tasks = &$_SESSION['ost_upgrader'][$this->getShash()]['tasks']; + + //Database migrater + $this->migrater = new DatabaseMigrater($this->signature, SCHEMA_SIGNATURE, $this->sqldir); + } + + function getStops() { + return array('7be60a84' => 'migrateAttachments2DB'); + } + + function onError($error) { + $this->setError($error); + $this->setState('aborted'); + } + + function isUpgradable() { + return (!$this->isAborted() && $this->getNextPatch()); + } + + function isAborted() { + return !strcasecmp($this->getState(), 'aborted'); + } + + function getSchemaSignature() { + return $this->signature; + } + + function getShash() { + return $this->shash; + } + + function getTablePrefix() { + return $this->prefix; + } + + function getSQLDir() { + return $this->sqldir; + } + + function getState() { + return $this->state; + } + + function setState($state) { + $this->state = $state; + } + + function getPatches() { + return $this->migrater->getPatches(); + } + + function getNextPatch() { + $p = $this->getPatches(); + return (count($p)) ? $p[0] : false; + } + + function getNextVersion() { + if(!$patch=$this->getNextPatch()) + return '(Latest)'; + + $info = $this->readPatchInfo($patch); + return $info['version']; + } + + function readPatchInfo($patch) { + $info = array(); + if (preg_match('/\*(.*)\*/', file_get_contents($patch), $matches)) { + if (preg_match('/@([\w\d_-]+)\s+(.*)$/', $matches[0], $matches2)) + foreach ($matches2 as $match) + $info[$match[0]] = $match[1]; + } + if (!isset($info['version'])) + $info['version'] = substr(basename($patch), 9, 8); + return $info; + } + + function getNextAction() { + + $action='Upgrade osTicket to '.$this->getVersion(); + if($this->getNumPendingTasks() && ($task=$this->getNextTask())) { + $action = $task['desc']; + if($task['status']) //Progress report... + $action.=' ('.$task['status'].')'; + } elseif($this->isUpgradable() && ($nextversion = $this->getNextVersion())) { + $action = "Upgrade to $nextversion"; + } + + return $action; + } + + function getNumPendingTasks() { + + return count($this->getPendingTasks()); + } + + function getPendingTasks() { + + $pending=array(); + if(($tasks=$this->getTasks())) { + foreach($tasks as $k => $task) { + if(!$task['done']) + $pending[$k] = $task; + } + } + + return $pending; + } + + function getTasks() { + return $this->tasks; + } + + function getNextTask() { + + if(!($tasks=$this->getPendingTasks())) + return null; + + return current($tasks); + } + + function removeTask($tId) { + + if(isset($this->tasks[$tId])) + unset($this->tasks[$tId]); + + return (!$this->tasks[$tId]); + } + + function setTaskStatus($tId, $status) { + if(isset($this->tasks[$tId])) + $this->tasks[$tId]['status'] = $status; + } + + function doTasks() { + + if(!($tasks=$this->getPendingTasks())) + return true; //Nothing to do. + + foreach($tasks as $k => $task) { + if(call_user_func(array($this, $task['func']), $k)===0) { + $this->tasks[$k]['done'] = true; + } else { //Task has pending items to process. + break; + } + } + + return (!$this->getPendingTasks()); + } + + function upgrade() { + + if($this->getPendingTasks() || !($patches=$this->getPatches())) + return false; + + foreach ($patches as $patch) { + if (!$this->load_sql_file($patch, $this->getTablePrefix())) + return false; + + //TODO: Log the upgrade + + + //clear previous patch info - + unset($_SESSION['ost_upgrader'][$this->getShash()]); + + //Load up post-upgrade tasks.... if any. + $phash = substr(basename($patch), 0, 17); + if(!($tasks=$this->getTasksForPatch($phash))) + continue; + + //We have tasks to perform - set the tasks and break. + $shash = substr($phash, 9, 8); + $_SESSION['ost_upgrader'][$shash]['tasks'] = $tasks; + $_SESSION['ost_upgrader'][$shash]['state'] = 'upgrade'; + break; + } + + return true; + + } + + function getTasksForPatch($phash) { + + $tasks=array(); + switch($phash) { //Add patch specific scripted tasks. + case 'd4fe13b1-7be60a84': //V1.6 ST- 1.7 * + $tasks[] = array('func' => 'migrateAttachments2DB', + 'desc' => 'Migrating attachments to database, it might take a while depending on the number of files.'); + break; + } + + //Check if cleanup p + $file=$this->getSQLDir().$phash.'.cleanup.sql'; + if(file_exists($file)) + $tasks[] = array('func' => 'cleanup', 'desc' => 'Post-upgrade cleanup!'); + + + return $tasks; + } + + /************* TASKS **********************/ + function cleanup($tId=0) { + + $file=$this->getSQLDir().$this->getShash().'-cleanup.sql'; + if(!file_exists($file)) //No cleanup script. + return 0; + + //We have a cleanup script ::XXX: Don't abort on error? + if($this->load_sql_file($file, $this->getTablePrefix(), false, true)) + return 0; + + //XXX: ??? + return false; + } + + + function migrateAttachments2DB($tId=0) { + echo "Process attachments here - $tId"; + $att_migrater = new AttachmentMigrater(); + $att_migrater->start_migration(); + # XXX: Loop here (with help of task manager) + $att_migrater->do_batch(); + return 0; + } +} +?> diff --git a/setup/inc/sql/02decaa2-60fcbee1.patch.sql b/setup/inc/sql/02decaa2-60fcbee1.patch.sql new file mode 100644 index 0000000000000000000000000000000000000000..40dc644b3df64b0e103a3a7c16ed3c835a4bfae3 --- /dev/null +++ b/setup/inc/sql/02decaa2-60fcbee1.patch.sql @@ -0,0 +1,6 @@ +-- Update all temlates with the new wording. +UPDATE `%TABLE_PREFIX%email_template` + SET `ticket_overlimit_body` = '%name\r\n\r\nYou have reached the maximum number of open tickets allowed.\r\n\r\nTo be able to open another ticket, one of your pending tickets must be closed. To update or add comments to an open ticket simply login using the link below.\r\n\r\n%url/view.php?e=%email\r\n\r\nThank you.\r\n\r\nSupport Ticket System'; + +UPDATE `%TABLE_PREFIX%config` + SET `schema_signature`='60fcbee1da3180d1b690187aa5006c88'; diff --git a/setup/inc/sql/522e5b78-02decaa2.patch.sql b/setup/inc/sql/522e5b78-02decaa2.patch.sql new file mode 100644 index 0000000000000000000000000000000000000000..78c951d69cc10f255ffb3e4ba85fcf93dae6db58 --- /dev/null +++ b/setup/inc/sql/522e5b78-02decaa2.patch.sql @@ -0,0 +1,10 @@ +/** + * @version v1.7-DPR2-P2 + */ +UPDATE `%TABLE_PREFIX%sla` + SET `created` = NOW(), + `updated` = NOW() + WHERE `created` IS NULL; + +UPDATE `%TABLE_PREFIX%config` + SET `schema_signature`='02decaa20c10c9615558762018e25507'; diff --git a/setup/inc/sql/60fcbee1-f8856d56.patch.sql b/setup/inc/sql/60fcbee1-f8856d56.patch.sql new file mode 100644 index 0000000000000000000000000000000000000000..2b7e48599816e88702f709f50557189b160a727e --- /dev/null +++ b/setup/inc/sql/60fcbee1-f8856d56.patch.sql @@ -0,0 +1,19 @@ +DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket_event`; +CREATE TABLE `%TABLE_PREFIX%ticket_event` ( + `ticket_id` int(11) unsigned NOT NULL default '0', + `staff_id` int(11) unsigned NOT NULL, + `team_id` int(11) unsigned NOT NULL, + `dept_id` int(11) unsigned NOT NULL, + `topic_id` int(11) unsigned NOT NULL, + `state` enum('created','closed','reopened','assigned','transferred','overdue') NOT NULL, + `staff` varchar(255) NOT NULL default 'SYSTEM', + `timestamp` datetime NOT NULL, + KEY `ticket_state` (`ticket_id`, `state`, `timestamp`), + KEY `ticket_stats` (`timestamp`, `state`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket_history`; +DROP TABLE IF EXISTS `%TABLE_PREFIX%history`; + +UPDATE `%TABLE_PREFIX%config` + SET `schema_signature`='f8856d56e51c5cc3416389de78b54515'; diff --git a/setup/inc/sql/7be60a84-522e5b78.patch.sql b/setup/inc/sql/7be60a84-522e5b78.patch.sql new file mode 100644 index 0000000000000000000000000000000000000000..acdaf7d0d3c1f8baaedd40bd68e33b01b97e72c9 --- /dev/null +++ b/setup/inc/sql/7be60a84-522e5b78.patch.sql @@ -0,0 +1,9 @@ +/** + * @version v1.7-DPR1 (P1) + */ +UPDATE `%TABLE_PREFIX%email_template` + SET `ticket_overlimit_subj` = 'Open Tickets Limit Reached' + WHERE `tpl_id` = 1 AND `cfg_id` = 1; + +UPDATE `%TABLE_PREFIX%config` + SET `schema_signature`='522e5b783c2824c67222260ee22baa93'; diff --git a/setup/inc/sql/f8856d56-abe9c0cb.patch.sql b/setup/inc/sql/f8856d56-abe9c0cb.patch.sql new file mode 100644 index 0000000000000000000000000000000000000000..a5f54aa8516aaaaf268e363b8ae58674725b61af --- /dev/null +++ b/setup/inc/sql/f8856d56-abe9c0cb.patch.sql @@ -0,0 +1,109 @@ +/** + * Merge ticket thread tables into one + * + * Replace the ticket_{message,response,note} tables with a single + * ticket_thread table that will contain data for all three current message + * types. This simplifies much of the ticket thread code and paves the way + * for other types of messages in the future. + * + * This patch automagically moves the data from the three federated tables + * into the one combined table. + */ +DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket_thread`; +CREATE TABLE `%TABLE_PREFIX%ticket_thread` ( + `id` int(11) unsigned NOT NULL auto_increment, + `pid` int(11) unsigned NOT NULL default '0', + `ticket_id` int(11) unsigned NOT NULL default '0', + `staff_id` int(11) unsigned NOT NULL default '0', + `thread_type` enum('M','R','N') NOT NULL, + `poster` varchar(128) NOT NULL default '', + `source` varchar(32) NOT NULL default '', + `title` varchar(255), + `body` text NOT NULL, + `ip_address` varchar(64) NOT NULL default '', + `created` datetime NOT NULL, + `updated` datetime NOT NULL, + -- Temporary columns for conversion + `old_pk` int(11) unsigned NOT NULL, + `old_pid` int(11) unsigned, + PRIMARY KEY (`id`), + KEY `ticket_id` (`ticket_id`), + KEY `staff_id` (`staff_id`), + FULLTEXT KEY `body` (`body`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket_email_info`; +CREATE TABLE `%TABLE_PREFIX%ticket_email_info` ( + `message_id` int(11) unsigned NOT NULL, + `email_mid` varchar(255) NOT NULL, + `headers` text, + KEY `message_id` (`email_mid`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- Transfer messages +INSERT INTO `%TABLE_PREFIX%ticket_thread` + (`ticket_id`, `thread_type`, `body`, `ip_address`, + `created`, `updated`, `old_pk`) + SELECT `ticket_id`, 'M', `message`, `ip_address`, + `created`, COALESCE(`updated`, NOW()), `msg_id` + FROM `%TABLE_PREFIX%ticket_message`; + +-- Transfer responses +INSERT INTO `%TABLE_PREFIX%ticket_thread` + (`ticket_id`, `staff_id`, `thread_type`, `poster`, `body`, `ip_address`, + `created`, `updated`, `old_pk`, `old_pid`) + SELECT `ticket_id`, `staff_id`, 'R', `staff_name`, `response`, `ip_address`, + `created`, COALESCE(`updated`, NOW()), `response_id`, `msg_id` + FROM `%TABLE_PREFIX%ticket_response`; + +-- Connect responses to (new) messages +CREATE TABLE `%TABLE_PREFIX%T_resp_links` + SELECT `id`, `old_pk`, `old_pid` FROM `%TABLE_PREFIX%ticket_thread`; + +UPDATE `%TABLE_PREFIX%ticket_thread` + SET `pid` = ( SELECT T2.`id` FROM `%TABLE_PREFIX%T_resp_links` T2 + WHERE `old_pid` = T2.`old_pk` ) + WHERE `thread_type` = 'R' + AND `old_pid` IS NOT NULL; + +DROP TABLE `%TABLE_PREFIX%T_resp_links`; + +-- Transfer notes +INSERT INTO `%TABLE_PREFIX%ticket_thread` + (`ticket_id`, `staff_id`, `thread_type`, `body`, `title`, + `source`, `poster`, `created`, `updated`, `old_pk`) + SELECT `ticket_id`, `staff_id`, 'N', `note`, `title`, + `source`, ( SELECT CONCAT_WS(' ', T2.`firstname`, T2.`lastname`) + FROM `%TABLE_PREFIX%staff` T2 + WHERE T2.`staff_id` = `staff_id` ), + `created`, NOW(), `note_id` + FROM `%TABLE_PREFIX%ticket_note`; + +-- Transfer email information from messages +INSERT INTO `%TABLE_PREFIX%ticket_email_info` + (`message_id`, `email_mid`, `headers`) + SELECT ( SELECT T2.`id` FROM `%TABLE_PREFIX%ticket_thread` T2 + WHERE `msg_id` = T2.`old_pk` + AND `thread_type` = 'M' ), + `messageId`, `headers` + FROM `%TABLE_PREFIX%ticket_message` + WHERE `messageId` IS NOT NULL; + +-- Update attachment table +UPDATE `%TABLE_PREFIX%ticket_attachment` + SET `ref_id` = ( SELECT T2.`id` FROM `%TABLE_PREFIX%ticket_thread` T2 + WHERE `ref_id` = T2.`old_pk` + AND `ref_type` = T2.`thread_type` ); + +-- Drop temporary columns +ALTER TABLE `%TABLE_PREFIX%ticket_thread` DROP COLUMN `old_pk`; +ALTER TABLE `%TABLE_PREFIX%ticket_thread` DROP COLUMN `old_pid`; + +-- Drop old tables +DROP TABLE `%TABLE_PREFIX%ticket_message`; +DROP TABLE `%TABLE_PREFIX%ticket_response`; +DROP TABLE `%TABLE_PREFIX%ticket_note`; + +-- Finished with patch +UPDATE `%TABLE_PREFIX%config` + SET `schema_signature`='abe9c0cb845be52c10fcd7b3e626a589'; diff --git a/setup/inc/sql/osticket-v1.7-mysql.sql b/setup/inc/sql/osticket-v1.7-mysql.sql index df11daf8612702b46a2c9fda0be56a2fe16f2445..fbd2059bab92027cac455a893689ddc9e80445ca 100644 --- a/setup/inc/sql/osticket-v1.7-mysql.sql +++ b/setup/inc/sql/osticket-v1.7-mysql.sql @@ -598,48 +598,28 @@ CREATE TABLE `%TABLE_PREFIX%ticket_lock` ( KEY `staff_id` (`staff_id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; -DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket_history`; -CREATE TABLE `%TABLE_PREFIX%ticket_history` ( +DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket_email_info`; +CREATE TABLE `%TABLE_PREFIX%ticket_email_info` ( + `message_id` int(11) unsigned NOT NULL, + `email_mid` varchar(255) NOT NULL, + `headers` text, + KEY `message_id` (`email_mid`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket_event`; +CREATE TABLE `%TABLE_PREFIX%ticket_event` ( `ticket_id` int(11) unsigned NOT NULL default '0', - `state` enum('opened','closed','assigned','transferred','overdue') NOT NULL, + `staff_id` int(11) unsigned NOT NULL, + `team_id` int(11) unsigned NOT NULL, + `dept_id` int(11) unsigned NOT NULL, + `topic_id` int(11) unsigned NOT NULL, + `state` enum('created','closed','reopened','assigned','transferred','overdue') NOT NULL, `staff` varchar(255) NOT NULL default 'SYSTEM', `timestamp` datetime NOT NULL, KEY `ticket_state` (`ticket_id`, `state`, `timestamp`), KEY `ticket_stats` (`timestamp`, `state`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; -DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket_message`; -CREATE TABLE `%TABLE_PREFIX%ticket_message` ( - `msg_id` int(11) unsigned NOT NULL auto_increment, - `ticket_id` int(11) unsigned NOT NULL default '0', - `messageId` varchar(255) default NULL, - `message` text NOT NULL, - `headers` text, - `source` varchar(16) default NULL, - `ip_address` varchar(16) default NULL, - `created` datetime NOT NULL, - `updated` datetime default NULL, - PRIMARY KEY (`msg_id`), - KEY `ticket_id` (`ticket_id`), - KEY `msgId` (`messageId`), - FULLTEXT KEY `message` (`message`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8; - -DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket_note`; -CREATE TABLE `%TABLE_PREFIX%ticket_note` ( - `note_id` int(11) unsigned NOT NULL auto_increment, - `ticket_id` int(11) unsigned NOT NULL default '0', - `staff_id` int(10) unsigned NOT NULL default '0', - `source` varchar(32) NOT NULL default '', - `title` varchar(255) NOT NULL default 'Generic Intermal Notes', - `note` text NOT NULL, - `created` datetime NOT NULL, - PRIMARY KEY (`note_id`), - KEY `ticket_id` (`ticket_id`), - KEY `staff_id` (`staff_id`), - FULLTEXT KEY `note` (`note`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8; - DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket_priority`; CREATE TABLE `%TABLE_PREFIX%ticket_priority` ( `priority_id` tinyint(4) NOT NULL auto_increment, @@ -660,22 +640,24 @@ INSERT INTO `%TABLE_PREFIX%ticket_priority` (`priority_id`, `priority`, `priorit (3, 'high', 'High', '#FEE7E7', 2, 1), (4, 'emergency', 'Emergency', '#FEE7E7', 1, 0); -DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket_response`; -CREATE TABLE `%TABLE_PREFIX%ticket_response` ( - `response_id` int(11) unsigned NOT NULL auto_increment, - `msg_id` int(11) unsigned NOT NULL default '0', +DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket_thread`; +CREATE TABLE `%TABLE_PREFIX%ticket_thread` ( + `id` int(11) unsigned NOT NULL auto_increment, + `pid` int(11) unsigned NOT NULL default '0', `ticket_id` int(11) unsigned NOT NULL default '0', `staff_id` int(11) unsigned NOT NULL default '0', - `staff_name` varchar(32) NOT NULL default '', - `response` text NOT NULL, - `ip_address` varchar(16) NOT NULL default '', + `thread_type` enum('M','R','N') NOT NULL, + `poster` varchar(128) NOT NULL default '', + `source` varchar(32) NOT NULL default '', + `title` varchar(255), + `body` text NOT NULL, + `ip_address` varchar(64) NOT NULL default '', `created` datetime NOT NULL, `updated` datetime NOT NULL, - PRIMARY KEY (`response_id`), + PRIMARY KEY (`id`), KEY `ticket_id` (`ticket_id`), - KEY `msg_id` (`msg_id`), KEY `staff_id` (`staff_id`), - FULLTEXT KEY `response` (`response`) + FULLTEXT KEY `body` (`body`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; DROP TABLE IF EXISTS `%TABLE_PREFIX%timezone`; diff --git a/setup/inc/sql/osticket-v1.7-mysql.sql.md5 b/setup/inc/sql/osticket-v1.7-mysql.sql.md5 new file mode 100644 index 0000000000000000000000000000000000000000..23011d006ad5e19d75630760bff1cfa872db12ec --- /dev/null +++ b/setup/inc/sql/osticket-v1.7-mysql.sql.md5 @@ -0,0 +1 @@ +abe9c0cb845be52c10fcd7b3e626a589 diff --git a/setup/inc/sql/v1.6st-1.7-upgrade-mysql.sql b/setup/inc/sql/v1.6st-1.7-upgrade-mysql.sql index efeb8de6f26eb4e4c4a5e10140147c5b1ebdd3c6..3a2acf2295170c9b6263b33f05d649c378ed5dbb 100644 --- a/setup/inc/sql/v1.6st-1.7-upgrade-mysql.sql +++ b/setup/inc/sql/v1.6st-1.7-upgrade-mysql.sql @@ -26,10 +26,14 @@ ALTER TABLE `%TABLE_PREFIX%ticket` 'Web', 'Email', 'Phone', 'API', 'Other') NOT NULL DEFAULT 'Other'; -- Add table for ticket history (statistics) tracking -DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket_history`; -CREATE TABLE `%TABLE_PREFIX%ticket_history` ( +DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket_event`; +CREATE TABLE `%TABLE_PREFIX%ticket_event` ( `ticket_id` int(11) unsigned NOT NULL default '0', - `state` enum('opened','closed','assigned','transferred','overdue') NOT NULL, + `staff_id` int(11) unsigned NOT NULL, + `team_id` int(11) unsigned NOT NULL, + `dept_id` int(11) unsigned NOT NULL, + `topic_id` int(11) unsigned NOT NULL, + `state` enum('created','closed','reopened','assigned','transferred','overdue') NOT NULL, `staff` varchar(255) NOT NULL default 'SYSTEM', `timestamp` datetime NOT NULL, KEY `ticket_state` (`ticket_id`, `state`, `timestamp`), diff --git a/setup/inc/upgrade-aborted.inc.php b/setup/inc/upgrade-aborted.inc.php index 8d8f64aa831841dd9431f017c7289760ba18448e..8624590d35710a42906952afab82b2688f028315 100644 --- a/setup/inc/upgrade-aborted.inc.php +++ b/setup/inc/upgrade-aborted.inc.php @@ -6,17 +6,18 @@ if(!defined('SETUPINC')) die('Kwaheri!'); <div id="intro"> <p>Upgrade aborted due to errors. Any errors at this stage are fatal. Please note the error(s), if any, when contacting us.<p> <?php - if($_SESSION['upgrader']['errors']) { - $errors=$_SESSION['upgrader']['errors']; + if($upgrader && ($errors=$upgrader->getErrors())) { if($errors['err']) echo sprintf('<b><font color="red">%s</font></b>',$errors['err']); - echo '<ul class="error">'; unset($errors['err']); - foreach($errors as $k=>$error) + foreach($errors as $k => $error) echo sprintf('<li>%s</li>',$error); echo '</ul>'; - } ?> + } else { + echo '<b><font color="red">Internal error occurred - get technical help.</font></b>'; + } + ?> <p>Please, refer to the <a target="_blank" href="http://osticket.com/wiki/Upgrade_and_Migration">Upgrade Guide</a> on the wiki for more information.</p> </div> <p><strong>Need Help?</strong> We provide <a target="_blank" href="http://osticket.com/support/professional_services.php"><u>professional upgrade services</u></a> and commercial support. <a target="_blank" href="http://osticket.com/support/">Contact us</a> today for expedited help.</p> diff --git a/setup/inc/upgrade-attachments.inc.php b/setup/inc/upgrade-attachments.inc.php deleted file mode 100644 index c8155d32c672e358cb068d79720a076327a88706..0000000000000000000000000000000000000000 --- a/setup/inc/upgrade-attachments.inc.php +++ /dev/null @@ -1,32 +0,0 @@ -<?php -if(!defined('SETUPINC')) die('Kwaheri!'); -$msg = $_SESSION['ost_upgrader']['msg']; -?> -<div id="main"> - <h1>Attachments Migration</h1> - <p>We're almost done! We're now migrating attachments to the database, it might take a while dending on the number of files in your database.<p> - <p style="color:#FF7700;font-weight:bold;">We have to migrate files in batches for technical reasons.</p> - <p>Please don't cancel or close the browser.</p> - - <div id="bar"> - <form method="post" action="upgrade.php" id="attachments"> - <input type="hidden" name="s" value="cleanup"> - <input class="btn" type="submit" name="submit" value="Next Batch"> - </form> - - </div> -</div> -<div id="sidebar"> - <h3>Upgrade Tips</h3> - <p>1. Be patient the process will take a few minutes.</p> - <p>2. If you experience any problems, you can always restore your files/dabase backup.</p> - <p>3. We can help, feel free to <a href="http://osticket.com/support/" target="_blank">contact us </a> for professional help.</p> -</div> -<div id="overlay"></div> - <div id="loading"> - <h4>Moving attachments</h4> - <br> - Please wait... while we migrate attachments! - <br><br> - <div id="msg" style="font-weight: bold;"><?php echo Format::htmlchars($msg); ?></div> - </div> diff --git a/setup/inc/upgrade-cleanup.inc.php b/setup/inc/upgrade-cleanup.inc.php deleted file mode 100644 index f8406ae533a9efbce73e864239d749b586e8f66e..0000000000000000000000000000000000000000 --- a/setup/inc/upgrade-cleanup.inc.php +++ /dev/null @@ -1,38 +0,0 @@ -<?php -if(!defined('SETUPINC')) die('Kwaheri!'); - -?> - <div id="main"> - <h1>osTicket Upgrade</h1> - <div id="intro"> - <p>We're almost done! Please don't cancel or close the browser, any errors at this stage will be fatal.</p> - </div> - <h2>Cleanup: Step 2 of 2</h2> - <p>The upgrade wizard will now attempt to do post upgrade cleanup. It might take a while dending on the size of your database. </p> - <ul> - <li>Setting Changes</li> - <li>Attachment Migration</li> - <li>Database Optimization</li> - </ul> - <div id="bar"> - <form method="post" action="upgrade.php" id="cleanup"> - <input type="hidden" name="s" value="cleanup"> - <input class="btn" type="submit" name="submit" value="Do It Now!"> - </form> - </div> - </div> - <div id="sidebar"> - <h3>Upgrade Tips</h3> - <p>1. Be patient the process will take a couple of seconds.</p> - <p>2. If you experience any problems, you can always restore your files/dabase backup.</p> - <p>3. We can help, feel free to <a href="http://osticket.com/support/" target="_blank">contact us </a> for professional help.</p> - </div> - - <div id="overlay"></div> - <div id="loading"> - <h4>Doing serious stuff!</h4> - <br> - Please wait... while we do post-upgrade cleanup! - <br><br> - <div id="msg" style="font-weight: bold;"></div> - </div> diff --git a/setup/inc/upgrade-core.inc.php b/setup/inc/upgrade-core.inc.php deleted file mode 100644 index ec42e50437537ea01931484a18e86c902ba909b1..0000000000000000000000000000000000000000 --- a/setup/inc/upgrade-core.inc.php +++ /dev/null @@ -1,38 +0,0 @@ -<?php -if(!defined('SETUPINC')) die('Kwaheri!'); - -?> - <div id="main"> - <h1>osTicket Upgrade</h1> - <div id="intro"> - <p>Thank you for taking the time to upgrade your osTicket intallation!</p> - <p>Please don't cancel or close the browser, any errors at this - stage will be fatal.</p> - </div> - <h2>Base upgrade: Step 1 of 2</h2> - <p>The upgrade wizard will now attempt to upgrade your database and core settings!</p> - <ul> - <li>Database enhancements</li> - <li>New and updated features</li> - <li>Enhance settings and security</li> - </ul> - <div id="bar"> - <form method="post" action="upgrade.php" id="upgrade"> - <input type="hidden" name="s" value="upgrade"> - <input class="btn" type="submit" name="submit" value="Do It Now!"> - </form> - </div> - </div> - <div id="sidebar"> - <h3>Upgrade Tips</h3> - <p>1. Be patient the process will take a couple of seconds.</p> - <p>2. If you experience any problems, you can always restore your files/dabase backup.</p> - <p>3. We can help, feel free to <a href="http://osticket.com/support/" target="_blank">contact us </a> for professional help.</p> - </div> - - <div id="overlay"></div> - <div id="loading"> - <h4>Doing serious stuff!</h4> - Please wait... while we upgrade your osTicket installation! - <div id="udb"><br><b>Smile!</b></div> - </div> diff --git a/setup/inc/upgrade-prereq.inc.php b/setup/inc/upgrade-prereq.inc.php new file mode 100644 index 0000000000000000000000000000000000000000..5f60cece25500679de83b01981ea05ac634949e9 --- /dev/null +++ b/setup/inc/upgrade-prereq.inc.php @@ -0,0 +1,50 @@ +<?php +if(!defined('SETUPINC')) die('Kwaheri!'); + +?> + <div id="main"> + <h1>osTicket Upgrade!</h1> + <font color="red"><b><?php echo $errors['err']; ?></b></font> + <div id="intro"> + <p>Thank you for being a loyal osTicket user!</p> + <p>The upgrade wizard will guide you every step of the way in the upgrade process. While we try to ensure that the upgrade process is straightforward and painless, we can't guarantee it will be the case for every user.</p> + </div> + <h2>Getting ready!</h2> + <p>Before we begin, we'll check your server configuration to make sure you meet the minimum requirements to run the latest version of osTicket.</p> + <h3>Prerequisites: <font color="red"><?php echo $errors['prereq']; ?></font></h3> + These items are necessary in order to use osTicket the latest version of osTicket. + <ul class="progress"> + <li class="<? echo $upgrader->check_php()?'yes':'no'; ?>"> + PHP v4.3 or greater - (<small><b><?php echo PHP_VERSION; ?></b></small>)</li> + <li class="<? echo $upgrader->check_mysql()?'yes':'no'; ?>"> + MySQL v4.4 or greater - (<small><b><?php echo extension_loaded('mysql')?'module loaded':'missing!'; ?></b></small>)</li> + </ul> + <h3>Higly Recommended:</h3> + We hightly recommend that you follow the steps below. + <ul> + <li>Take osTicket offline momentarily during upgrade.</li> + <li>Backup the current database, if you haven't done so already.</li> + <li>Be patient the upgrade process will take a couple of seconds.</li> + </ul> + <div id="bar"> + <form method="post" action="upgrade.php" id="prereq"> + <input type="hidden" name="s" value="prereq"> + <input class="btn" type="submit" name="submit" value="Start Upgrade Now »"> + </form> + </div> + </div> + <div id="sidebar"> + <h3>Upgrade Tips</h3> + <p>1. Remember to backup your osTicket database</p> + <p>2. Take osTicket offline momentarily</p> + <p>3. If you experience any problems, you can always restore your files/dabase backup.</p> + <p>4. We can help, feel free to <a href="http://osticket.com/support/" target="_blank">contact us </a> for professional help.</p> + + </div> + + <div id="overlay"></div> + <div id="loading"> + <h4>Doing stuff!</h4> + Please wait... while we upgrade your osTicket installation! + <div id="udb"></div> + </div> diff --git a/setup/inc/upgrade.inc.php b/setup/inc/upgrade.inc.php index e5b8ba77bef7da18c547820031d1ca294b2b4dea..6f05cd169c66d49163908d8a6c6bef9d5b9a1a18 100644 --- a/setup/inc/upgrade.inc.php +++ b/setup/inc/upgrade.inc.php @@ -1,50 +1,40 @@ <?php -if(!defined('SETUPINC')) die('Kwaheri!'); +if(!defined('SETUPINC') || !$upgrader) die('Kwaheri!'); +$action=$upgrader->getNextAction(); ?> <div id="main"> - <h1>osTicket Upgrade!</h1> - <font color="red"><b><?php echo $errors['err']; ?></b></font> + <h1>osTicket Upgrade</h1> <div id="intro"> - <p>Thank you for being a loyal osTicket user!</p> - <p>The upgrade wizard will guide you every step of the way in the upgrade process. While we try to ensure that the upgrade process is straightforward and painless, we can't guarantee it will be the case for every user.</p> + <p>Thank you for taking the time to upgrade your osTicket intallation!</p> + <p>Please don't cancel or close the browser, any errors at this + stage will be fatal.</p> </div> - <h2>Getting ready!</h2> - <p>Before we begin, we'll check your server configuration to make sure you meet the minimum requirements to run the latest version of osTicket.</p> - <h3>Prerequisites: <font color="red"><?php echo $errors['prereq']; ?></font></h3> - These items are necessary in order to use osTicket the latest version of osTicket. - <ul class="progress"> - <li class="<? echo $upgrader->check_php()?'yes':'no'; ?>"> - PHP v4.3 or greater - (<small><b><?php echo PHP_VERSION; ?></b></small>)</li> - <li class="<? echo $upgrader->check_mysql()?'yes':'no'; ?>"> - MySQL v4.4 or greater - (<small><b><?php echo extension_loaded('mysql')?'module loaded':'missing!'; ?></b></small>)</li> - </ul> - <h3>Higly Recommended:</h3> - We hightly recommend that you follow the steps below. + <h2><?php echo $action ?></h2> + <p>The upgrade wizard will now attempt to upgrade your database and core settings!</p> <ul> - <li>Take osTicket offline momentarily during upgrade.</li> - <li>Backup the current database, if you haven't done so already.</li> - <li>Be patient the upgrade process will take a couple of seconds.</li> + <li>Database enhancements</li> + <li>New and updated features</li> + <li>Enhance settings and security</li> </ul> <div id="bar"> <form method="post" action="upgrade.php" id="upgrade"> - <input type="hidden" name="s" value="prereq"> - <input class="btn" type="submit" name="submit" value="Start Upgrade Now »"> + <input type="hidden" name="s" value="upgrade"> + <input type="hidden" name="sh" value="<?php echo $upgrader->getSchemaSignature(); ?>"> + <input class="btn" type="submit" name="submit" value="Do It Now!"> </form> </div> </div> <div id="sidebar"> <h3>Upgrade Tips</h3> - <p>1. Remember to backup your osTicket database</p> - <p>2. Take osTicket offline momentarily</p> - <p>3. If you experience any problems, you can always restore your files/dabase backup.</p> - <p>4. We can help, feel free to <a href="http://osticket.com/support/" target="_blank">contact us </a> for professional help.</p> - + <p>1. Be patient the process will take a couple of seconds.</p> + <p>2. If you experience any problems, you can always restore your files/dabase backup.</p> + <p>3. We can help, feel free to <a href="http://osticket.com/support/" target="_blank">contact us </a> for professional help.</p> </div> <div id="overlay"></div> <div id="loading"> - <h4>Doing stuff!</h4> + <h4><?php echo $action; ?></h4> Please wait... while we upgrade your osTicket installation! - <div id="udb"></div> + <div id="msg" style="font-weight: bold;padding-top:10px;">Smile!</div> </div> diff --git a/setup/install.php b/setup/install.php index 27b1388933d03ef9c0db5690dd147213848d750f..d019598e55de7099c9dbb517b4a9aa1663886ad0 100644 --- a/setup/install.php +++ b/setup/install.php @@ -15,6 +15,9 @@ **********************************************************************/ require('setup.inc.php'); +require_once INC_DIR.'class.installer.php'; + + //define('OSTICKET_CONFIGFILE','../include/ost-config.php'); //osTicket config file full path. define('OSTICKET_CONFIGFILE','../include/ost-config.php'); //XXX: Make sure the path is corrent b4 releasing. diff --git a/setup/js/setup.js b/setup/js/setup.js index 5d274ea3198bbec310c20abef16ac68df51ee270..b1f8e08c3aa48397206c43ad854fc3bf4815473c 100644 --- a/setup/js/setup.js +++ b/setup/js/setup.js @@ -13,30 +13,30 @@ jQuery(function($) { left : ($(window).width() / 2 - 160) }); - $('form#install, form#upgrade, form#attachments').submit(function(e) { + $('form#install').submit(function(e) { $('input[type=submit]', this).attr('disabled', 'disabled'); $('#overlay, #loading').show(); return true; }); - $('form#cleanup').submit(function(e) { + $('form#upgrade').submit(function(e) { e.preventDefault(); var form = $(this); $('input[type=submit]', this).attr('disabled', 'disabled'); $('#overlay, #loading').show(); - doCleanup('upgrade',form.attr('action')); + doTasks('upgrade.php',form.serialize()); + return false; }); - - function doCleanup(type,url) { + function doTasks(url, data) { function _lp(count) { $.ajax({ type: 'GET', - url: 'cleanup.php', + url: 'p.php', async: true, cache: false, - data: {c:count,type:type}, + data: data, dataType: 'text', success: function(res) { if (res) { @@ -45,16 +45,17 @@ jQuery(function($) { }, statusCode: { 200: function() { - setTimeout(function() { _lp(count+1); },2); + setTimeout(function() { _lp(count+1); }, 2); }, 304: function() { - $('#loading #msg').html("We're done... "); - setTimeout(function() { location.href =url;},1000); + $('#loading #msg').html("We're done... cleaning up!"); + setTimeout(function() { location.href =url;}, 3000); } }, - error: function(){ - alert("Something went wrong"); + error: function() { + $('#loading #msg').html("Something went wrong"); + setTimeout(function() { location.href =url;}, 1000); } }); }; diff --git a/setup/p.php b/setup/p.php new file mode 100644 index 0000000000000000000000000000000000000000..babeebb866f198e7fc78516a34133164d72a9b47 --- /dev/null +++ b/setup/p.php @@ -0,0 +1,69 @@ +<?php +/********************************************************************* + upgrader.php + + osTicket Upgrader Helper - called via ajax. + + Peter Rotich <peter@osticket.com> + Copyright (c) 2006-2012 osTicket + http://www.osticket.com + + Released under the GNU General Public License WITHOUT ANY WARRANTY. + See LICENSE.TXT for details. + + vim: expandtab sw=4 ts=4 sts=4: +**********************************************************************/ +function staffLoginPage($msg) { + Http::response(403, $msg?$msg:'Access Denied'); + exit; +} + +require '../scp/staff.inc.php'; +if(!$thisstaff or !$thisstaff->isAdmin()) { + staffLoginPage('Admin Access Required!'); + exit; +} + +define('SETUPINC', true); +define('INC_DIR', './inc/'); +define('SQL_DIR', INC_DIR.'sql/'); + +require_once INC_DIR.'class.upgrader.php'; + + +$upgrader = new Upgrader($cfg->getSchemaSignature(), TABLE_PREFIX, SQL_DIR); + +//Just report the next action on the first call. +if(!$_SESSION['ost_upgrader'][$upgrader->getShash()]['progress']) { + $_SESSION['ost_upgrader'][$upgrader->getShash()]['progress'] = $upgrader->getNextAction(); + Http::response(200, $upgrader->getNextAction()); + exit; +} + +if($upgrader->getNumPendingTasks()) { + if($upgrader->doTasks() && !$upgrader->getNumPendingTasks() && $cfg->isUpgradePending()) { + //Just reporting done...with tasks - break in between patches! + header("HTTP/1.1 304 Not Modified"); + exit; + } +} elseif($cfg->isUpgradePending() && $upgrader->isUpgradable()) { + $version = $upgrader->getNextVersion(); + if($upgrader->upgrade()) { + //We're simply reporting progress here - call back will report next action' + Http::response(200, "Upgraded to $version ... post-upgrade checks!"); + exit; + } +} elseif(!$cfg->isUpgradePending()) { + $upgrader->setState('done'); + session_write_close(); + header("HTTP/1.1 304 Not Modified"); + exit; +} + +if($upgrader->isAborted() || $upgrader->getErrors()) { + Http::response(416, "We have a problem ... wait a sec."); + exit; +} + +Http::response(200, $upgrader->getNextAction()); +?> diff --git a/setup/setup.inc.php b/setup/setup.inc.php index f2af40af61e1b7e94b9ae915eb1e81e103560594..44b2ad4d593f5521b66ad170c9e801a817cf74f1 100644 --- a/setup/setup.inc.php +++ b/setup/setup.inc.php @@ -52,10 +52,8 @@ ini_set('include_path', './'.PATH_SEPARATOR.INC_DIR.PATH_SEPARATOR.INCLUDE_DIR.P endif; #required files -require_once(INC_DIR.'class.setup.php'); require_once(INCLUDE_DIR.'class.validator.php'); require_once(INCLUDE_DIR.'class.format.php'); require_once(INCLUDE_DIR.'class.misc.php'); require_once(INCLUDE_DIR.'mysql.php'); - ?> diff --git a/setup/test/lint.php b/setup/test/lint.php index c25f7acec092a0a17e0dcf295173cc742b480329..4566c495a247874f538fc043cd777185e17d509c 100644 --- a/setup/test/lint.php +++ b/setup/test/lint.php @@ -9,7 +9,7 @@ function get_osticket_root_path() { if (file_exists($start . '/main.inc.php')) break; $start .= '/..'; } - return $start; + return realpath($start); } $root = get_osticket_root_path(); @@ -17,8 +17,7 @@ $root = get_osticket_root_path(); # Check PHP syntax across all php files function glob_recursive($pattern, $flags = 0) { $files = glob($pattern, $flags); - foreach (glob(dirname($pattern).'/*', GLOB_ONLYDIR|GLOB_NOSORT) - as $dir) { + foreach (glob(dirname($pattern).'/*', GLOB_ONLYDIR|GLOB_NOSORT) as $dir) { $files = array_merge($files, glob_recursive($dir.'/'.basename($pattern), $flags)); } @@ -26,7 +25,7 @@ function glob_recursive($pattern, $flags = 0) { } echo "PHP Syntax Errors: "; ob_start(); -$scripts=glob_recursive("$root/*/*.php"); +$scripts=glob_recursive("$root/*.php"); $exit=0; $syntax_errors=""; foreach ($scripts as $s) { @@ -63,4 +62,46 @@ if (strlen($lint_errors)) { } else { echo "\n"; } + +function find_function_calls($scripts) { + $calls=array(); + foreach ($scripts as $s) { + $lines = explode("\n", file_get_contents($s)); + $lineno=0; + foreach (explode("\n", file_get_contents($s)) as $line) { + $lineno++; $matches=array(); + preg_match_all('/-[>]([a-zA-Z0-9]*)\(/', $line, $matches, + PREG_SET_ORDER); + foreach ($matches as $m) { + $calls[] = array($s, $lineno, $line, $m[1]); + } + } + } + return $calls; +} + +$php_script_content=''; +foreach ($scripts as $s) { + $php_script_content .= file_get_contents($s); +} +echo "Access to undefined object methods: "; +ob_start(); +foreach (find_function_calls($scripts) as $call) { + list($file, $no, $line, $func) = $call; + if (!preg_match('/^\s*(\/\*[^*]*\*\/)?'."\s*function\s+&?\s*$func\\(/m", + $php_script_content)) { + print "$func: Definitely undefined, from $file:$no\n"; + } +} +$undef_func_errors = ob_get_clean(); + +if (strlen($undef_func_errors)) { + $undef_func_errors=str_replace("$root/", '', $undef_func_errors); + echo "FAIL\n"; + echo "-------------------------------------------------------\n"; + echo "$undef_func_errors"; + exit(); +} else { + echo "\n"; +} ?> diff --git a/setup/upgrade.php b/setup/upgrade.php index 6fc34cfd307cfcc9df319deb25101ec159f52d75..0406383707cfe245fd11aae9323ee1422d6d679e 100644 --- a/setup/upgrade.php +++ b/setup/upgrade.php @@ -13,5 +13,89 @@ vim: expandtab sw=4 ts=4 sts=4: **********************************************************************/ -die('Upgrade NOT supported for v1.7 DPR.'); +function staffLoginPage($msg) { + + $_SESSION['_staff']['auth']['dest']=THISPAGE; + $_SESSION['_staff']['auth']['msg']=$msg; + header('Location: ../scp/login.php'); + exit; +} + +require '../scp/staff.inc.php'; +if(!$thisstaff or !$thisstaff->isAdmin()) { + staffLoginPage('Admin Access Required!'); + exit; +} + +define('SETUPINC', true); +define('INC_DIR', './inc/'); +define('SQL_DIR', INC_DIR.'sql/'); + +require_once INC_DIR.'class.upgrader.php'; + +//$_SESSION['ost_upgrader']=null; +$upgrader = new Upgrader($cfg->getSchemaSignature(), TABLE_PREFIX, SQL_DIR); + + +$wizard=array(); +$wizard['title']='osTicket Upgrade Wizard'; +$wizard['tagline']='Upgrading osTicket to v'.$upgrader->getVersionVerbose(); +$wizard['logo']='logo-upgrade.png'; +$wizard['menu']=array('Upgrade Guide'=>'http://osticket.com/wiki/Upgrade_and_Migration', + 'Get Professional Help'=>'http://osticket.com/support'); +$errors=array(); +if($_POST && $_POST['s'] && !$upgrader->isAborted()) { + switch(strtolower($_POST['s'])) { + case 'prereq': + //XXX: check if it's upgradable version?? + if(!$cfg->isUpgradePending()) + $errors['err']=' Nothing to do! System already upgraded to the current version'; + elseif(!$upgrader->isUpgradable()) + $errors['err']='The upgrader does NOT support upgrading from the current vesion!'; + elseif($upgrader->check_prereq()) + $upgrader->setState('upgrade'); + else + $errors['prereq']='Minimum requirements not met!'; + break; + case 'upgrade': //Manual upgrade.... when JS (ajax) is not supported. + if($upgrader->getNumPendingTasks()) { + $upgrader->doTasks(); + } elseif($cfg->isUpgradePending() && $upgrader->isUpgradable()) { + $upgrader->upgrade(); + } elseif(!$cfg->isUpgradePending()) { + $upgrader->setState('done'); + } + + if(($errors=$upgrader->getErrors())) { + $upgrader->setState('aborted'); + } + break; + default: + $errors['err']='Unknown action!'; + } +} + +switch(strtolower($upgrader->getState())) { + case 'aborted': + $inc='upgrade-aborted.inc.php'; + break; + case 'upgrade': + $inc='upgrade.inc.php'; + break; + case 'done': + $inc='upgrade-done.inc.php'; + break; + default: + $inc='upgrade-prereq.inc.php'; + if($upgrader->isAborted()) + $inc='upgrade-aborted.inc.php'; + elseif(!$cfg->isUpgradePending()) + $errors['err']='Nothing to do! System already upgraded to the latest version'; + elseif(!$upgrader->isUpgradable()) + $errors['err']='The upgrader does NOT support upgrading from the current vesion!'; +} + +require(INC_DIR.'header.inc.php'); +require(INC_DIR.$inc); +require(INC_DIR.'footer.inc.php'); ?>