diff --git a/assets/default/css/theme.css b/assets/default/css/theme.css index dde40189e88227edaa3f1c18e4aec6b7e1bb67db..c6a6242df3d461805e06d366f451d3abf34a29ff 100644 --- a/assets/default/css/theme.css +++ b/assets/default/css/theme.css @@ -495,7 +495,7 @@ body { #ticketForm div.error label, #clientLogin div.error label { color: #a00; } -#ticketForm p, #clientLogin p { +#clientLogin p { clear: both; text-align: center; } @@ -646,7 +646,7 @@ a.refresh { #ticketThread table th { text-align: left; border-bottom: 1px solid #aaa; - font-size: 11pt; + font-size: 12px; padding: 5px; } #ticketThread table td { @@ -659,7 +659,7 @@ a.refresh { background: #ddd; } #ticketThread .info { - padding: 5px; + padding: 2px; background: #f9f9f9; border-top: 1px solid #ddd; height: 16px; @@ -667,16 +667,13 @@ a.refresh { } #ticketThread .info a { display: inline-block; - margin: 5px 20px 5px 0; + margin: 5px 10px 5px 0; padding-left: 24px; height: 16px; line-height: 16px; background-position: 0 50%; background-repeat: no-repeat; } -#ticketThread .info .pdf { - background-image: url('../images/filetypes/pdf.png?1319636863'); -} #reply { margin-top: 20px; diff --git a/attachment.php b/attachment.php new file mode 100644 index 0000000000000000000000000000000000000000..819ff5863b559522f70a65fd1c2fc56846e37d8a --- /dev/null +++ b/attachment.php @@ -0,0 +1,36 @@ +<?php +/********************************************************************* + attachment.php + + Attachments interface for clients. + Clients should never see the dir paths. + + 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('secure.inc.php'); +require_once(INCLUDE_DIR.'class.attachment.php'); +//Basic checks +if(!$thisclient + || !$_GET['id'] + || !$_GET['h'] + || !($attachment=Attachment::lookup($_GET['id'])) + || !($file=$attachment->getFile())) + die('Unknown attachment!'); + +//Validate session access hash - we want to make sure the link is FRESH! and the user has access to the parent ticket!! +$vhash=md5($attachment->getFileId().session_id().$file->getHash()); +if(strcasecmp(trim($_GET['h']),$vhash) + || !($ticket=$attachment->getTicket()) + || !$ticket->checkClientAccess($thisclient)) + die('Unknown or invalid attachment'); +//Download the file.. +$file->download(); + +?> diff --git a/captcha.php b/captcha.php new file mode 100644 index 0000000000000000000000000000000000000000..3ab68f746ddb378da077cac80b616caf6f69b129 --- /dev/null +++ b/captcha.php @@ -0,0 +1,20 @@ +<?php +/********************************************************************* + captcha.php + + Simply returns captcha image. + + 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('main.inc.php'); +require(INCLUDE_DIR.'class.captcha.php'); +$captcha = new Captcha(5,12,ROOT_DIR.'images/captcha/'); +echo $captcha->getImage(); +?> diff --git a/client.inc.php b/client.inc.php index 5461bd2f75246f57b710f74312eb45b9c4cfba9a..b714e93b44bd587f4d10a2f292b2d4890bc63a3f 100644 --- a/client.inc.php +++ b/client.inc.php @@ -51,7 +51,7 @@ require_once(INCLUDE_DIR.'class.dept.php'); //clear some vars $errors=array(); $msg=''; -$thisclient=null; +$thisclient=$nav=null; //Make sure the user is valid..before doing anything else. if($_SESSION['_client']['userID'] && $_SESSION['_client']['key']) $thisclient = new ClientSession($_SESSION['_client']['userID'],$_SESSION['_client']['key']); @@ -60,6 +60,8 @@ if($_SESSION['_client']['userID'] && $_SESSION['_client']['key']) if($thisclient && $thisclient->getId() && $thisclient->isValid()){ $thisclient->refreshSession(); } +/* Client specific defaults */ +define('PAGE_LIMIT',DEFAULT_PAGE_LIMIT); $nav = new UserNav($thisclient, 'home'); ?> diff --git a/images/bg.gif b/images/bg.gif deleted file mode 100644 index e20f31775822d9b0a7a01ddaf38cb1f48a60e6f2..0000000000000000000000000000000000000000 Binary files a/images/bg.gif and /dev/null differ diff --git a/images/fibres.png b/images/fibres.png deleted file mode 100644 index 7ad3ac27f71bdf17f637ffae3d86d36e24359764..0000000000000000000000000000000000000000 Binary files a/images/fibres.png and /dev/null differ diff --git a/images/home.gif b/images/home.gif deleted file mode 100644 index b25c0781dd0b8f66d4a9271b662061b54d7a9c4d..0000000000000000000000000000000000000000 Binary files a/images/home.gif and /dev/null differ diff --git a/images/icons/attachment.gif b/images/icons/attachment.gif deleted file mode 100644 index 4400e61e9812a3b2a070c89fc6fce7489c104e17..0000000000000000000000000000000000000000 Binary files a/images/icons/attachment.gif and /dev/null differ diff --git a/images/icons/refresh.gif b/images/icons/refresh.gif deleted file mode 100644 index 8268958a19e016741fffb8309b1174e548f5ce19..0000000000000000000000000000000000000000 Binary files a/images/icons/refresh.gif and /dev/null differ diff --git a/images/icons/thread.gif b/images/icons/thread.gif deleted file mode 100644 index bffd6b0b3cf5ce0cadfc38683ee7fb3fa0a5c82a..0000000000000000000000000000000000000000 Binary files a/images/icons/thread.gif and /dev/null differ diff --git a/images/icons/ticket.gif b/images/icons/ticket.gif deleted file mode 100644 index 4304ea7955091c46d9fe570faefc643773a5c1de..0000000000000000000000000000000000000000 Binary files a/images/icons/ticket.gif and /dev/null differ diff --git a/images/icons/ticket_source_email.gif b/images/icons/ticket_source_email.gif deleted file mode 100644 index 6b57605d47b7fc2e4729b5a6602bdf4768ad749f..0000000000000000000000000000000000000000 Binary files a/images/icons/ticket_source_email.gif and /dev/null differ diff --git a/images/icons/ticket_source_other.gif b/images/icons/ticket_source_other.gif deleted file mode 100644 index 4304ea7955091c46d9fe570faefc643773a5c1de..0000000000000000000000000000000000000000 Binary files a/images/icons/ticket_source_other.gif and /dev/null differ diff --git a/images/icons/ticket_source_phone.gif b/images/icons/ticket_source_phone.gif deleted file mode 100644 index b9aa8ed58a2993eab69a1c83fba78bb627e9004f..0000000000000000000000000000000000000000 Binary files a/images/icons/ticket_source_phone.gif and /dev/null differ diff --git a/images/icons/ticket_source_web.gif b/images/icons/ticket_source_web.gif deleted file mode 100644 index 1b7a5b909075fb879056d15468e407df21e0507d..0000000000000000000000000000000000000000 Binary files a/images/icons/ticket_source_web.gif and /dev/null differ diff --git a/images/lipsum.png b/images/lipsum.png deleted file mode 100644 index feb6a95fba027cb3d54883fc64ade1294c74bd09..0000000000000000000000000000000000000000 Binary files a/images/lipsum.png and /dev/null differ diff --git a/images/logo.png b/images/logo.png deleted file mode 100644 index 256344139522f7f8bc65b36e1ef0890e0fa3cf52..0000000000000000000000000000000000000000 Binary files a/images/logo.png and /dev/null differ diff --git a/images/logo2.jpg b/images/logo2.jpg deleted file mode 100644 index 16bc12ed36e707ace9d2d9e5443cc6d3a895711b..0000000000000000000000000000000000000000 Binary files a/images/logo2.jpg and /dev/null differ diff --git a/images/logout.gif b/images/logout.gif deleted file mode 100644 index 6dd774f09e48292379250ac0f1be17ccdb30baec..0000000000000000000000000000000000000000 Binary files a/images/logout.gif and /dev/null differ diff --git a/images/my_tickets.gif b/images/my_tickets.gif deleted file mode 100644 index ee2d25bbedd01ba5a64e9a66f5fc72b7b876f10c..0000000000000000000000000000000000000000 Binary files a/images/my_tickets.gif and /dev/null differ diff --git a/images/new_ticket.gif b/images/new_ticket.gif deleted file mode 100644 index 32d9636e71fa848c3b7d0f0d8eb559b78465ef22..0000000000000000000000000000000000000000 Binary files a/images/new_ticket.gif and /dev/null differ diff --git a/images/new_ticket_icon.jpg b/images/new_ticket_icon.jpg deleted file mode 100644 index 855eef0644245185b7b2f700d35d6a953aa65cd1..0000000000000000000000000000000000000000 Binary files a/images/new_ticket_icon.jpg and /dev/null differ diff --git a/images/poweredby.jpg b/images/poweredby.jpg deleted file mode 100644 index c98eb7d679b09975599711643cfcd3549c0540f6..0000000000000000000000000000000000000000 Binary files a/images/poweredby.jpg and /dev/null differ diff --git a/images/rainbow.png b/images/rainbow.png deleted file mode 100644 index c08f52edb522e5ec42c237994622f3b8520b428b..0000000000000000000000000000000000000000 Binary files a/images/rainbow.png and /dev/null differ diff --git a/images/refresh_btn.gif b/images/refresh_btn.gif deleted file mode 100644 index 8a33b22d9a9b026391e38a8bbb0d6834eb789a93..0000000000000000000000000000000000000000 Binary files a/images/refresh_btn.gif and /dev/null differ diff --git a/images/ticket_status.gif b/images/ticket_status.gif deleted file mode 100644 index 0775549996b70c79816e455e6850d1abf0e376ab..0000000000000000000000000000000000000000 Binary files a/images/ticket_status.gif and /dev/null differ diff --git a/images/ticket_status_icon.jpg b/images/ticket_status_icon.jpg deleted file mode 100644 index bf27b1f904418c311f05b27f118a55622be51b47..0000000000000000000000000000000000000000 Binary files a/images/ticket_status_icon.jpg and /dev/null differ diff --git a/images/verticalbar.jpg b/images/verticalbar.jpg deleted file mode 100644 index 2678913d2cdb9b8ec861e71396fcb92a552ff13a..0000000000000000000000000000000000000000 Binary files a/images/verticalbar.jpg and /dev/null differ diff --git a/images/view_closed_btn.gif b/images/view_closed_btn.gif deleted file mode 100644 index 6cd8f080a9007a85a2c0f08a6133f54a0253d6e8..0000000000000000000000000000000000000000 Binary files a/images/view_closed_btn.gif and /dev/null differ diff --git a/images/view_open_btn.gif b/images/view_open_btn.gif deleted file mode 100644 index 8ed6be9ce8159b20abfb0c9ea69b5235a4903b33..0000000000000000000000000000000000000000 Binary files a/images/view_open_btn.gif and /dev/null differ diff --git a/include/class.client.php b/include/class.client.php index f7ede15c52fe33b0a1a99dfdecb8081c64407d0d..e1057afa651472052589c0629fed129475d0e45e 100644 --- a/include/class.client.php +++ b/include/class.client.php @@ -4,8 +4,8 @@ Handles everything about client - The class will undergo major changes one client's accounts are used. - At the moment we will play off the email + ticket ID authentication. + NOTE: Please note that osTicket uses email address and ticket ID to authenticate the user*! + Client is modeled on the info of the ticket used to login . Peter Rotich <peter@osticket.com> Copyright (c) 2006-2012 osTicket @@ -19,75 +19,104 @@ class Client { - var $id; var $fullname; var $username; - var $passwd; var $email; - - var $udata; var $ticket_id; var $ticketID; - function Client($email,$id){ + var $ht; + + + function Client($email,$id) { $this->id =0; $this->load($id,$email); } - function isClient(){ - return TRUE; - } + function load($id=0, $email='') { - function load($id,$email=''){ + if(!$id && !($id=$this->getId())) + return false; - $sql='SELECT ticket_id,ticketID,name,email FROM '.TICKET_TABLE.' WHERE ticketID='.db_input($id); - if($email){ //don't validate...using whatever is entered. + $sql='SELECT ticket_id, ticketID, name, email, phone, phone_ext ' + .' FROM '.TICKET_TABLE + .' WHERE ticketID='.db_input($id); + if($email) $sql.=' AND email='.db_input($email); - } - $res=db_query($sql); - if(!$res || !db_num_rows($res)) + + if(!($res=db_query($sql)) || !db_num_rows($res)) return NULL; - $row=db_fetch_array($res); - $this->udata=$row; - $this->id = $row['ticketID']; //placeholder - $this->ticket_id = $row['ticket_id']; - $this->ticketID = $row['ticketID']; - $this->fullname = ucfirst($row['name']); - $this->username = $row['email']; - $this->email = $row['email']; + $this->ht = db_fetch_array($res); + $this->id = $this->ht['ticketID']; //placeholder + $this->ticket_id = $this->ht['ticket_id']; + $this->ticketID = $this->ht['ticketID']; + $this->fullname = ucfirst($this->ht['name']); + $this->username = $this->ht['email']; + $this->email = $this->ht['email']; + + $this->stats = array(); return($this->id); } + function reload() { + return $this->load(); + } + + function isClient() { + return TRUE; + } - function getId(){ + function getId() { return $this->id; } - function getEmail(){ + function getEmail() { return $this->email; } - function getUserName(){ + function getUserName() { return $this->username; } - function getName(){ + function getName() { return $this->fullname; } + + function getPhone() { + return $this->ht['phone']; + } + + function getPhoneExt() { + return $this->ht['phone_ext']; + } function getTicketID() { return $this->ticketID; } + function getTicketStats() { + + if(!$this->stats['tickets']) + $this->stats['tickets'] = Ticket::getClientStats($this->getEmail()); + + return $this->stats['tickets']; + } + + function getNumTickets() { + return ($stats=$this->getTicketStats())?($stats['open']+$stats['closed']):0; + } + + function getNumOpenTickets() { + return ($stats=$this->getTicketStats())?$stats['open']:0; + } + /* ------------- Static ---------------*/ function lookup($id, $email) { return ($id && is_numeric($id) && ($c=new Client($id,$email)) && $c->getId()==$id)?$c:null; } - } - ?> diff --git a/include/class.config.php b/include/class.config.php index 1e3d7745ffaf9788715308564bcc676fc28ac845..37040ebca4372e993870537bb248e9fb48685a5a 100644 --- a/include/class.config.php +++ b/include/class.config.php @@ -32,17 +32,20 @@ class Config { $this->load($id); } - function load($id) { + function load($id=0) { + if(!$id && !($id=$this->getId())) + return false; - $sql='SELECT * FROM '.CONFIG_TABLE.' WHERE id='.db_input($id); - if($id && ($res=db_query($sql)) && db_num_rows($res)) { - $this->config=db_fetch_array($res); - $this->id=$this->config['id']; + $sql='SELECT * FROM '.CONFIG_TABLE + .' WHERE id='.db_input($id); + if(!($res=db_query($sql)) || !db_num_rows($res)) + return false; - return true; - } + + $this->config=db_fetch_array($res); + $this->id=$this->config['id']; - return false; + return true; } //Initialize some default values. @@ -52,10 +55,13 @@ class Config { } function reload() { - if($this->load($this->id)) - $this->init(); - } + if(!$this->load($this->getId())) + return false; + + $this->init(); + return true; + } function isHelpDeskOffline() { return !$this->isSystemOnline(); @@ -75,7 +81,7 @@ class Config { return '1.7 DPR'; } - function getSchemaVersion() { + function getSchemaSignature() { return $this->config['schema_signature']; } @@ -111,7 +117,7 @@ class Config { } function getId() { - return $this->config['id']; + return $this->id; } function getTitle() { @@ -145,6 +151,10 @@ class Config { function getPasswdResetPeriod() { return $this->config['passwd_reset_period']; } + + function showRelatedTickets() { + return $this->config['show_related_tickets']; + } function getClientTimeout() { return $this->getClientSessionTimeout(); diff --git a/include/class.faq.php b/include/class.faq.php index 99d6def270ef2f54340dda2cea0f9929a8712f5e..7e23803dc458272ed7f81184c190213ddabd0e85 100644 --- a/include/class.faq.php +++ b/include/class.faq.php @@ -192,7 +192,7 @@ class FAQ { /* The h key must match validation in file.php */ $hash=$attachment['hash'].md5($attachment['id'].session_id().$attachment['hash']); if($attachment['size']) - $size=sprintf('(<i>%s</i>)',Format::file_size($attachment['size'])); + $size=sprintf(' <small>(<i>%s</i>)</small>',Format::file_size($attachment['size'])); $str.=sprintf('<a class="Icon file" href="file.php?h=%s" target="%s">%s</a>%s %s', $hash, $target, Format::htmlchars($attachment['name']), $size, $separator); diff --git a/include/class.file.php b/include/class.file.php index 91bd1cddce71f1438580bdffd9bf9782ffe125e9..b9bfbe1b7d2975ebdcc467bfb826ed35b8f1ec75 100644 --- a/include/class.file.php +++ b/include/class.file.php @@ -138,6 +138,7 @@ class AttachmentFile { exit(); } + /* Function assumes the files types have been validated */ function upload($file) { if(!$file['name'] || !is_uploaded_file($file['tmp_name'])) diff --git a/include/class.filter.php b/include/class.filter.php index 9b9d7279052ad0e5624642cb9f9f1c2ed127a6c5..4f18e96514c307077b7300a02674f8ad1698039e 100644 --- a/include/class.filter.php +++ b/include/class.filter.php @@ -260,7 +260,7 @@ class Filter { # Set owning department (?) if ($this->getDeptId()) $ticket['deptId']=$this->getDeptId(); # Set ticket priority (?) - if ($this->getPriorityId()) $ticket['pri']=$this->getPriorityId(); + if ($this->getPriorityId()) $ticket['priorityId']=$this->getPriorityId(); # Set SLA plan (?) if ($this->getSLAId()) $ticket['slaId']=$this->getSLAId(); # Auto-assign to (?) diff --git a/include/class.nav.php b/include/class.nav.php index 561fc963dcd80165bc755fd96588907a3e06a1ac..a3b719f08d6bec16f6a2a7bb3fb264b1730c2f13 100644 --- a/include/class.nav.php +++ b/include/class.nav.php @@ -263,15 +263,24 @@ class UserNav { $navs = array(); $user = $this->user; - $navs['home']=array('desc'=>'Support Center Home','href'=>'index.php','title'=>''); + $navs['home']=array('desc'=>'Support Center Home','href'=>'index.php','title'=>''); if($cfg && $cfg->isKnowledgebaseEnabled()) $navs['kb']=array('desc'=>'Knowledgebase','href'=>'kb/index.php','title'=>''); - $navs['new']=array('desc'=>'Open New Ticket','href'=>'open.php','title'=>''); - if($user && $user->isValid()) - $navs['tickets']=array('desc'=>'My Tickets','href'=>'tickets.php','title'=>''); - else + $navs['new']=array('desc'=>'Open New Ticket','href'=>'open.php','title'=>''); + if($user && $user->isValid()) { + if($cfg && $cfg->showRelatedTickets()) { + $navs['tickets']=array('desc'=>sprintf('My Tickets (%d)',$user->getNumTickets()), + 'href'=>'tickets.php', + 'title'=>'Show all tickets'); + } else { + $navs['tickets']=array('desc'=>'View Ticket Thread', + 'href'=>sprintf('tickets.php?id=%d',$user->getTicketID()), + 'title'=>'View ticket status'); + } + } else { $navs['status']=array('desc'=>'Check Ticket Status','href'=>'view.php','title'=>''); + } $this->navs=$navs; } diff --git a/include/class.staff.php b/include/class.staff.php index bfb0b79d2735c32b2410845fba1f0f89490bf0ba..9968965991fc024caa326747da423a01d0202eb8 100644 --- a/include/class.staff.php +++ b/include/class.staff.php @@ -37,15 +37,18 @@ class Staff { if(!$var && !($var=$this->getId())) return false; - $sql='SELECT staff.*,grp.*,tz.offset as tz_offset,TIME_TO_SEC(TIMEDIFF(NOW(),IFNULL(staff.passwdreset,staff.created))) as passwd_change_sec '. - 'FROM '.STAFF_TABLE.' staff '. - 'LEFT JOIN '.GROUP_TABLE.' grp ON(grp.group_id=staff.group_id) '. - 'LEFT JOIN '.TIMEZONE_TABLE.' tz ON(tz.id=staff.timezone_id) '; + $sql='SELECT staff.*, grp.*, tz.offset as tz_offset ' + .' ,TIME_TO_SEC(TIMEDIFF(NOW(),IFNULL(staff.passwdreset,staff.created))) as passwd_change_sec ' + .' FROM '.STAFF_TABLE.' staff ' + .' LEFT JOIN '.GROUP_TABLE.' grp ON(grp.group_id=staff.group_id) ' + .' LEFT JOIN '.TIMEZONE_TABLE.' tz ON(tz.id=staff.timezone_id) '; + $sql.=sprintf('WHERE %s=%s',is_numeric($var)?'staff_id':'username',db_input($var)); if(!($res=db_query($sql)) || !db_num_rows($res)) return NULL; + $this->ht=db_fetch_array($res); $this->id = $this->ht['staff_id']; $this->teams =$this->ht['teams']=$this->getTeams(); diff --git a/include/class.ticket.php b/include/class.ticket.php index 2c111cec2f5a733716c73d7c2a03402690f7ff10..4801f1625594d030dd137861cfb4e4db7d9896e9 100644 --- a/include/class.ticket.php +++ b/include/class.ticket.php @@ -175,6 +175,18 @@ class Ticket{ || $staff->getId()==$this->getStaffId()); } + function checkClientAccess($client) { + global $cfg; + + if(!is_object($client) && !($client=Client::lookup($client))) + return false; + + if(!strcasecmp($client->getEmail(),$this->getEmail())) + return true; + + return ($cfg && $cfg->showRelatedTickets() && $client->getTicketId()==$ticket->getExtId()); + } + //Getters function getId(){ return $this->id; @@ -437,8 +449,10 @@ class Ticket{ function getRelatedTicketsCount(){ - $sql='SELECT count(*) FROM '.TICKET_TABLE.' WHERE email='.db_input($this->getEmail()); - return db_count($sql); + $sql='SELECT count(*) FROM '.TICKET_TABLE + .' WHERE email='.db_input($this->getEmail()); + + return db_result(db_query($sql)); } function getThreadCount() { @@ -488,7 +502,7 @@ class Ticket{ ON (msg.ticket_id=attach.ticket_id AND msg.msg_id=attach.ref_id AND ref_type="M") ' .' WHERE msg.ticket_id='.db_input($this->getId()) .' GROUP BY msg.msg_id ' - .' ORDER BY msg.created DESC '; + .' ORDER BY msg.created ASC '; $messages=array(); if(($res=db_query($sql)) && db_num_rows($res)) @@ -1193,7 +1207,9 @@ class Ticket{ $this->onMessage($autorespond); //must be called b4 sending alerts to staff. - if(!($tpl = $dept->getTemplate())) + $dept = $this->getDept(); + + if(!$dept || !($tpl = $dept->getTemplate())) $tpl= $cfg->getDefaultTemplate(); if(!($email=$cfg->getAlertEmail())) @@ -1458,10 +1474,14 @@ class Ticket{ - function lookup($id){ //Assuming local ID is the only lookup used! + function lookup($id) { //Assuming local ID is the only lookup used! return ($id && is_numeric($id) && ($ticket= new Ticket($id)) && $ticket->getId()==$id)?$ticket:null; } + function lookupByExtId($id) { + return self::lookup(self:: getIdByExtId($id)); + } + function genExtRandID() { global $cfg; @@ -1537,6 +1557,27 @@ class Ticket{ return db_fetch_array(db_query($sql)); } + + /* Quick client's tickets stats + @email - valid email. + */ + function getClientStats($email) { + + if(!$email || !Validator::is_email($email)) + return null; + + $sql='SELECT count(open.ticket_id) as open, count(closed.ticket_id) as closed ' + .' FROM '.TICKET_TABLE.' ticket ' + .' LEFT JOIN '.TICKET_TABLE.' open + ON (open.ticket_id=ticket.ticket_id AND open.status=\'open\') ' + .' LEFT JOIN '.TICKET_TABLE.' closed + ON (closed.ticket_id=ticket.ticket_id AND closed.status=\'closed\')' + .' WHERE ticket.email='.db_input($email); + + return db_fetch_array(db_query($sql)); + } + + //FIXME: Refactor the code for version 1.7 function update($var,&$errors) { global $cfg,$thisstaff; @@ -1650,7 +1691,7 @@ class Ticket{ break; case 'staff': $fields['deptId'] = array('type'=>'int', 'required'=>1, 'error'=>'Dept. required'); - $fields['topicId'] = array('type'=>'int', 'required'=>1, 'error'=>'Topic required'); + $fields['topicId'] = array('type'=>'int', 'required'=>1, 'error'=>'Topic required'); $fields['duedate'] = array('type'=>'date', 'required'=>0, 'error'=>'Invalid date - must be MM/DD/YY'); case 'api': $fields['source'] = array('type'=>'string', 'required'=>1, 'error'=>'Indicate source'); @@ -1660,10 +1701,10 @@ class Ticket{ break; default: # TODO: Return error message - $errors['origin'] = 'Invalid origin given'; + $errors['err']=$errors['origin'] = 'Invalid origin given'; } - $fields['pri'] = array('type'=>'int', 'required'=>0, 'error'=>'Invalid Priority'); - $fields['phone'] = array('type'=>'phone', 'required'=>0, 'error'=>'Valid phone # required'); + $fields['priorityId'] = array('type'=>'int', 'required'=>0, 'error'=>'Invalid Priority'); + $fields['phone'] = array('type'=>'phone', 'required'=>0, 'error'=>'Valid phone # required'); if(!Validator::process($fields, $vars, $errors) && !$errors['err']) $errors['err'] ='Missing or invalid data - check the errors and try again'; @@ -1703,7 +1744,8 @@ class Ticket{ if (isset($vars['autorespond'])) $autorespond=$vars['autorespond']; //check ticket limits..if limit set is >0 - //TODO: Base ticket limits on SLA... XXX: move it elsewhere?? + //TODO: XXX: move it elsewhere?? Client::checkMaxOpenTickets($email,$vars) + if($vars['email'] && !$errors && $cfg->getMaxOpenTickets()>0 && strcasecmp($origin,'staff')){ $openTickets=Ticket::getOpenTicketsByEmail($vars['email']); if($openTickets>=$cfg->getMaxOpenTickets()) { @@ -1804,14 +1846,6 @@ class Ticket{ //post the message. $msgid=$ticket->postMessage($vars['message'],$source,$vars['mid'],$vars['header'],true); - //TODO: recover from postMessage error?? - - //Upload attachments...web based. - XXX: Assumes user uploaded attachments!! XXX: move it to client interface. - if($_FILES['attachment']['name'] && $cfg->allowOnlineAttachments() && $msgid) { - if(!$cfg->allowAttachmentsOnlogin() || ($cfg->allowAttachmentsOnlogin() && ($thisuser && $thisuser->isValid()))) { - $ticket->uploadAttachment($_FILES['attachment'],$msgid,'M'); - } - } // Configure service-level-agreement for this ticket $ticket->selectSLAId($vars['slaId']); diff --git a/include/class.topic.php b/include/class.topic.php index 59159c8c90a5501150f22342fdf886ed5a729330..40ab8096bc1831b821ea37754b18e3d1a1a22e3e 100644 --- a/include/class.topic.php +++ b/include/class.topic.php @@ -135,6 +135,10 @@ class Topic { return $topics; } + function getPublicHelpTopics() { + return self::getHelpTopics(true); + } + function getIdByName($topic){ $sql='SELECT topic_id FROM '.TOPIC_TABLE.' WHERE topic='.db_input($topic); diff --git a/include/client/header.inc.php b/include/client/header.inc.php index ad88a0c80d13cb9655a5b113d28c5de94943b102..65966c838279f9174536bba87f01d5f5c3526cd4 100644 --- a/include/client/header.inc.php +++ b/include/client/header.inc.php @@ -21,8 +21,14 @@ header("Content-Type: text/html; charset=UTF-8\r\n"); <a id="logo" href="<?php echo ROOT_PATH; ?>index.php" title="Support Center"><img src="<?php echo ASSETS_PATH; ?>images/logo.png" border=0 alt="Support Center"></a> <p> <?php - if($thisclient && is_object($thisclient) && $thisclient->isValid()) { ?> - <a href="<?php echo ROOT_PATH; ?>tickets.php">My Tickets</a> - + if($thisclient && is_object($thisclient) && $thisclient->isValid()) { + echo $thisclient->getName().' - '; + ?> + <?php + if($cfg->showRelatedTickets()) {?> + <a href="<?php echo ROOT_PATH; ?>tickets.php">My Tickets <b>(<?php echo $thisclient->getNumTickets(); ?>)</b></a> - + <?php + } ?> <a href="<?php echo ROOT_PATH; ?>logout.php">Log Out</a> <?php }elseif($nav){ ?> diff --git a/include/client/kb-category.inc.php b/include/client/kb-category.inc.php index f166fb5bdf8a1f528e56b965c5c32dca3e16dd8f..50a51782f214b8fc28b78f54afdd005c3f1a71df 100644 --- a/include/client/kb-category.inc.php +++ b/include/client/kb-category.inc.php @@ -1,34 +1,31 @@ <?php if(!defined('OSTCLIENTINC') || !$category || !$category->isPublic()) die('Access Denied'); - ?> -<div style="width:700;padding-top:10px; float:left;"> - <h2>Frequently Asked Questions</h2> -</div> -<div style="float:right;text-align:right;padding-top:5px;padding-right:5px;"> </div> -<div class="clear"></div> -<br> -<div><strong><?php echo $category->getName() ?></strong></div> +<h1><strong><?php echo $category->getName() ?></strong></h1> <p> <?php echo Format::safe_html($category->getDescription()); ?> </p> <hr> <?php -$sql='SELECT faq.faq_id, question ' +$sql='SELECT faq.faq_id, question, count(attach.file_id) as attachments ' .' FROM '.FAQ_TABLE.' faq ' .' LEFT JOIN '.FAQ_ATTACHMENT_TABLE.' attach ON(attach.faq_id=faq.faq_id) ' .' WHERE faq.ispublished=1 AND faq.category_id='.db_input($category->getId()) .' GROUP BY faq.faq_id'; if(($res=db_query($sql)) && db_num_rows($res)) { - echo '<div id="faq"> + echo ' + <h2>Frequently Asked Questions</h2> + <div id="faq"> <ol>'; while($row=db_fetch_array($res)) { + $attachments=$row['attachments']?'<span class="Icon file"></span>':''; echo sprintf(' - <li><a href="faq.php?id=%d" >%s</a></li>', - $row['faq_id'],Format::htmlchars($row['question'])); + <li><a href="faq.php?id=%d" >%s %s</a></li>', + $row['faq_id'],Format::htmlchars($row['question']), $attachments); } echo ' </ol> - </div>'; + </div> + <p><a class="back" href="index.php">« Go Back</a></p>'; }else { echo '<strong>Category does not have any FAQs. <a href="index.php">Back To Index</a></strong>'; } diff --git a/include/client/knowledgebase.inc.php b/include/client/knowledgebase.inc.php index 0af99ba21b1d92532a6063e175e9cf0fdc69c2c9..83484e95de818d732a67fed39b980fd5e9262e95 100644 --- a/include/client/knowledgebase.inc.php +++ b/include/client/knowledgebase.inc.php @@ -1,5 +1,6 @@ <?php if(!defined('OSTCLIENTINC')) die('Access Denied'); + ?> <h1>Frequently Asked Questions</h1> <form action="index.php" method="get" style="padding-top:15px;"> @@ -14,6 +15,7 @@ if(!defined('OSTCLIENTINC')) die('Access Denied'); $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 '; @@ -40,6 +42,7 @@ if(!defined('OSTCLIENTINC')) die('Access Denied'); $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 '; @@ -88,7 +91,7 @@ if($_REQUEST['q'] || $_REQUEST['cid'] || $_REQUEST['topicId']) { //Search. } else { //Category Listing. $sql='SELECT cat.category_id, cat.name, cat.description, cat.ispublic, count(faq.faq_id) as faqs ' .' FROM '.FAQ_CATEGORY_TABLE.' cat ' - .' LEFT JOIN '.FAQ_TABLE.' faq ON(faq.category_id=cat.category_id) ' + .' LEFT JOIN '.FAQ_TABLE.' faq ON(faq.category_id=cat.category_id AND faq.ispublished=1) ' .' WHERE cat.ispublic=1 ' .' GROUP BY cat.category_id ' .' HAVING faqs>0 ' diff --git a/include/client/open.inc.php b/include/client/open.inc.php index fd31bc9b81f907204134114e1aed59d3fc728cb6..9c2a82b4706e1fc83253471eea8224e47cd7b382 100644 --- a/include/client/open.inc.php +++ b/include/client/open.inc.php @@ -1,21 +1,40 @@ <?php -if(!defined('OSTCLIENTINC')) die('Access Denied'); //Say bye to our friend.. +if(!defined('OSTCLIENTINC')) die('Access Denied!'); +$info=array(); +if($thisclient && $thisclient->isValid()) { + $info=array('name'=>$thisclient->getName(), + 'email'=>$thisclient->getEmail(), + 'phone'=>$thisclient->getPhone(), + 'phone_ext'=>$thisclient->getPhoneExt()); +} -$info=($_POST && $errors)?Format::htmlchars($_POST):array(); +$info=($_POST && $errors)?Format::htmlchars($_POST):$info; ?> - <h1>Open a New Ticket</h1> <p>Please fill in the form below to open a new ticket.</p> <form id="ticketForm" method="post" action="open.php" enctype="multipart/form-data"> + <input type="hidden" name="a" value="open"> <div> <label for="name" class="required">Full Name:</label> + <?php + if($thisclient && $thisclient->isValid()) { + echo $thisclient->getName(); + } else { ?> <input id="name" type="text" name="name" size="30" value="<?php echo $info['name']; ?>"> <font class="error">* <?php echo $errors['name']; ?></font> + <?php + } ?> </div> <div> - <label for="email" class="required">E-Mail Address:</label> + <label for="email" class="required">Email Address:</label> + <?php + if($thisclient && $thisclient->isValid()) { + echo $thisclient->getEmail(); + } else { ?> <input id="email" type="text" name="email" size="30" value="<?php echo $info['email']; ?>"> <font class="error">* <?php echo $errors['email']; ?></font> + <?php + } ?> </div> <div> <label for="phone">Telephone:</label> @@ -30,16 +49,14 @@ $info=($_POST && $errors)?Format::htmlchars($_POST):array(); <select id="topicId" name="topicId"> <option value="" selected="selected">— Select a Help Topics —</option> <?php - $sql='SELECT topic_id,topic FROM '.TOPIC_TABLE.' WHERE isactive=1 ORDER BY topic'; - if(($res=db_query($sql)) && db_num_rows($res)) { - while (list($topicId,$topic) = db_fetch_row($res)){ - $selected = ($info['topicId']==$topicId)?'selected="selected"':''; ?> - <option value="<?php echo $topicId; ?>"<?php echo $selected; ?>><?php echo $topic; ?></option> - <?php - } - }else{ ?> - <option value="0" >General Inquiry</option> - <?php } ?> + if($topics=Topic::getPublicHelpTopics()) { + foreach($topics as $id =>$name) { + echo sprintf('<option value="%d" %s>%s</option>', + $id, ($info['topicId']==$id)?'selected="selected"':'', $name); + } + } else { ?> + <option value="0" >General Inquiry</option> + <?php } ?> </select> <font class="error">* <?php echo $errors['topicId']; ?></font> </div> @@ -58,35 +75,41 @@ $info=($_POST && $errors)?Format::htmlchars($_POST):array(); <textarea id="message" cols="60" rows="8" name="message"><?php echo $info['message']; ?></textarea> </div> <?php if(($cfg->allowOnlineAttachments() && !$cfg->allowAttachmentsOnlogin()) - || ($cfg->allowAttachmentsOnlogin() && ($thisuser && $thisuser->isValid()))) { ?> + || ($cfg->allowAttachmentsOnlogin() && ($thisclient && $thisclient->isValid()))) { ?> <div> - <label for="attachment">Attachments:</label> - <input id="attachment" type="file" name="attachment"><font class="error"> <?php echo $errors['attachment']; ?></font> + <label for="attachments">Attachments:</label> + <span id="uploads"></span> + <input type="file" class="multifile" name="attachments[]" id="attachments" size="30" value="" /> + <font class="error"> <?php echo $errors['attachments']; ?></font> </div> <?php } ?> <?php - if($cfg && $cfg->allowPriorityChange()) { - $sql='SELECT priority_id,priority_desc FROM '.TICKET_PRIORITY_TABLE.' WHERE ispublic=1 ORDER BY priority_urgency DESC'; - if(($res=db_query($sql)) && db_num_rows($res)) {?> - <div> + if($cfg->allowPriorityChange() && ($priorities=Priority::getPriorities())) { ?> + <div> <label for="priority">Ticket Priority:</label> <select id="priority" name="priorityId"> - <?php + <?php if(!$info['priorityId']) - $info['priorityId']=$cfg->getDefaultPriorityId(); //use system's default priority. - while($row=db_fetch_array($res)){ - $selected=$info['priorityId']==$row['priority_id']?'selected="selected"':''; - ?> - <option value="<?php echo $row['priority_id']; ?>" <?php echo $selected; ?> ><?php echo $row['priority_desc']; ?></option> - <?php } ?> + $info['priorityId'] = $cfg->getDefaultPriorityId(); //System default. + foreach($priorities as $id =>$name) { + echo sprintf('<option value="%d" %s>%s</option>', + $id, ($info['priorityId']==$id)?'selected="selected"':'', $name); + + } + ?> + + + </select> + <font class="error"> <?php echo $errors['priorityId']; ?></font> - </div> + + </div> <?php - } - } ?> + } + ?> <?php - if($cfg && $cfg->enableCaptcha() && (!$thisuser || !$thisuser->isValid())) { + if($cfg && $cfg->enableCaptcha() && (!$thisclient || !$thisclient->isValid())) { if($_POST && $errors && !$errors['captcha']) $errors['captcha']='Please re-enter the text again'; ?> @@ -101,7 +124,7 @@ $info=($_POST && $errors)?Format::htmlchars($_POST):array(); <?php } ?> <br> - <p> + <p style="padding-left:150px;"> <input type="submit" value="Create Ticket"> <input type="reset" value="Reset"> <input type="button" value="Cancel" onClick='window.location.href="index.php"'> diff --git a/include/client/tickets.inc.php b/include/client/tickets.inc.php new file mode 100644 index 0000000000000000000000000000000000000000..a360217167bde83dedcb4decb339677e3c5370d6 --- /dev/null +++ b/include/client/tickets.inc.php @@ -0,0 +1,172 @@ +<?php +if(!defined('OSTCLIENTINC') || !is_object($thisclient) || !$thisclient->isValid() || !$cfg->showRelatedTickets()) die('Access Denied'); + +$qstr='&'; //Query string collector +$status=null; +if(isset($_REQUEST['status'])) { //Query string status has nothing to do with the real status used below. + $qstr.='status='.urlencode($_REQUEST['status']); + //Status we are actually going to use on the query...making sure it is clean! + switch(strtolower($_REQUEST['status'])) { + case 'open': + case 'closed': + $status=strtolower($_REQUEST['status']); + break; + default: + $status=''; //ignore + } +} elseif($thisclient->getNumOpenTickets()) { + $status='open'; //Defaulting to open +} + +$sortOptions=array('id'=>'ticketID', 'name'=>'ticket.name', 'subject'=>'ticket.subject', + 'email'=>'ticket.email', 'status'=>'ticket.status', 'dept'=>'dept_name','date'=>'ticket.created'); +$orderWays=array('DESC'=>'DESC','ASC'=>'ASC'); +//Sorting options... +$order_by=$order=null; +$sort=($_REQUEST['sort'] && $sortOptions[strtolower($_REQUEST['sort'])])?strtolower($_REQUEST['sort']):'date'; +if($sort && $sortOptions[$sort]) + $order_by =$sortOptions[$sort]; + +$order_by=$order_by?$order_by:'ticket_created'; +if($_REQUEST['order'] && $orderWays[strtoupper($_REQUEST['order'])]) + $order=$orderWays[strtoupper($_REQUEST['order'])]; + +$order=$order?$order:'ASC'; +if($order_by && strpos($order_by,',')) + $order_by=str_replace(','," $order,",$order_by); + +$x=$sort.'_sort'; +$$x=' class="'.strtolower($order).'" '; + +$qselect='SELECT ticket.ticket_id,ticket.ticketID,ticket.dept_id,isanswered, dept.ispublic, ticket.subject, ticket.name, ticket.email '. + ',dept_name,ticket. status, ticket.source, ticket.created '; + +$qfrom='FROM '.TICKET_TABLE.' ticket ' + .' LEFT JOIN '.DEPT_TABLE.' dept ON (ticket.dept_id=dept.dept_id) '; + +$qwhere =' WHERE ticket.email='.db_input($thisclient->getEmail()); + +if($status){ + $qwhere.=' AND ticket.status='.db_input($status); +} + +$search=($_REQUEST['a']=='search' && $_REQUEST['q']); +if($search) { + $qstr.='&a='.urlencode($_REQUEST['a']).'&q='.urlencode($_REQUEST['q']); + if(is_numeric($_REQUEST['q'])) { + $qwhere.=" AND ticket.ticketID LIKE '$queryterm%'"; + } else {//Deep 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%'" + .' ) '; + $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 )'; + } +} + +$total=db_count('SELECT count(DISTINCT ticket.ticket_id) '.$qfrom.' '.$qwhere); +$pageNav=new Pagenate($total,$page, PAGE_LIMIT); +$pageNav->setURL('tickets.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&order='.urlencode($_REQUEST['order'])); + +//more stuff... +$qselect.=' ,count(attach_id) as attachments '; +$qfrom.=' LEFT JOIN '.TICKET_ATTACHMENT_TABLE.' attach ON ticket.ticket_id=attach.ticket_id '; +$qgroup=' GROUP BY ticket.ticket_id'; + +$query="$qselect $qfrom $qwhere $qgroup ORDER BY $order_by $order LIMIT ".$pageNav->getStart().",".$pageNav->getLimit(); +//echo $query; +$res = db_query($query); +$showing=($res && db_num_rows($res))?$pageNav->showing():""; +$showing.=($status)?(' '.ucfirst($status).' Tickets'):' All Tickets'; +if($search) + $showing="Search Results: $showing"; + +$negorder=$order=='DESC'?'ASC':'DESC'; //Negate the sorting + +?> +<h1>My Tickets</h1> +<br> +<form action="tickets.php" method="get" id="ticketSearchForm"> + <input type="hidden" name="a" value="search"> + <input type="text" name="q" size="20" value="<?php echo Format::htmlchars($_REQUEST['q']); ?>"> + <select name="status"> + <option value="">— Any Status —</option> + <option value="open" <?php echo ($status=='open')?'selected="selected"':'';?>>Open</option> + <option value="closed" <?php echo ($status=='closed')?'selected="selected"':'';?>>Closed</option> + </select> + <input type="submit" value="Go"> +</form> +<a class="refresh" href="<?php echo $_SERVER['REQUEST_URI']; ?>">Refresh</a> +<table id="ticketTable" width="800" border="0" cellspacing="0" cellpadding="0"> + <caption><?php echo $showing; ?></caption> + <thead> + <tr> + <th width="70" nowrap> + <a href="tickets.php?sort=ID&order=<?php echo $negorder; ?><?php echo $qstr; ?>" title="Sort By Ticket ID">Ticket #</a> + </th> + <th width="100"> + <a href="tickets.php?sort=date&order=<?php echo $negorder; ?><?php echo $qstr; ?>" title="Sort By Date">Create Date</a> + </th> + <th width="80"> + <a href="tickets.php?sort=status&order=<?php echo $negorder; ?><?php echo $qstr; ?>" title="Sort By Status">Status</a> + </th> + <th width="240"> + <a href="tickets.php?sort=subj&order=<?php echo $negorder; ?><?php echo $qstr; ?>" title="Sort By Subject">Subject</a> + </th> + <th width="150"> + <a href="tickets.php?sort=dept&order=<?php echo $negorder; ?><?php echo $qstr; ?>" title="Sort By Department">Department</a> + </th> + <th width="150">Phone Number</th> + </tr> + </thead> + <tbody> + <?php + if($res && ($num=db_num_rows($res))) { + $defaultDept=Dept::getDefaultDeptName(); //Default public dept. + while ($row = db_fetch_array($res)) { + $dept=$row['ispublic']?$row['dept_name']:$defaultDept; + $subject=Format::htmlchars(Format::truncate($row['subject'],40)); + if($row['attachments']) + $subject.=' <span class="Icon file"></span>'; + + $ticketID=$row['ticketID']; + if($row['isanswered'] && !strcasecmp($row['status'],'open')) { + $subject="<b>$subject</b>"; + $ticketID="<b>$ticketID</b>"; + } + $phone=Format::phone($row['phone']); + if($row['phone_ext']) + $phone.=' '.$row['phone_ext']; + ?> + <tr id="<?php echo $row['ticketID']; ?>"> + <td class="centered"> + <a class="Icon <?php echo strtolower($row['source']); ?>Ticket" title="<?php echo $row['email']; ?>" + href="tickets.php?id=<?php echo $row['ticketID']; ?>"><?php echo $ticketID; ?></a> + </td> + <td> <?=Format::db_date($row['created'])?></td> + <td> <?=ucfirst($row['status'])?></td> + <td> + <a href="tickets.php?id=<?php echo $row['ticketID']; ?>"><?php echo $subject; ?></a> + </td> + <td> <?=Format::truncate($dept,30)?></td> + <td><?php echo $phone; ?></td> + </tr> + <?php + } + + } else { + echo '<tr><td colspan="7">Your query did not match any records</td></tr>'; + } + ?> + </tbody> +</table> +<?php +if($res && $num>0) { + echo '<div> Page:'.$pageNav->getPageLinks().' </div>'; +} +?> diff --git a/include/client/view.inc.php b/include/client/view.inc.php new file mode 100644 index 0000000000000000000000000000000000000000..e720ed96bffa58c5d7321e7fe2544c7829a86678 --- /dev/null +++ b/include/client/view.inc.php @@ -0,0 +1,157 @@ +<?php +if(!defined('OSTCLIENTINC') || !$thisclient || !$ticket || !$ticket->checkClientAccess($thisclient)) die('Access Denied!'); + +$info=($_POST && $errors)?Format::htmlchars($_POST):array(); + +$dept = $ticket->getDept(); +//Making sure we don't leak out internal dept names +if(!$dept || !$dept->isPublic()) + $dept = $cfg->getDefaultDept(); + +?> +<table width="800" cellpadding="1" cellspacing="0" border="0" id="ticketInfo"> + <tr> + <td colspan="2" width="100%"> + <h1> + Ticket #<?php echo $ticket->getExtId(); ?> + <a href="view.php?id=<?php echo $ticket->getExtId(); ?>" title="Reload"><span class="Icon refresh"> </span></a> + </h1> + </td> + </tr> + <tr> + <td width="50%"> + <table class="infoTable" cellspacing="1" cellpadding="3" width="100%" border="0"> + <tr> + <th width="100">Ticket Status:</th> + <td><?php echo ucfirst($ticket->getStatus()); ?></td> + </tr> + <tr> + <th>Department:</th> + <td><?php echo Format::htmlchars($dept->getName()); ?></td> + </tr> + <tr> + <th>Create Date:</th> + <td><?php echo Format::db_datetime($ticket->getCreateDate()); ?></td> + </tr> + </table> + </td> + <td width="50%"> + <table class="infoTable" cellspacing="1" cellpadding="3" width="100%" border="0"> + <tr> + <th width="100">Name:</th> + <td><?php echo ucfirst($ticket->getName()); ?></td> + </tr> + <tr> + <th width="100">Email:</th> + <td><?php echo Format::htmlchars($ticket->getEmail()); ?></td> + </tr> + <tr> + <th>Phone:</th> + <td><?php echo $ticket->getPhoneNumber(); ?></td> + </tr> + </table> + </td> + </tr> +</table> +<br> +<h2>Subject:<?php echo Format::htmlchars($ticket->getSubject()); ?></h2> +<br> +<span class="Icon thread">Ticket Thread</span> +<div id="ticketThread"> +<?php +if($ticket->getThreadCount() && ($messages = $ticket->getMessages())) { + + foreach($messages as $message) {?> + + <table class="message" cellspacing="0" cellpadding="1" width="800" border="0"> + + <tr><th><?php echo Format::db_datetime($message['created']); ?></th></tr> + + <tr><td><?php echo Format::display($message['message']); ?></td></tr> + + <?php + + if($message['attachments'] && ($links=$ticket->getAttachmentsLinks($message['msg_id'],'M'))) { ?> + + <tr><td class="info"><?php echo $links; ?></td></tr> + + <?php + + } ?> + + </table> + <?php + if($message['responses'] && ($responses=$ticket->getResponses($message['msg_id']))) { + foreach($responses as $resp) { + $staff=$cfg->hideStaffName()?'staff':Format::htmlchars($resp['staff_name']); + ?> + <table class="response" cellspacing="0" cellpadding="1" width="100%" border="0"> + <tr> + <th><?php echo Format::db_datetime($resp['created']);?> - <?php echo $staff; ?></th> + </tr> + <tr><td><?php echo Format::display($resp['response']); ?></td></tr> + <?php + if($resp['attachments'] && ($links=$ticket->getAttachmentsLinks($resp['response_id'],'R'))) {?> + <tr><td class="info"><?php echo $links; ?></td></tr> + <?php + }?> + </table> + <? + } + } + } +} +?> +</div> +<div class="clear" style="padding-bottom:10px;"></div> +<?php if($errors['err']) { ?> + <div id="msg_error"><?php echo $errors['err']; ?></div> +<?php }elseif($msg) { ?> + <div id="msg_notice"><?php echo $msg; ?></div> +<?php }elseif($warn) { ?> + <div id="msg_warning"><?php echo $warn; ?></div> +<?php } ?> +<form id="reply" action="tickets.php?id=<?php echo $ticket->getExtId(); ?>#reply" name="reply" method="post" enctype="multipart/form-data"> + <h2>Post a Reply</h2> + <input type="hidden" name="id" value="<?php echo $ticket->getExtId(); ?>"> + <input type="hidden" name="a" value="reply"> + <table border="0" cellspacing="0" cellpadding="3" width="800"> + <tr> + <td width="160"> + <label>Message:</label> + </td> + <td width="640"> + <?php + if($ticket->isClosed()) { + $msg='<b>Ticket will be reopened on message post</b>'; + } else { + $msg='To best assist you, please be specific and detailed'; + } + ?> + <span id="msg"><em><?php echo $msg; ?> </em></span><font class="error">* <?php echo $errors['message']; ?></font><br/> + <textarea name="message" id="message" cols="50" rows="9" wrap="soft"><?php echo $info['message']; ?></textarea> + </td> + </tr> + <?php + if($cfg->allowOnlineAttachments()) { ?> + <tr> + <td width="160"> + <label for="attachment">Attachments:</label> + </td> + <td width="640" id="reply_form_attachments" class="attachments"> + <div class="uploads"> + </div> + <div class="file_input"> + <input type="file" name="attachments[]" size="30" value="" /> + </div> + </td> + </tr> + <?php + } ?> + </table> + <p style="padding-left:165px;"> + <input type="submit" value="Post Reply"> + <input type="reset" value="Reset"> + <input type="button" value="Cancel" onClick="history.go(-1)"> + </p> +</form> diff --git a/include/staff/api.inc.php b/include/staff/api.inc.php index 7463ad0956cbfbb02d2e4d3faa82cfa0cd6da35e..21eac469162af3d2cc9652d8e8255f230ee18460 100644 --- a/include/staff/api.inc.php +++ b/include/staff/api.inc.php @@ -1,146 +1,147 @@ -<?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. -$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 +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> + $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> + $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> + 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> + 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> + 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/apikeys.inc.php b/include/staff/apikeys.inc.php index 26468089d56016c34e8dfd1dfefc972f33854b29..d7063c749ce92c04cddc36f20902b88181ab51d4 100644 --- a/include/staff/apikeys.inc.php +++ b/include/staff/apikeys.inc.php @@ -25,10 +25,8 @@ $$x=' class="'.strtolower($order).'" '; $order_by="$order_column $order "; $total=db_count('SELECT count(*) FROM '.API_KEY_TABLE.' '); -$pagelimit=$thisstaff->getPageLimit(); -$pagelimit=$pagelimit?$pagelimit:PAGE_LIMIT; //true default...if all fails. $page=($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1; -$pageNav=new Pagenate($total,$page,$pagelimit); +$pageNav=new Pagenate($total,$page,PAGE_LIMIT); $pageNav->setURL('apikeys.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&order='.urlencode($_REQUEST['order'])); //Ok..lets roll...create the actual query $qstr.='&order='.($order=='DESC'?'ASC':'DESC'); diff --git a/include/staff/banlist.inc.php b/include/staff/banlist.inc.php index 5978964273ed573ca42fa817ed7eaf348ae143cb..ecef00ba4325e18339b4f733d82a34b38466b950 100644 --- a/include/staff/banlist.inc.php +++ b/include/staff/banlist.inc.php @@ -41,10 +41,8 @@ $$x=' class="'.strtolower($order).'" '; $order_by="$order_column $order "; $total=db_count('SELECT count(DISTINCT rule.id) '.$from.' '.$where); -$pagelimit=$thisstaff->getPageLimit(); -$pagelimit=$pagelimit?$pagelimit:PAGE_LIMIT; //true default...if all fails. $page=($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1; -$pageNav=new Pagenate($total,$page,$pagelimit); +$pageNav=new Pagenate($total, $page, PAGE_LIMIT); $pageNav->setURL('banlist.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&order='.urlencode($_REQUEST['order'])); $qstr.='&order='.($order=='DESC'?'ASC':'DESC'); $query="$select $from $where ORDER BY $order_by LIMIT ".$pageNav->getStart().",".$pageNav->getLimit(); diff --git a/include/staff/cannedreplies.inc.php b/include/staff/cannedreplies.inc.php index db44a79f3cc9470cdbdbd0746bd589a5bc16b44f..601e27d37f49646b4043b57a717abb64cb626b96 100644 --- a/include/staff/cannedreplies.inc.php +++ b/include/staff/cannedreplies.inc.php @@ -33,10 +33,8 @@ $$x=' class="'.strtolower($order).'" '; $order_by="$order_column $order "; $total=db_count('SELECT count(*) FROM '.CANNED_TABLE.' canned '); -$pagelimit=$thisstaff->getPageLimit(); -$pagelimit=$pagelimit?$pagelimit:PAGE_LIMIT; //true default...if all fails. $page=($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1; -$pageNav=new Pagenate($total,$page,$pagelimit); +$pageNav=new Pagenate($total, $page, PAGE_LIMIT); $pageNav->setURL('canned.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&order='.urlencode($_REQUEST['order'])); //Ok..lets roll...create the actual query $qstr.='&order='.($order=='DESC'?'ASC':'DESC'); diff --git a/include/staff/categories.inc.php b/include/staff/categories.inc.php index bba679898b0c5b8891486faa657eb73114f50f1f..a437338c20a156550487faf891324e2a16406562 100644 --- a/include/staff/categories.inc.php +++ b/include/staff/categories.inc.php @@ -28,10 +28,8 @@ $$x=' class="'.strtolower($order).'" '; $order_by="$order_column $order "; $total=db_count('SELECT count(*) FROM '.FAQ_CATEGORY_TABLE.' cat '); -$pagelimit=$thisstaff->getPageLimit(); -$pagelimit=$pagelimit?$pagelimit:PAGE_LIMIT; //true default...if all fails. $page=($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1; -$pageNav=new Pagenate($total,$page,$pagelimit); +$pageNav=new Pagenate($total, $page, PAGE_LIMIT); $pageNav->setURL('categories.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&order='.urlencode($_REQUEST['order'])); $qstr.='&order='.($order=='DESC'?'ASC':'DESC'); $query="$sql GROUP BY cat.category_id ORDER BY $order_by LIMIT ".$pageNav->getStart().",".$pageNav->getLimit(); diff --git a/include/staff/directory.inc.php b/include/staff/directory.inc.php index b687d811f2a8993c7eb8753fadb4efe5fe7668ad..c9d11a3d4bf1d8921b3261fc80d3e9a6a73616ae 100644 --- a/include/staff/directory.inc.php +++ b/include/staff/directory.inc.php @@ -52,10 +52,8 @@ $$x=' class="'.strtolower($order).'" '; $order_by="$order_column $order "; $total=db_count('SELECT count(DISTINCT staff.staff_id) '.$from.' '.$where); -$pagelimit=$thisstaff->getPageLimit(); -$pagelimit=$pagelimit?$pagelimit:PAGE_LIMIT; //true default...if all fails. $page=($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1; -$pageNav=new Pagenate($total,$page,$pagelimit); +$pageNav=new Pagenate($total, $page, PAGE_LIMIT); $pageNav->setURL('directory.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&order='.urlencode($_REQUEST['order'])); //Ok..lets roll...create the actual query $qstr.='&order='.($order=='DESC'?'ASC':'DESC'); diff --git a/include/staff/emails.inc.php b/include/staff/emails.inc.php index 44e277b468ad9879edb7fe528b7ba960e0762858..65d34d7b9bfb0b10acd983bfe41e5671932d3060 100644 --- a/include/staff/emails.inc.php +++ b/include/staff/emails.inc.php @@ -29,10 +29,8 @@ $$x=' class="'.strtolower($order).'" '; $order_by="$order_column $order "; $total=db_count('SELECT count(*) FROM '.EMAIL_TABLE.' email '); -$pagelimit=$thisstaff->getPageLimit(); -$pagelimit=$pagelimit?$pagelimit:PAGE_LIMIT; //true default...if all fails. $page=($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1; -$pageNav=new Pagenate($total,$page,$pagelimit); +$pageNav=new Pagenate($total, $page, PAGE_LIMIT); $pageNav->setURL('emails.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&order='.urlencode($_REQUEST['order'])); //Ok..lets roll...create the actual query $qstr.='&order='.($order=='DESC'?'ASC':'DESC'); diff --git a/include/staff/filters.inc.php b/include/staff/filters.inc.php index 4b9d6f31eb0e04f995ef7ffafde66a6a84bdb618..fb8a48d268a7705d5eb3a49b4076a6dcdb3b0b17 100644 --- a/include/staff/filters.inc.php +++ b/include/staff/filters.inc.php @@ -29,10 +29,8 @@ $$x=' class="'.strtolower($order).'" '; $order_by="$order_column $order "; $total=db_count('SELECT count(*) FROM '.EMAIL_FILTER_TABLE.' filter '); -$pagelimit=$thisstaff->getPageLimit(); -$pagelimit=$pagelimit?$pagelimit:PAGE_LIMIT; //true default...if all fails. $page=($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1; -$pageNav=new Pagenate($total,$page,$pagelimit); +$pageNav=new Pagenate($total, $page, PAGE_LIMIT); $pageNav->setURL('filters.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&order='.urlencode($_REQUEST['order'])); //Ok..lets roll...create the actual query $qstr.='&order='.($order=='DESC'?'ASC':'DESC'); diff --git a/include/staff/helptopics.inc.php b/include/staff/helptopics.inc.php index 51a7666889f562676910351c69edcf8e10f96b91..27ffde9bdacac59c2687b30b5046dde4255b1537 100644 --- a/include/staff/helptopics.inc.php +++ b/include/staff/helptopics.inc.php @@ -30,10 +30,8 @@ $$x=' class="'.strtolower($order).'" '; $order_by="$order_column $order "; $total=db_count('SELECT count(*) FROM '.TOPIC_TABLE.' topic '); -$pagelimit=$thisstaff->getPageLimit(); -$pagelimit=$pagelimit?$pagelimit:PAGE_LIMIT; //true default...if all fails. $page=($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1; -$pageNav=new Pagenate($total,$page,$pagelimit); +$pageNav=new Pagenate($total, $page, PAGE_LIMIT); $pageNav->setURL('helptopics.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&order='.urlencode($_REQUEST['order'])); //Ok..lets roll...create the actual query $qstr.='&order='.($order=='DESC'?'ASC':'DESC'); diff --git a/include/staff/settings-general.inc.php b/include/staff/settings-general.inc.php index ff5e058b1e36bdb2a7b51282201c9b5c3e633412..2e1e347bef5c45eab3826c2b263a59149cb32fc4 100644 --- a/include/staff/settings-general.inc.php +++ b/include/staff/settings-general.inc.php @@ -1,196 +1,197 @@ -<form action="settings.php?t=general" method="post" id="save"> -<input type="hidden" name="t" value="general" > -<table class="form_table settings_table" width="940" border="0" cellspacing="0" cellpadding="2"> - <thead> - <tr> - <th colspan="2"> - <h4>General Settings</h4> - <em>Offline mode will disable client interface and only allow admins to login to Staff Control Panel</em> - </th> - </tr> - </thead> - <tbody> - - <tr> - <td width="220" class="required">Helpdesk Status:</td> - <td> - <input type="radio" name="isonline" value="1" <?php echo $config['isonline']?'checked="checked"':''; ?> /><b>Online</b> (Active) - <input type="radio" name="isonline" value="0" <?php echo !$config['isonline']?'checked="checked"':''; ?> /><b>Offline</b> (Disabled) - <font class="error"> <?php echo $config['isoffline']?'osTicket offline':''; ?></font> - </td> - </tr> - <tr> - <td width="220" class="required">Helpdesk URL:</td> - <td> - <input type="text" size="40" name="helpdesk_url" value="<?php echo $config['helpdesk_url']; ?>"> - <font class="error">* <?php echo $errors['helpdesk_url']; ?></font></td> - </tr> - <tr> - <td width="220" class="required">Helpdesk Name/Title:</td> - <td><input type="text" size="40" name="helpdesk_title" value="<?php echo $config['helpdesk_title']; ?>"> - <font class="error">* <?php echo $errors['helpdesk_title']; ?></font></td> - </tr> - <tr> - <td width="220" class="required">Default Department:</td> - <td> - <select name="default_dept_id"> - <option value="">— Select Default Department —</option> +<form action="settings.php?t=general" method="post" id="save"> +<input type="hidden" name="t" value="general" > +<table class="form_table settings_table" width="940" border="0" cellspacing="0" cellpadding="2"> + <thead> + <tr> + <th colspan="2"> + <h4>General Settings</h4> + <em>Offline mode will disable client interface and only allow admins to login to Staff Control Panel</em> + </th> + </tr> + </thead> + <tbody> + + <tr> + <td width="220" class="required">Helpdesk Status:</td> + <td> + <input type="radio" name="isonline" value="1" <?php echo $config['isonline']?'checked="checked"':''; ?> /><b>Online</b> (Active) + <input type="radio" name="isonline" value="0" <?php echo !$config['isonline']?'checked="checked"':''; ?> /><b>Offline</b> (Disabled) + <font class="error"> <?php echo $config['isoffline']?'osTicket offline':''; ?></font> + </td> + </tr> + <tr> + <td width="220" class="required">Helpdesk URL:</td> + <td> + <input type="text" size="40" name="helpdesk_url" value="<?php echo $config['helpdesk_url']; ?>"> + <font class="error">* <?php echo $errors['helpdesk_url']; ?></font></td> + </tr> + <tr> + <td width="220" class="required">Helpdesk Name/Title:</td> + <td><input type="text" size="40" name="helpdesk_title" value="<?php echo $config['helpdesk_title']; ?>"> + <font class="error">* <?php echo $errors['helpdesk_title']; ?></font></td> + </tr> + <tr> + <td width="220" class="required">Default Department:</td> + <td> + <select name="default_dept_id"> + <option value="">— Select Default Department —</option> <?php - $sql='SELECT dept_id,dept_name FROM '.DEPT_TABLE.' WHERE ispublic=1'; - if(($res=db_query($sql)) && db_num_rows($res)){ - while (list($id,$name) = db_fetch_row($res)){ - $selected = ($config['default_dept_id']==$id)?'selected="selected"':''; ?> - <option value="<?php echo $id; ?>"<?php echo $selected; ?>><?php echo $name; ?> Dept</option> + $sql='SELECT dept_id,dept_name FROM '.DEPT_TABLE.' WHERE ispublic=1'; + if(($res=db_query($sql)) && db_num_rows($res)){ + while (list($id,$name) = db_fetch_row($res)){ + $selected = ($config['default_dept_id']==$id)?'selected="selected"':''; ?> + <option value="<?php echo $id; ?>"<?php echo $selected; ?>><?php echo $name; ?> Dept</option> <?php - } - } ?> - </select> <font class="error">* <?php echo $errors['default_dept_id']; ?></font> - </td> - </tr> - <tr> - <td width="220" class="required">Default Email Templates:</td> - <td> - <select name="default_template_id"> - <option value="">— Select Default Template —</option> + } + } ?> + </select> <font class="error">* <?php echo $errors['default_dept_id']; ?></font> + </td> + </tr> + <tr> + <td width="220" class="required">Default Email Templates:</td> + <td> + <select name="default_template_id"> + <option value="">— Select Default Template —</option> <?php - $sql='SELECT tpl_id,name FROM '.EMAIL_TEMPLATE_TABLE.' WHERE isactive=1 AND cfg_id='.db_input($cfg->getId()).' ORDER BY name'; - if(($res=db_query($sql)) && db_num_rows($res)){ - while (list($id,$name) = db_fetch_row($res)){ - $selected = ($config['default_template_id']==$id)?'selected="selected"':''; ?> - <option value="<?php echo $id; ?>"<?php echo $selected; ?>><?php echo $name; ?></option> + $sql='SELECT tpl_id,name FROM '.EMAIL_TEMPLATE_TABLE.' WHERE isactive=1 AND cfg_id='.db_input($cfg->getId()).' ORDER BY name'; + if(($res=db_query($sql)) && db_num_rows($res)){ + while (list($id,$name) = db_fetch_row($res)){ + $selected = ($config['default_template_id']==$id)?'selected="selected"':''; ?> + <option value="<?php echo $id; ?>"<?php echo $selected; ?>><?php echo $name; ?></option> <?php - } - } ?> - </select> <font class="error">* <?php echo $errors['default_template_id']; ?></font> - </td> - </tr> - - <tr><td>Default Page Size:</td> - <td> - <select name="max_page_size"> + } + } ?> + </select> <font class="error">* <?php echo $errors['default_template_id']; ?></font> + </td> + </tr> + + <tr><td>Default Page Size:</td> + <td> + <select name="max_page_size"> <?php - $pagelimit=$config['max_page_size']; - for ($i = 5; $i <= 50; $i += 5) { - ?> - <option <?php echo $config['max_page_size']==$i?'selected="selected"':''; ?> value="<?php echo $i; ?>"><?php echo $i; ?></option> + $pagelimit=$config['max_page_size']; + for ($i = 5; $i <= 50; $i += 5) { + ?> + <option <?php echo $config['max_page_size']==$i?'selected="selected"':''; ?> value="<?php echo $i; ?>"><?php echo $i; ?></option> <?php - } ?> - </select> - </td> - </tr> - <tr> - <td>Default Log Level:</td> - <td> - <select name="log_level"> - <option value=0 <?php echo $config['log_level'] == 0 ? 'selected="selected"':''; ?>>None (Disable Logger)</option> - <option value=3 <?php echo $config['log_level'] == 3 ? 'selected="selected"':''; ?>> DEBUG</option> - <option value=2 <?php echo $config['log_level'] == 2 ? 'selected="selected"':''; ?>> WARN</option> - <option value=1 <?php echo $config['log_level'] == 1 ? 'selected="selected"':''; ?>> ERROR</option> - </select> - <font class="error"> <?php echo $errors['log_level']; ?></font> - </td> - </tr> - <tr> - <td>Purge Logs:</td> - <td> - <select name="log_graceperiod"> - <option value=0 selected>Never Purge Logs</option> + } ?> + </select> + </td> + </tr> + <tr> + <td>Default Log Level:</td> + <td> + <select name="log_level"> + <option value=0 <?php echo $config['log_level'] == 0 ? 'selected="selected"':''; ?>>None (Disable Logger)</option> + <option value=3 <?php echo $config['log_level'] == 3 ? 'selected="selected"':''; ?>> DEBUG</option> + <option value=2 <?php echo $config['log_level'] == 2 ? 'selected="selected"':''; ?>> WARN</option> + <option value=1 <?php echo $config['log_level'] == 1 ? 'selected="selected"':''; ?>> ERROR</option> + </select> + <font class="error"> <?php echo $errors['log_level']; ?></font> + </td> + </tr> + <tr> + <td>Purge Logs:</td> + <td> + <select name="log_graceperiod"> + <option value=0 selected>Never Purge Logs</option> <?php - for ($i = 1; $i <=12; $i++) { - ?> - <option <?php echo $config['log_graceperiod']==$i?'selected="selected"':''; ?> value="<?php echo $i; ?>"> - After <?php echo $i; ?> <?php echo ($i>1)?'Months':'Month'; ?></option> + for ($i = 1; $i <=12; $i++) { + ?> + <option <?php echo $config['log_graceperiod']==$i?'selected="selected"':''; ?> value="<?php echo $i; ?>"> + After <?php echo $i; ?> <?php echo ($i>1)?'Months':'Month'; ?></option> <?php - } ?> - </select> - </td> - </tr> - <tr><td>Password Reset Policy:</th> - <td> - <select name="passwd_reset_period"> - <option value="0"> — None —</option> - <?php - for ($i = 1; $i <= 12; $i++) { - echo sprintf('<option value="%d" %s>%s%s</option>', - $i,(($config['passwd_reset_period']==$i)?'selected="selected"':''),$i>1?"Every $i ":'',$i>1?' Months':'Monthly'); - } - ?> - </select> - <font class="error"> <?php echo $errors['passwd_reset_period']; ?></font> - </td> - </tr> - <tr><td>Staff Excessive Logins:</td> - <td> - <select name="staff_max_logins"> - <?php - for ($i = 1; $i <= 10; $i++) { - echo sprintf('<option value="%d" %s>%d</option>',$i,(($config['staff_max_logins']==$i)?'selected="selected"':''),$i); - } - ?> - </select> failed login attempt(s) allowed before a - <select name="staff_login_timeout"> - <?php - for ($i = 1; $i <= 10; $i++) { - echo sprintf('<option value="%d" %s>%d</option>',$i,(($config['staff_login_timeout']==$i)?'selected="selected"':''),$i); - } - ?> - </select> minute lock-out is enforced. - </td> - </tr> - <tr><td>Staff Session Timeout:</td> - <td> - <input type="text" name="staff_session_timeout" size=6 value="<?php echo $config['staff_session_timeout']; ?>"> - Maximum idle time in minutes before a staff member must log in again (enter 0 to disable). - </td> - </tr> - <tr><td>Bind Staff Session to IP:</td> - <td> - <input type="checkbox" name="staff_ip_binding" <?php echo $config['staff_ip_binding']?'checked="checked"':''; ?>> - <em>(binds staff session to originating IP address upon login)</em> - </td> - </tr> - <tr><td>Client Excessive Logins:</td> - <td> - <select name="client_max_logins"> - <?php - for ($i = 1; $i <= 10; $i++) { - echo sprintf('<option value="%d" %s>%d</option>',$i,(($config['client_max_logins']==$i)?'selected="selected"':''),$i); - } - - ?> - </select> failed login attempt(s) allowed before a - <select name="client_login_timeout"> - <?php - for ($i = 1; $i <= 10; $i++) { - echo sprintf('<option value="%d" %s>%d</option>',$i,(($config['client_login_timeout']==$i)?'selected="selected"':''),$i); - } - ?> - </select> minute lock-out is enforced. - </td> - </tr> - - <tr><td>Client Session Timeout:</td> - <td> - <input type="text" name="client_session_timeout" size=6 value="<?php echo $config['client_session_timeout']; ?>"> - Maximum idle time in minutes before a client must log in again (enter 0 to disable). - </td> - </tr> - <tr><td>Clickable URLs:</td> - <td> - <input type="checkbox" name="clickable_urls" <?php echo $config['clickable_urls']?'checked="checked"':''; ?>> - <em>(converts URLs in messages to clickable links)</em> - </td> - </tr> - <tr><td>Enable Auto Cron:</td> - <td> - <input type="checkbox" name="enable_auto_cron" <?php echo $config['enable_auto_cron']?'checked="checked"':''; ?>> - <em>(executes cron jobs based on staff activity - not recommended)</em> - </td> - </tr> - </tbody> -</table> -<p style="padding-left:250px;"> - <input class="button" type="submit" name="submit" value="Save Changes"> - <input class="button" type="reset" name="reset" value="Reset Changes"> -</p> -</form> + } ?> + </select> + </td> + </tr> + <tr><td>Password Reset Policy:</th> + <td> + <select name="passwd_reset_period"> + <option value="0"> — None —</option> + <?php + for ($i = 1; $i <= 12; $i++) { + echo sprintf('<option value="%d" %s>%s%s</option>', + $i,(($config['passwd_reset_period']==$i)?'selected="selected"':''),$i>1?"Every $i ":'',$i>1?' Months':'Monthly'); + } + ?> + </select> + <font class="error"> <?php echo $errors['passwd_reset_period']; ?></font> + </td> + </tr> + <tr><td>Staff Excessive Logins:</td> + <td> + <select name="staff_max_logins"> + <?php + for ($i = 1; $i <= 10; $i++) { + echo sprintf('<option value="%d" %s>%d</option>',$i,(($config['staff_max_logins']==$i)?'selected="selected"':''),$i); + } + ?> + </select> failed login attempt(s) allowed before a + <select name="staff_login_timeout"> + <?php + for ($i = 1; $i <= 10; $i++) { + echo sprintf('<option value="%d" %s>%d</option>',$i,(($config['staff_login_timeout']==$i)?'selected="selected"':''),$i); + } + ?> + </select> minute lock-out is enforced. + </td> + </tr> + <tr><td>Staff Session Timeout:</td> + <td> + <input type="text" name="staff_session_timeout" size=6 value="<?php echo $config['staff_session_timeout']; ?>"> + Maximum idle time in minutes before a staff member must log in again (enter 0 to disable). + </td> + </tr> + <tr><td>Bind Staff Session to IP:</td> + <td> + <input type="checkbox" name="staff_ip_binding" <?php echo $config['staff_ip_binding']?'checked="checked"':''; ?>> + <em>(binds staff session to originating IP address upon login)</em> + </td> + </tr> + <tr><td>Client Excessive Logins:</td> + <td> + <select name="client_max_logins"> + <?php + for ($i = 1; $i <= 10; $i++) { + echo sprintf('<option value="%d" %s>%d</option>',$i,(($config['client_max_logins']==$i)?'selected="selected"':''),$i); + } + + ?> + </select> failed login attempt(s) allowed before a + <select name="client_login_timeout"> + <?php + for ($i = 1; $i <= 10; $i++) { + echo sprintf('<option value="%d" %s>%d</option>',$i,(($config['client_login_timeout']==$i)?'selected="selected"':''),$i); + } + ?> + </select> minute lock-out is enforced. + </td> + </tr> + + <tr><td>Client Session Timeout:</td> + <td> + <input type="text" name="client_session_timeout" size=6 value="<?php echo $config['client_session_timeout']; ?>"> + Maximum idle time in minutes before a client must log in again (enter 0 to disable). + </td> + </tr> + <tr><td>Clickable URLs:</td> + <td> + <input type="checkbox" name="clickable_urls" <?php echo $config['clickable_urls']?'checked="checked"':''; ?>> + <em>(converts URLs in messages to clickable links)</em> + </td> + </tr> + <tr><td>Enable Auto Cron:</td> + <td> + <input type="checkbox" name="enable_auto_cron" <?php echo $config['enable_auto_cron']?'checked="checked"':''; ?>> + <em>(executes cron jobs based on staff activity - not recommended)</em> + </td> + </tr> + </tbody> +</table> +<p style="padding-left:250px;"> + <input class="button" type="submit" name="submit" value="Save Changes"> + <input class="button" type="reset" name="reset" value="Reset Changes"> +</p> +</form> + diff --git a/include/staff/slaplans.inc.php b/include/staff/slaplans.inc.php index 4ebb46b334e4e2a15b3f63f163824c03accbca29..5dea61f69b8ccaeaec3b84411185fbe4a26da886 100644 --- a/include/staff/slaplans.inc.php +++ b/include/staff/slaplans.inc.php @@ -25,10 +25,8 @@ $$x=' class="'.strtolower($order).'" '; $order_by="$order_column $order "; $total=db_count('SELECT count(*) FROM '.SLA_TABLE.' sla '); -$pagelimit=$thisstaff->getPageLimit(); -$pagelimit=$pagelimit?$pagelimit:PAGE_LIMIT; //true default...if all fails. $page=($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1; -$pageNav=new Pagenate($total,$page,$pagelimit); +$pageNav=new Pagenate($total, $page, PAGE_LIMIT); $pageNav->setURL('slas.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&order='.urlencode($_REQUEST['order'])); //Ok..lets roll...create the actual query $qstr.='&order='.($order=='DESC'?'ASC':'DESC'); diff --git a/include/staff/staffmembers.inc.php b/include/staff/staffmembers.inc.php index be8497b97c5030009cac3ff099dd8fadffa00ace..aa41b1bbf4a00a6143bb8bd0961d8a8ab4a801b0 100644 --- a/include/staff/staffmembers.inc.php +++ b/include/staff/staffmembers.inc.php @@ -46,10 +46,8 @@ $$x=' class="'.strtolower($order).'" '; $order_by="$order_column $order "; $total=db_count('SELECT count(DISTINCT staff.staff_id) '.$from.' '.$where); -$pagelimit=$thisstaff->getPageLimit(); -$pagelimit=$pagelimit?$pagelimit:PAGE_LIMIT; //true default...if all fails. $page=($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1; -$pageNav=new Pagenate($total,$page,$pagelimit); +$pageNav=new Pagenate($total,$page,PAGE_LIMIT); $pageNav->setURL('staff.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&order='.urlencode($_REQUEST['order'])); //Ok..lets roll...create the actual query $qstr.='&order='.($order=='DESC'?'ASC':'DESC'); diff --git a/include/staff/syslogs.inc.php b/include/staff/syslogs.inc.php index 1cec6aff3f253876a77c11d961ca87cba5b3c91f..482dd429c3738faea83e49df05a09c8dd391a7e2 100644 --- a/include/staff/syslogs.inc.php +++ b/include/staff/syslogs.inc.php @@ -71,9 +71,7 @@ $qfrom=' FROM '.SYSLOG_TABLE.' log '; $total=db_count("SELECT count(*) $qfrom $qwhere"); $page = ($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1; //pagenate -$pagelimit=$thisstaff->getPageLimit(); -$pagelimit=$pagelimit?$pagelimit:PAGE_LIMIT; //true default...if all fails. -$pageNav=new Pagenate($total,$page,$pagelimit); +$pageNav=new Pagenate($total, $page, PAGE_LIMIT); $pageNav->setURL('syslogs.php',$qstr); $qstr.='&order='.($order=='DESC'?'ASC':'DESC'); $query="$qselect $qfrom $qwhere ORDER BY $order_by LIMIT ".$pageNav->getStart().",".$pageNav->getLimit(); diff --git a/include/staff/templates.inc.php b/include/staff/templates.inc.php index 8ce8ca8546ed5932fa5788aec5430400b68e6210..7f82f656f12cafe984de35ff205eb62bfef2b1a7 100644 --- a/include/staff/templates.inc.php +++ b/include/staff/templates.inc.php @@ -28,10 +28,8 @@ $$x=' class="'.strtolower($order).'" '; $order_by="$order_column $order "; $total=db_count('SELECT count(*) FROM '.EMAIL_TEMPLATE_TABLE.' tpl '); -$pagelimit=$thisstaff->getPageLimit(); -$pagelimit=$pagelimit?$pagelimit:PAGE_LIMIT; //true default...if all fails. $page=($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1; -$pageNav=new Pagenate($total,$page,$pagelimit); +$pageNav=new Pagenate($total, $page, PAGE_LIMIT); $pageNav->setURL('templates.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&order='.urlencode($_REQUEST['order'])); //Ok..lets roll...create the actual query $qstr.='&order='.($order=='DESC'?'ASC':'DESC'); diff --git a/include/staff/tickets.inc.php b/include/staff/tickets.inc.php index dad492a18f83dd64ed22f94de6a662de5e46ae45..d0b27690e2cf138140c1707e1f3a92809493cc91 100644 --- a/include/staff/tickets.inc.php +++ b/include/staff/tickets.inc.php @@ -180,8 +180,8 @@ if(!$order_by && $showanswered) { }elseif(!$order_by && !strcasecmp($status,'closed')){ $order_by='ticket.closed, ticket.created'; //No priority sorting for closed tickets. } -$order_by =$order_by?$order_by:'priority_urgency,effective_date,ticket.created'; -$order=$order?$order:'DESC'; +$order_by =$order_by?$order_by:'priority_urgency, effective_date, ticket.created'; +$order=$order?$order:'ASC'; if($order_by && strpos($order_by,',')) $order_by=str_replace(','," $order,",$order_by); @@ -200,6 +200,7 @@ $qselect ='SELECT DISTINCT ticket.ticket_id,lock_id,ticketID,ticket.dept_id,tick $qfrom=' FROM '.TICKET_TABLE.' ticket '. ' LEFT JOIN '.DEPT_TABLE.' dept ON ticket.dept_id=dept.dept_id '; +$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 )' @@ -210,7 +211,7 @@ $qgroup=' GROUP BY ticket.ticket_id'; //get ticket count based on the query so far.. $total=db_count("SELECT count(DISTINCT ticket.ticket_id) $qfrom $sjoin $qwhere"); //pagenate -$pagelimit=($_GET['limit'] && is_numeric($_GET['limit']))?$_GET['limit']:$thisstaff->getPageLimit(); +$pagelimit=($_GET['limit'] && is_numeric($_GET['limit']))?$_GET['limit']:PAGE_LIMIT; $page=($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1; $pageNav=new Pagenate($total,$page,$pagelimit); $pageNav->setURL('tickets.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&order='.urlencode($_REQUEST['order'])); @@ -350,7 +351,7 @@ $basic_display=!isset($_REQUEST['advance_search'])?true:false; <div class="clear"></div> <div style="margin-bottom:20px"> <form action="tickets.php" method="POST" name='tickets' onSubmit="return checkbox_checker(this,1,0);"> - <a class="refresh" href="">Refresh</a> + <a class="refresh" href="<?php echo $_SERVER['REQUEST_URI']; ?>">Refresh</a> <input type="hidden" name="a" value="mass_process" > <input type="hidden" name="status" value="<?php echo $status; ?>" > <table class="list" border="0" cellspacing="1" cellpadding="2" width="940"> diff --git a/index.php b/index.php index 37e5c7f1b2dd3e899d3d7a154d5e074629ed1bfe..ac4fe04a014455d083aacab299fdace3a045e529 100644 --- a/index.php +++ b/index.php @@ -13,4 +13,40 @@ vim: expandtab sw=4 ts=4 sts=4: **********************************************************************/ -require('offline.php'); +require('client.inc.php'); +$section = 'home'; +require(CLIENTINC_DIR.'header.inc.php'); +?> + +<div id="landing_page"> + <h1>Welcome to the Support Center</h1> + <p> + In order to streamline support requests and better serve you, we utilize a support ticket system. Every support request is assigned a unique ticket number which you can use to track the progress and responses online. For your reference we provide complete archives and history of all your support requests. A valid email address is required to submit a ticket. + </p> + + <div id="new_ticket"> + <h3>Open A New Ticket</h3> + <form method="get" action="open.php"> + <div>Please provide as much detail as possible so we can best assist you. To update a previously submitted ticket, please login.</div> + <input type="submit" value="Open a New Ticket"> + </form> + </div> + + <div id="check_status"> + <h3>Check Ticket Status</h3> + <form class="status_form" action="view.php" method="get"> + <div>We provide archives and history of all your current and past support requests complete with responses.</div> + <input type="submit" value="Check Ticket Status"> + </form> + </div> +</div> +<div class="clear"></div> +<?php +if($cfg && $cfg->isKnowledgebaseEnabled()){ + //FIXME: provide ability to feature or select random FAQs ?? +?> +<p>Be sure to browse our <a href="kb/index.php">Frequently Asked Questions (FAQs)</a>, before opening a ticket.</p> +</div> +<?php +} ?> +<?php require(CLIENTINC_DIR.'footer.inc.php'); ?> diff --git a/js/osticket.js b/js/osticket.js index fd04ff48c809525267ebaacca85ac30cb37dd00a..a809e6f2f794a0534096c69b2a210428424d703d 100644 --- a/js/osticket.js +++ b/js/osticket.js @@ -1,79 +1 @@ -jQuery(function($) { - var max_uploads = 5; - var current_reply_uploads = 0; - var current_note_uploads = 0; - - function parse_upload(elem) { - var new_input = elem.clone(); - var filename = elem.val(); - if(filename != '') { - var container = elem.parent().parent(); - var form_type = container.attr('id'); - elem.blur().hide(); - $('.uploads', container).append('<div><label><input type="checkbox" name="uploads[]" value="' + filename + '" checked="checked"> ' + filename.replace('C:\\', '').replace('fakepath\\', '') + '</label></div>'); - if(form_type=='reply_form_attachments') { - current_reply_uploads++; - if(current_reply_uploads < max_uploads) { - elem.after(new_input.val('').blur()); - } - } else { - current_note_uploads++; - if(current_note_uploads < max_uploads) { - elem.after(new_input.val('').blur()); - } - } - } - } - - if($.browser.msie) { - $('.attachments').delegate('input[type=file]', 'click', function() { - var elem = $(this); - setTimeout(function() { - parse_upload(elem); - elem.blur(); - }, 0); - }); - } else { - $('.attachments').delegate('input[type=file]', 'change', function() { - var elem = $(this); - parse_upload(elem); - }); - } - - $('.uploads').delegate('.uploads input', 'click', function(e) { - e.preventDefault(); - var elem = $(this); - elem.attr('checked', 'checked'); - if(confirm("Are you sure you want to delete this attachment?")==true) { - var container = elem.parent().parent(); - var cparent = container.parent().parent(); - var form_type = cparent.attr('id'); - var filename = elem.val(); - $('input[type=file]', cparent).each(function() { - if($(this).val() == filename) { - $(this).remove(); - } - }); - container.remove(); - var new_input = $('input[type=file]:last', cparent).clone(); - var last_elem = $('input[type=file]:last', cparent); - if(form_type=='reply_form_attachments') { - current_reply_uploads--; - if(current_reply_uploads < max_uploads) { - if(last_elem.css('display')=='none') { - last_elem.after(new_input.val('').show()); - } - } - } else { - current_note_uploads--; - if(current_note_uploads < max_uploads) { - if(last_elem.css('display')=='none') { - last_elem.after(new_input.val('').show()); - } - } - } - } else { - e.preventDefault(); - } - }); -}); \ No newline at end of file +//Nothing for now... diff --git a/login.php b/login.php new file mode 100644 index 0000000000000000000000000000000000000000..044d74644785f32a0f79bae76e6c4309fd473b2a --- /dev/null +++ b/login.php @@ -0,0 +1,91 @@ +<?php +/********************************************************************* + login.php + + Client Login + + 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('client.inc.php'); +if(!defined('INCLUDE_DIR')) die('Fatal Error'); +define('CLIENTINC_DIR',INCLUDE_DIR.'client/'); +define('OSTCLIENTINC',TRUE); //make includes happy + +require_once(INCLUDE_DIR.'class.client.php'); +require_once(INCLUDE_DIR.'class.ticket.php'); +//We are ready baby +$loginmsg='Authentication Required'; +if($_POST && (!empty($_POST['lemail']) && !empty($_POST['lticket']))): + $loginmsg='Authentication Required'; + $email=trim($_POST['lemail']); + $ticketID=trim($_POST['lticket']); + //$_SESSION['_client']=array(); #Uncomment to disable login strikes. + + //Check time for last max failed login attempt strike. + $loginmsg='Invalid login'; + if($_SESSION['_client']['laststrike']) { + if((time()-$_SESSION['_client']['laststrike'])<$cfg->getClientLoginTimeout()) { + $loginmsg='Excessive failed login attempts'; + $errors['err']='You\'ve reached maximum failed login attempts allowed. Try again later or <a href="open.php">open a new ticket</a>'; + }else{ //Timeout is over. + //Reset the counter for next round of attempts after the timeout. + $_SESSION['_client']['laststrike']=null; + $_SESSION['_client']['strikes']=0; + } + } + //See if we can fetch local ticket id associated with the ID given + if(!$errors && is_numeric($ticketID) && Validator::is_email($email) && ($ticket=Ticket::lookupByExtId($ticketID))) { + //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){ + //valid match...create session goodies for the client. + $user = new ClientSession($email,$ticket->getId()); + $_SESSION['_client']=array(); //clear. + $_SESSION['_client']['userID'] =$ticket->getEmail(); //Email + $_SESSION['_client']['key'] =$ticket->getExtId(); //Ticket ID --acts as password when used with email. See above. + $_SESSION['_client']['token'] =$user->getSessionToken(); + $_SESSION['TZ_OFFSET']=$cfg->getTZoffset(); + $_SESSION['daylight']=$cfg->observeDaylightSaving(); + //Log login info... + $msg=sprintf("%s/%s logged in [%s]",$ticket->getEmail(),$ticket->getExtId(),$_SERVER['REMOTE_ADDR']); + Sys::log(LOG_DEBUG,'User login',$msg); + //Redirect tickets.php + session_write_close(); + session_regenerate_id(); + @header("Location: tickets.php?id=".$ticket->getExtId()); + require_once('tickets.php'); //Just incase. of header already sent error. + exit; + } + } + //If we get to this point we know the login failed. + $_SESSION['_client']['strikes']+=1; + if(!$errors && $_SESSION['_client']['strikes']>$cfg->getClientMaxLogins()) { + $loginmsg='Access Denied'; + $errors['err']='Forgot your login info? Please <a href="open.php">open a new ticket</a>.'; + $_SESSION['_client']['laststrike']=time(); + $alert='Excessive login attempts by a client?'."\n". + 'Email: '.$_POST['lemail']."\n".'Ticket#: '.$_POST['lticket']."\n". + 'IP: '.$_SERVER['REMOTE_ADDR']."\n".'Time:'.date('M j, Y, g:i a T')."\n\n". + 'Attempts #'.$_SESSION['_client']['strikes']; + Sys::log(LOG_ALERT,'Excessive login attempts (client)',$alert,($cfg->alertONLoginError())); + }elseif($_SESSION['_client']['strikes']%2==0){ //Log every other failed login attempt as a warning. + $alert='Email: '.$_POST['lemail']."\n".'Ticket #: '.$_POST['lticket']."\n".'IP: '.$_SERVER['REMOTE_ADDR']. + "\n".'TIME: '.date('M j, Y, g:i a T')."\n\n".'Attempts #'.$_SESSION['_client']['strikes']; + Sys::log(LOG_WARNING,'Failed login attempt (client)',$alert); + } +endif; + +$nav = new UserNav(); +$nav->setActiveNav('status'); +require(CLIENTINC_DIR.'header.inc.php'); +require(CLIENTINC_DIR.'login.inc.php'); +require(CLIENTINC_DIR.'footer.inc.php'); +?> diff --git a/logout.php b/logout.php new file mode 100644 index 0000000000000000000000000000000000000000..72c3560ecc7f540febb1ea0032c9b6cd39e2d3d6 --- /dev/null +++ b/logout.php @@ -0,0 +1,24 @@ +<?php +/********************************************************************* + logout.php + + Destroy clients session. + + 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('client.inc.php'); +//We are checking to make sure the user is logged in before a logout to avoid session reset tricks on excess logins +$_SESSION['_client']=array(); +session_unset(); +session_destroy(); +header('Location: index.php'); +require('index.php'); +?> diff --git a/main.inc.php b/main.inc.php index 6fd211ed3b4505f825dc8869e92e8186d92c1e68..53314c1ba469595a63f30a8e7584e3a10c250ae5 100644 --- a/main.inc.php +++ b/main.inc.php @@ -102,9 +102,6 @@ #CURRENT EXECUTING SCRIPT. define('THISPAGE',Misc::currentURL()); - #pagenation default - define('PAGE_LIMIT',20); - # This is to support old installations. with no secret salt. if(!defined('SECRET_SALT')) define('SECRET_SALT',md5(TABLE_PREFIX.ADMIN_EMAIL)); @@ -164,10 +161,7 @@ $ferror='Unable to connect to the database'; }elseif(!($cfg=Sys::getConfig())){ $ferror='Unable to load config info from DB. Get tech support.'; - }elseif(!ini_get('short_open_tag')) { - $ferror='Short open tag disabled! - osTicket requires it turned ON.'; } - if($ferror){ //Fatal error Sys::alertAdmin('osTicket Fatal Error',$ferror); //try alerting admin. die("<b>Fatal Error:</b> Contact system administrator."); //Generic error. @@ -175,6 +169,11 @@ } //Init $cfg->init(); + + //System defaults we might want to make global// + #pagenation default - user can overwrite it! + define('DEFAULT_PAGE_LIMIT',$cfg->getPageSize()?$cfg->getPageSize():25); + //Start session handler! $session=osTicketSession::start(SESSION_TTL); // start_session //Set default timezone...staff will overwrite it. diff --git a/offline.php b/offline.php index 3c3b24a425c78badc335c45cc62a9022fa61d1f6..24f8401a14c9710de2f9bf7af3a13985a47a099d 100644 --- a/offline.php +++ b/offline.php @@ -14,6 +14,11 @@ vim: expandtab sw=4 ts=4 sts=4: **********************************************************************/ require_once('client.inc.php'); +if($cfg && !$cfg->isHelpDeskOffline()) { + @header('Location: index.php'); //Redirect if the system is online. + include('index.php'); + exit; +} $nav=null; require(CLIENTINC_DIR.'header.inc.php'); ?> diff --git a/open.php b/open.php new file mode 100644 index 0000000000000000000000000000000000000000..11d3a0a9d3397d64941886169a5fa2892ea663a1 --- /dev/null +++ b/open.php @@ -0,0 +1,55 @@ +<?php +/********************************************************************* + open.php + + New tickets handle. + + 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('client.inc.php'); +define('SOURCE','Web'); //Ticket source. +$inc='open.inc.php'; //default include. +$errors=array(); +if($_POST): + $_POST['deptId']=$_POST['emailId']=0; //Just Making sure we don't accept crap...only topicId is expected. + if($thisclient) { + $_POST['name']=$thisclient->getName(); + $_POST['email']=$thisclient->getEmail(); + } elseif($cfg->enableCaptcha()) { + if(!$_POST['captcha']) + $errors['captcha']='Enter text shown on the image'; + elseif(strcmp($_SESSION['captcha'],md5($_POST['captcha']))) + $errors['captcha']='Invalid - try again!'; + } + + //Ticket::create...checks for errors.. + if(($ticket=Ticket::create($_POST,$errors,SOURCE))){ + $msg='Support ticket request created'; + //Logged in...simply view the newly created ticket. + if($thisclient && $thisclient->isValid()) { + if(!$cfg->showRelatedTickets()) + $_SESSION['_client']['key']= $ticket->getExtId(); //Resetting login Key to the current ticket! + session_write_close(); + session_regenerate_id(); + @header('Location: tickets.php?id='.$ticket->getExtId()); + } + //Thank the user and promise speedy resolution! + $inc='thankyou.inc.php'; + }else{ + $errors['err']=$errors['err']?$errors['err']:'Unable to create a ticket. Please correct errors below and try again!'; + } +endif; + +//page +$nav->setActiveNav('new'); +require(CLIENTINC_DIR.'header.inc.php'); +require(CLIENTINC_DIR.$inc); +require(CLIENTINC_DIR.'footer.inc.php'); +?> diff --git a/scp/staff.inc.php b/scp/staff.inc.php index 3c0d328809cbc94b37e9a2fee074ce6dabb08a97..b3ee30a4ec3a555c2fd8c3c86ed6e72b2c6517ca 100644 --- a/scp/staff.inc.php +++ b/scp/staff.inc.php @@ -79,11 +79,14 @@ if(!$thisstaff->isadmin()){ //Keep the session activity alive $thisstaff->refreshSession(); + +/******* SET STAFF DEFAULTS **********/ //Set staff's timezone offset. $_SESSION['TZ_OFFSET']=$thisstaff->getTZoffset(); $_SESSION['daylight']=$thisstaff->observeDaylight(); define('AUTO_REFRESH_RATE',$thisstaff->getRefreshRate()*60); +define('PAGE_LIMIT',$thisstaff->getPageLimit()?$thisstaff->getPageLimit():DEFAULT_PAGE_LIMIT); //Clear some vars. we use in all pages. $errors=array(); diff --git a/secure.inc.php b/secure.inc.php new file mode 100644 index 0000000000000000000000000000000000000000..3096b3503036e8746a58cea56aa2e85f977b4896 --- /dev/null +++ b/secure.inc.php @@ -0,0 +1,25 @@ +<?php +/********************************************************************* + secure.inc.php + + File included on every client's "secure" pages + + 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: +**********************************************************************/ +if(!strcasecmp(basename($_SERVER['SCRIPT_NAME']),basename(__FILE__))) die('Kwaheri!'); +if(!file_exists('client.inc.php')) die('Fatal Error.'); +require_once('client.inc.php'); +//User must be logged in! +if(!$thisclient || !$thisclient->getId() || !$thisclient->isValid()){ + require('./login.php'); + exit; +} +$thisclient->refreshSession(); +?> diff --git a/setup/inc/class.setup.php b/setup/inc/class.setup.php index c4d986c655ad6041591f879f7e4c077ef24ec6b7..c6bf7b6751c9e80236d3cbfe143a37c6d52cf6c5 100644 --- a/setup/inc/class.setup.php +++ b/setup/inc/class.setup.php @@ -303,7 +303,7 @@ class Installer extends SetupWizard { 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 ' + .', 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']) diff --git a/tickets.php b/tickets.php new file mode 100644 index 0000000000000000000000000000000000000000..d4759ba522e328911d2e9a494254ce338ea7f905 --- /dev/null +++ b/tickets.php @@ -0,0 +1,89 @@ +<?php +/********************************************************************* + tickets.php + + Main client/user interface. + Note that we are using external ID. The real (local) ids are hidden from user. + + 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('secure.inc.php'); +if(!is_object($thisclient) || !$thisclient->isValid()) die('Access denied'); //Double check again. +require_once(INCLUDE_DIR.'class.ticket.php'); +$ticket=null; +if($_REQUEST['id']) { + if(!($ticket=Ticket::lookupByExtId($_REQUEST['id']))) { + $errors['err']='Unknown or invalid ticket ID.'; + }elseif(!$ticket->checkClientAccess($thisclient)) { + $errors['err']='Unknown or invalid ticket ID.'; //Using generic message on purpose! + $ticket=null; + } +} + +//Process post...depends on $ticket object above. +if($_POST && is_object($ticket) && $ticket->getId()): + $errors=array(); + switch(strtolower($_POST['a'])){ + case 'reply': + if(!$ticket->checkClientAccess($thisclient)) //double check perm again! + $errors['err']='Access Denied. Possibly invalid ticket ID'; + + if(!$_POST['message']) + $errors['message']='Message required'; + + //check attachment..if any is set + $files=($cfg->allowOnlineAttachments() && $_FILES['attachments'])?Format::files($_FILES['attachments']):array(); + if($files) { + + foreach($files as $file) { + if(!$file['name']) continue; + + if(!$cfg->canUploadFileType($file['name'])) + $errors['attachment']='Invalid file type [ '.$file['name'].' ]'; + elseif($file['size']>$cfg->getMaxFileSize()) + $errors['attachment']='File '.$file['name'].'is too big. Max '.$cfg->getMaxFileSize().' bytes allowed'; + } + } + + if(!$errors){ + //Everything checked out...do the magic. + if(($msgid=$ticket->postMessage($_POST['message'],'Web'))) { + if($files && $cfg->allowOnlineAttachments()) + $ticket->uploadAttachments($files,$msgid,'M'); + + $msg='Message Posted Successfully'; + } else { + $errors['err']='Unable to post the message. Try again'; + } + + } elseif(!$errors['err']) { + print_r($errors); + $errors['err']='Error(s) occurred. Please try again'; + + } + break; + default: + $errors['err']='Uknown action'; + } + $ticket->reload(); +endif; +$nav->setActiveNav('tickets'); +if($ticket && $ticket->checkClientAccess($thisclient)) { + $inc='view.inc.php'; +} elseif($cfg->showRelatedTickets() && $thisclient->getNumTickets()) { + $inc='tickets.inc.php'; +} else { + $nav->setActiveNav('new'); + $inc='open.inc.php'; +} +include(CLIENTINC_DIR.'header.inc.php'); +include(CLIENTINC_DIR.$inc); +include(CLIENTINC_DIR.'footer.inc.php'); +?> diff --git a/view.php b/view.php new file mode 100644 index 0000000000000000000000000000000000000000..984b04c3019645c6ca1d075bbab0aac8460e4094 --- /dev/null +++ b/view.php @@ -0,0 +1,21 @@ +<?php +/********************************************************************* + view.php + + Ticket View. + + Peter Rotich <peter@osticket.com> + Copyright (c) 2006-2010 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: + $Id: $ +**********************************************************************/ +require('secure.inc.php'); +if(!is_object($thisclient) || !$thisclient->isValid()) die('Access denied'); //Double check again. +//We are now using tickets.php but we need to keep view.php for backward compatibility +require('tickets.php'); +?>