function update($var,&$errors) { global $cfg,$thisuser; $fields=array(); $fields['name'] = array('type'=>'string', 'required'=>1, 'error'=>'Name required'); $fields['email'] = array('type'=>'email', 'required'=>1, 'error'=>'Email is required'); $fields['note'] = array('type'=>'text', 'required'=>1, 'error'=>'Reason for the update required'); $fields['subject'] = array('type'=>'string', 'required'=>1, 'error'=>'Subject required'); $fields['pri'] = array('type'=>'int', 'required'=>0, 'error'=>'Invalid Priority'); $fields['phone'] = array('type'=>'phone', 'required'=>0, 'error'=>'Valid phone # required'); $fields['duedate'] = array('type'=>'date', 'required'=>0, 'error'=>'Invalid date - must be MM/DD/YY'); $fields['franstaff_id'] = array('type'=>'string', 'required'=>0, 'error'=>'Franchisees Staff ID required'); $fields['fran_id'] = array('type'=>'string', 'required'=>1, 'error'=>'Franchisee is Required'); $params = new Validator($fields); if(!$params->validate($var)){ $errors=array_merge($errors,$params->errors()); } if($var['duedate']){ if($this->isClosed()) $errors['duedate']='Duedate can NOT be set on a closed ticket'; elseif(!$var['time'] || strpos($var['time'],':')===false) $errors['time']='Select time'; elseif(strtotime($var['duedate'].' '.$var['time'])===false) $errors['duedate']='Invalid duedate'; elseif(strtotime($var['duedate'].' '.$var['time'])<=time()) $errors['duedate']='Due date must be in the future'; } //Make sure phone extension is valid if($var['phone_ext'] ) { if(!is_numeric($var['phone_ext']) && !$errors['phone']) $errors['phone']='Invalid phone ext.'; elseif(!$var['phone']) //make sure they just didn't enter ext without phone # $errors['phone']='Phone number required'; } if(!$errors){ $sql='UPDATE '.TICKET_TABLE.' SET updated=NOW() '. ',email='.db_input($var['email']). ',name='.db_input(Format::striptags($var['name'])). ',subject='.db_input(Format::striptags($var['subject'])). ',phone='.db_input($var['phone']). ',phone_ext='.db_input($var['phone_ext']?$var['phone_ext']:NULL). ',priority_id='.db_input($var['pri']). ',franstaff_id='.db_input(Format::striptags($var['franstaff_id'])). ',fran_id='.db_input(Format::striptags($var['fran_id'])). ',duedate='.($var['duedate']?db_input(date('Y-m-d G:i',Misc::dbtime($var['duedate'].' '.$var['time']))):'NULL'); if($var['duedate']) { //We are setting new duedate... $sql.=',isoverdue=0'; } $sql.=' WHERE ticket_id='.db_input($this->getId()); //echo $sql; if(db_query($sql)){ $this->postNote('Ticket Edit',$var['note']); $this->reload(); return true; } } return false; } /* * The mother of all functions...You break it you fix it! * * $autorespond and $alertstaff overwrites config info... */ function create($var,&$errors,$origin,$autorespond=true,$alertstaff=true) { global $cfg,$thisclient,$_FILES; $id=0; $fields=array(); $fields['name'] = array('type'=>'string', 'required'=>1, 'error'=>'Name required'); $fields['email'] = array('type'=>'email', 'required'=>1, 'error'=>'Valid email required'); $fields['subject'] = array('type'=>'string', 'required'=>1, 'error'=>'Subject required'); $fields['message'] = array('type'=>'text', 'required'=>1, 'error'=>'Message required'); $fields['franstaff_id'] = array('type'=>'string', 'required'=>0, 'error'=>'Franchisees Staff ID required'); $fields['fran_id'] = array('type'=>'string', 'required'=>1, 'error'=>'Franchisee is required'); if(strcasecmp($origin,'web')==0) { //Help topic only applicable on web tickets. $fields['topicId'] = array('type'=>'int', 'required'=>1, 'error'=>'Select help topic'); }elseif(strcasecmp($origin,'staff')==0){ //tickets created by staff...e.g on callins. $fields['topicId'] = array('type'=>'int', 'required'=>1, 'error'=>'Select help topic please'); $fields['deptId'] = array('type'=>'int', 'required'=>1, 'error'=>'Dept. required'); $fields['source'] = array('type'=>'string', 'required'=>1, 'error'=>'Indicate source'); $fields['duedate'] = array('type'=>'date', 'required'=>0, 'error'=>'Invalid date - must be MM/DD/YY'); }else { //Incoming emails $fields['emailId'] = array('type'=>'int', 'required'=>1, 'error'=>'Email unknown'); } $fields['pri'] = array('type'=>'int', 'required'=>0, 'error'=>'Invalid Priority'); $fields['phone'] = array('type'=>'phone', 'required'=>0, 'error'=>'Valid phone # required'); $validate = new Validator($fields); if(!$validate->validate($var)){ $errors=array_merge($errors,$validate->errors()); } //Make sure the email is not banned if(!$errors && BanList::isbanned($var['email'])) $errors['err']='Ticket denied Error #403'; if(!$errors && $thisclient && strcasecmp($thisclient->getEmail(),$var['email'])) $errors['email']='Email mismatch.'; //Make sure phone extension is valid if($var['phone_ext'] ) { if(!is_numeric($var['phone_ext']) && !$errors['phone']) $errors['phone']='Invalid phone ext.'; elseif(!$var['phone']) //make sure they just didn't enter ext without phone # $errors['phone']='Phone number required'; } //Make sure the due date is valid if($var['duedate']){ if(!$var['time'] || strpos($var['time'],':')===false) $errors['time']='Select time'; elseif(strtotime($var['duedate'].' '.$var['time'])===false) $errors['duedate']='Invalid duedate'; elseif(strtotime($var['duedate'].' '.$var['time'])<=time()) $errors['duedate']='Due date must be in the future'; } //check attachment..if any is set ...only set on webbased tickets.. if($_FILES['attachment']['name'] && $cfg->allowOnlineAttachments()) { if(!$cfg->canUploadFileType($_FILES['attachment']['name'])) $errors['attachment']='Invalid file type [ '.$_FILES['attachment']['name'].' ]'; elseif($_FILES['attachment']['size']>$cfg->getMaxFileSize()) $errors['attachment']='File is too big. Max '.$cfg->getMaxFileSize().' bytes allowed'; } //check ticket limits..if limit set is >0 //TODO: Base ticket limits on SLA... if(($var['email'] && !$errors && $cfg->getMaxOpenTickets()>0)){ $openTickets=Ticket::getOpenTicketsByEmail($var['email']); if($openTickets>=$cfg->getMaxOpenTickets()) { $errors['err']="You've reached the maximum open tickets allowed."; //Send the notice only once (when the limit is reached) incase of autoresponders at client end. if($cfg->getMaxOpenTickets()==$openTickets && $cfg->sendOverlimitNotice()) { if($var['deptId']) $dept = new Dept($var['deptId']); if(!$dept || !($tplId=$dept->getTemplateId())) $tplId=$cfg->getDefaultTemplateId(); $sql='SELECT ticket_overlimit_subj,ticket_overlimit_body FROM '.EMAIL_TEMPLATE_TABLE. ' WHERE cfg_id='.db_input($cfg->getId()).' AND tpl_id='.db_input($tplId); $resp=db_query($sql); if(db_num_rows($resp) && list($subj,$body)=db_fetch_row($resp)){ $body = str_replace("%name", $var['name'],$body); $body = str_replace("%email",$var['email'],$body); $body = str_replace("%url", $cfg->getBaseUrl(),$body); $body = str_replace('%signature',($dept && $dept->isPublic())?$dept->getSignature():'',$body); if(!$dept || !($email=$dept->getAutoRespEmail())) $email=$cfg->getDefaultEmail(); if($email) $email->send($var['email'],$subj,$body); } } //Alert admin...this might be spammy (no option to disable)...but it is helpful..I think. $msg='Support ticket request denied for '.$var['email']."\n". 'Open ticket:'.$openTickets."\n". 'Max Allowed:'.$cfg->getMaxOpenTickets()."\n"; Sys::alertAdmin('Overlimit Notice',$msg); } } //Any error above is fatal. if($errors) { return 0; } // OK...just do it. $deptId=$var['deptId']; //pre-selected Dept if any. $topicId=$var['topicId']; // added by Masino Sinaga, October 13, 2009 $priorityId=$var['pri']; $source=ucfirst($var['source']); $topic=NULL; // Intenal mapping magic...see if we need to overwrite anything if(isset($var['topicId']) && !$var['deptId']) { //Ticket created via web by user if($var['topicId'] && ($topic= new Topic($var['topicId'])) && $topic->getId()) { $deptId=$topic->getDeptId(); $priorityId=$priorityId?$priorityId:$topic->getPriorityId(); $topicDesc=$topic->getName(); if($autorespond) $autorespond=$topic->autoRespond(); } $source='Web'; }elseif($var['emailId'] && !$var['deptId']) { //Emailed Tickets $email= new Email($var['emailId']); if($email && $email->getId()){ $deptId=$email->getDeptId(); $priorityId=$priorityId?$priorityId:$email->getPriorityId(); if($autorespond) $autorespond=$email->autoRespond(); } $email=null; $source='Email'; }elseif($var['deptId']){ //Opened by staff. $deptId=$var['deptId']; $source=ucfirst($var['source']); // Begin of MOD by Masino Sinaga, October 13, 2009, mod Help Topic in RC5 $topic= new Topic($topicId); $priorityId=$priorityId?$priorityId:$topic->getPriorityId(); $topicDesc=$topic->getName(); if($autorespond) $autorespond=$topic->autoRespond(); // End of MOD by Masino Sinaga, October 13, 2009, mod Help Topic in RC5 } //Last minute checks $priorityId=$priorityId?$priorityId:$cfg->getDefaultPriorityId(); $deptId=$deptId?$deptId:$cfg->getDefaultDeptId(); $ipaddress=$var['ip']?$var['ip']:$_SERVER['REMOTE_ADDR']; //We are ready son...hold on to the rails. $extId=Ticket::genExtRandID(); $sql= 'INSERT INTO '.TICKET_TABLE.' SET created=NOW() '. ',ticketID='.db_input($extId). ',dept_id='.db_input($deptId). ',priority_id='.db_input($priorityId). ',email='.db_input($var['email']). ',name='.db_input(Format::striptags($var['name'])). ',subject='.db_input(Format::striptags($var['subject'])). ',topic='.db_input(Format::striptags($topicDesc)). ',phone='.db_input($var['phone']). ',phone_ext='.db_input($var['phone_ext']?$var['phone_ext']:''). ',ip_address='.db_input($ipaddress). ',franstaff_id='.db_input(Format::striptags($var['franstaff_id'])). ',fran_id='.db_input(Format::striptags($var['fran_id'])). ',source='.db_input($source); //Make sure the origin is staff - avoid firebug hack! if($var['duedate'] && !strcasecmp($origin,'staff')) $sql.=',duedate='.db_input(date('Y-m-d G:i',Misc::dbtime($var['duedate'].' '.$var['time']))); //echo $sql; $ticket=null; //return $ticket; if(db_query($sql) && ($id=db_insert_id())){ if(!$cfg->useRandomIds()){ //Sequential ticketIDs support really..really suck arse. $extId=$id; //To make things really easy we are going to use autoincrement ticket_id. db_query('UPDATE '.TICKET_TABLE.' SET ticketID='.db_input($extId).' WHERE ticket_id='.$id); //TODO: RETHING what happens if this fails?? [At the moment on failure random ID is used...making stuff usable] } //Load newly created ticket. $ticket = new Ticket($id); //post the message. $msgid=$ticket->postMessage($var['message'],$source,$var['mid'],$var['header'],true); //TODO: recover from postMessage error?? //Upload attachments...web based. if($_FILES['attachment']['name'] && $cfg->allowOnlineAttachments() && $msgid) { if(!$cfg->allowAttachmentsOnlogin() || ($cfg->allowAttachmentsOnlogin() && ($thisclient && $thisclient->isValid()))) { $ticket->uploadAttachment($_FILES['attachment'],$msgid,'M'); //TODO: recover from upload issues? } } $dept=$ticket->getDept(); if(!$dept || !($tplId=$dept->getTemplateId())) $tplId=$cfg->getDefaultTemplateId(); //Overwrite auto responder if the FROM email is one of the internal emails...loop control. if($autorespond && (Email::getIdByEmail($ticket->getEmail()))) $autorespond=false; //SEND OUT NEW TICKET AUTORESP && ALERTS. //New Ticket AutoResponse.. if($autorespond && $cfg->autoRespONNewTicket() && $dept->autoRespONNewTicket()){ $sql='SELECT ticket_autoresp_subj,ticket_autoresp_body FROM '.EMAIL_TEMPLATE_TABLE. ' WHERE cfg_id='.db_input($cfg->getId()).' AND tpl_id='.db_input($tplId); if(($resp=db_query($sql)) && db_num_rows($resp) && list($subj,$body)=db_fetch_row($resp)){ $body=$ticket->replaceTemplateVars($body); $subj=$ticket->replaceTemplateVars($subj); $body = str_replace('%message',($var['issue']?$var['issue']:$var['message']),$body); $body = str_replace('%signature',($dept && $dept->isPublic())?$dept->getSignature():'',$body); if(!$dept || !($email=$dept->getAutoRespEmail())) $email=$cfg->getDefaultEmail(); if($email){ //Reply separator tag. if($cfg->stripQuotedReply() && ($tag=$cfg->getReplySeparator())) $body ="\n$tag\n\n".$body; $email->send($ticket->getEmail(),$subj,$body); } }else { Sys::log(LOG_WARNING,'Template Fetch Error',"Unable to fetch autoresponse template #$tplId"); } } //If enabled...send alert to staff (New Ticket Alert) if($alertstaff && $cfg->alertONNewTicket() && is_object($ticket)){ $sql='SELECT ticket_alert_subj,ticket_alert_body FROM '.EMAIL_TEMPLATE_TABLE. ' WHERE cfg_id='.db_input($cfg->getId()).' AND tpl_id='.db_input($tplId); if(($resp=db_query($sql)) && db_num_rows($resp) && list($subj,$body)=db_fetch_row($resp)){ $body=$ticket->replaceTemplateVars($body); $subj=$ticket->replaceTemplateVars($subj); $body = str_replace('%message',($var['issue']?$var['issue']:$var['message']),$body); if(!($email=$cfg->getAlertEmail())) $email =$cfg->getDefaultEmail(); if($email && $email->getId()) { $sentlist=array(); //Admin Alert. if($cfg->alertAdminONNewTicket()){ $alert = str_replace("%staff",'Admin',$body); $email->send($cfg->getAdminEmail(),$subj,$alert); $sentlist[]=$cfg->getAdminEmail(); } //get the list $recipients=array(); //Dept. Manager if($cfg->alertDeptManagerONNewTicket()) { $recipients[]=$dept->getManager(); } //Staff members if($cfg->alertDeptMembersONNewTicket()) { $sql='SELECT staff_id FROM '.STAFF_TABLE.' WHERE onvacation=0 AND dept_id='.db_input($dept->getId()); if(($users=db_query($sql)) && db_num_rows($users)) { while(list($id)=db_fetch_row($users)) $recipients[]= new Staff($id); } } foreach( $recipients as $k=>$staff){ if(!$staff || !is_object($staff) || !$staff->isAvailable()) continue; if(in_array($staff->getEmail(),$sentlist)) continue; //avoid duplicate emails. $alert = str_replace("%staff",$staff->getFirstName(),$body); $email->send($staff->getEmail(),$subj,$alert); $sentlist[]=$staff->getEmail(); } } }else { Sys::log(LOG_WARNING,'Template Fetch Error',"Unable to fetch 'new ticket' alert template #$tplId"); } } } return $ticket; }