function create($var, &$errors, $origin, $autorespond = true, $alertstaff = true) { global $cfg, $thisclient, $_FILES; /* Coders never code so fully and joyfully as when they do it for free - Peter Rotich */ $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'); 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['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'; //We don't want to tell the user the real reason...Psssst. Sys::log(LOG_WARNING, 'Ticket denied', 'Banned email - ' . $var['email']); //We need to let admin know which email got banned. } 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 [ ' . Format::htmlchars($_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 && strcasecmp($origin, 'staff')) { $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\nNotice only sent once"; 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. $priorityId = $var['pri']; $source = ucfirst($var['source']); $topic = NULL; // Intenal mapping magic...see if we need to overwrite anything if (isset($var['topicId'])) { //Ticket created via web by user/or staff if ($var['topicId'] && ($topic = new Topic($var['topicId'])) && $topic->getId()) { $deptId = $deptId ? $deptId : $topic->getDeptId(); $priorityId = $priorityId ? $priorityId : $topic->getPriorityId(); $topicDesc = $topic->getName(); if ($autorespond) { $autorespond = $topic->autoRespond(); } } $source = $var['source'] ? $var['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']); } //Don't auto respond to mailer daemons. if (strpos(strtolower($var['email']), 'mailer-daemon@') !== false || strpos(strtolower($var['email']), 'postmaster@') !== false) { $autorespond = false; } //Last minute checks $priorityId = $priorityId ? $priorityId : $cfg->getDefaultPriorityId(); $deptId = $deptId ? $deptId : $cfg->getDefaultDeptId(); $topicId = $var['topicId'] ? $var['topicId'] : 0; $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) . ',topic_id=' . db_input($topicId) . ',priority_id=' . db_input($priorityId) . ',email=' . db_input($var['email']) . ',name=' . db_input(Format::striptags($var['name'])) . ',subject=' . db_input(Format::striptags($var['subject'])) . ',helptopic=' . db_input(Format::striptags($topicDesc)) . ',phone="' . db_input($var['phone'], false) . '"' . ',phone_ext=' . db_input($var['phone_ext'] ? $var['phone_ext'] : '') . ',ip_address=' . db_input($ipaddress) . ',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; }
function create($vars, &$errors, $origin, $autorespond = true, $alertstaff = true) { global $cfg, $thisclient, $_FILES; //Make sure the email is not banned if ($vars['email'] && EmailFilter::isBanned($vars['email'])) { $errors['err'] = 'Ticket denied. Error #403'; Sys::log(LOG_WARNING, 'Ticket denied', 'Banned email - ' . $vars['email']); return 0; } $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'); switch (strtolower($origin)) { case 'web': $fields['topicId'] = array('type' => 'int', 'required' => 1, 'error' => 'Select help topic'); break; case 'staff': $fields['deptId'] = array('type' => 'int', 'required' => 1, 'error' => 'Dept. 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'); break; case 'email': $fields['emailId'] = array('type' => 'int', 'required' => 1, 'error' => 'Email unknown'); break; default: # TODO: Return error message $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'); if (!Validator::process($fields, $vars, $errors) && !$errors['err']) { $errors['err'] = 'Missing or invalid data - check the errors and try again'; } //Make sure phone extension is valid if ($vars['phone_ext']) { if (!is_numeric($vars['phone_ext']) && !$errors['phone']) { $errors['phone'] = 'Invalid phone ext.'; } elseif (!$vars['phone']) { //make sure they just didn't enter ext without phone # XXX: reconsider allowing! $errors['phone'] = 'Phone number required'; } } //Make sure the due date is valid if ($vars['duedate']) { if (!$vars['time'] || strpos($vars['time'], ':') === false) { $errors['time'] = 'Select time'; } elseif (strtotime($vars['duedate'] . ' ' . $vars['time']) === false) { $errors['duedate'] = 'Invalid duedate'; } elseif (strtotime($vars['duedate'] . ' ' . $vars['time']) <= time()) { $errors['duedate'] = 'Due date must be in the future'; } } //check attachment..if any is set ...only set on webbased tickets.. //XXX:?? Create ticket anyway and simply drop the attachments?? We're already doing so with emails. if ($_FILES['attachment']['name'] && $cfg->allowOnlineAttachments()) { if (!$cfg->canUploadFileType($_FILES['attachment']['name'])) { $errors['attachment'] = 'Invalid file type [ ' . Format::htmlchars($_FILES['attachment']['name']) . ' ]'; } elseif ($_FILES['attachment']['size'] > $cfg->getMaxFileSize()) { $errors['attachment'] = 'File is too big. Max ' . $cfg->getMaxFileSize() . ' bytes allowed'; } } # Perform email filter actions on the new ticket arguments XXX: Move filter to the top and check for reject... if (!$errors && ($ef = new EmailFilter($vars))) { $ef->apply($vars); } # Some things will need to be unpacked back into the scope of this # function 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?? if ($vars['email'] && !$errors && $cfg->getMaxOpenTickets() > 0 && strcasecmp($origin, 'staff')) { $openTickets = Ticket::getOpenTicketsByEmail($vars['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 ($vars['deptId']) { $dept = Dept::lookup($vars['deptId']); } if (!$dept || !($tpl = $dept->getTemplate())) { $tpl = $cfg->getDefaultTemplate(); } if (!$dept || !($email = $dept->getAutoRespEmail())) { $email = $cfg->getDefaultEmail(); } if ($tpl && ($msg = $tpl->getOverlimitMsgTemplate()) && $email) { $body = str_replace('%name', $vars['name'], $msg['body']); $body = str_replace('%email', $vars['email'], $msg['body']); $body = str_replace('%url', $cfg->getBaseUrl(), $body); $body = str_replace('%signature', $dept && $dept->isPublic() ? $dept->getSignature() : '', $body); $email->send($vars['email'], $msg['subj'], $body); } //Log + Alert admin...this might be spammy (no option to disable)...but it is helpful..I think. $msg = 'Support ticket request denied for ' . $vars['email'] . "\n" . 'Open ticket:' . $openTickets . "\n" . 'Max Allowed:' . $cfg->getMaxOpenTickets() . "\n\nNotice only sent once"; Sys::log(LOG_CRIT, 'Overlimit Notice', $msg); } } } //Any error above is fatal. if ($errors) { return 0; } // OK...just do it. $deptId = $vars['deptId']; //pre-selected Dept if any. $priorityId = $vars['pri']; $source = ucfirst($vars['source']); $topic = NULL; // Intenal mapping magic...see if we need to overwrite anything if (isset($vars['topicId']) && ($topic = Topic::lookup($vars['topicId']))) { //Ticket created via web by user/or staff $deptId = $deptId ? $deptId : $topic->getDeptId(); $priorityId = $priorityId ? $priorityId : $topic->getPriorityId(); if ($autorespond) { $autorespond = $topic->autoRespond(); } $source = $vars['source'] ? $vars['source'] : 'Web'; } elseif ($vars['emailId'] && !$vars['deptId'] && ($email = Email::lookup($vars['emailId']))) { //Emailed Tickets $deptId = $email->getDeptId(); $priorityId = $priorityId ? $priorityId : $email->getPriorityId(); if ($autorespond) { $autorespond = $email->autoRespond(); } $email = null; $source = 'Email'; } elseif ($vars['deptId']) { //Opened by staff. $deptId = $vars['deptId']; $source = ucfirst($vars['source']); } //Last minute checks $priorityId = $priorityId ? $priorityId : $cfg->getDefaultPriorityId(); $deptId = $deptId ? $deptId : $cfg->getDefaultDeptId(); $topicId = $vars['topicId'] ? $vars['topicId'] : 0; $ipaddress = $vars['ip'] ? $vars['ip'] : $_SERVER['REMOTE_ADDR']; //We are ready son...hold on to the rails. $extId = Ticket::genExtRandID(); $sql = 'INSERT INTO ' . TICKET_TABLE . ' SET created=NOW() ' . ' ,lastmessage= NOW()' . ' ,ticketID=' . db_input($extId) . ' ,dept_id=' . db_input($deptId) . ' ,topic_id=' . db_input($topicId) . ' ,priority_id=' . db_input($priorityId) . ' ,email=' . db_input($vars['email']) . ' ,name=' . db_input(Format::striptags($vars['name'])) . ' ,subject=' . db_input(Format::striptags($vars['subject'])) . ' ,phone="' . db_input($vars['phone'], false) . '"' . ' ,phone_ext=' . db_input($vars['phone_ext'] ? $vars['phone_ext'] : '') . ' ,ip_address=' . db_input($ipaddress) . ' ,source=' . db_input($source); //Make sure the origin is staff - avoid firebug hack! if ($vars['duedate'] && !strcasecmp($origin, 'staff')) { $sql .= ' ,duedate=' . db_input(date('Y-m-d G:i', Misc::dbtime($vars['duedate'] . ' ' . $vars['time']))); } if (!db_query($sql) || !($id = db_insert_id()) || !($ticket = Ticket::lookup($id))) { return null; } /* -------------------- POST CREATE ------------------------ */ $dept = $ticket->getDept(); 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 . ' LIMIT 1'); //TODO: RETHING what happens if this fails?? [At the moment on failure random ID is used...making stuff usable] } //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']); //Auto assign staff or team - auto assignment based on filter rules. if ($vars['staffId'] && !$vars['assignId']) { $ticket->assignToStaff($vars['staffId'], 'auto-assignment'); } if ($vars['teamId'] && !$vars['assignId']) { $ticket->assignToTeam($vars['teamId'], 'auto-assignment'); } /********** double check auto-response ************/ //Overwrite auto responder if the FROM email is one of the internal emails...loop control. if ($autorespond && Email::getIdByEmail($ticket->getEmail())) { $autorespond = false; } if ($autorespond && $dept && !$dept->autoRespONNewTicket()) { $autorespond = false; } # Messages that are clearly auto-responses from email systems should # not have a return 'ping' message if ($autorespond && $vars['header'] && EmailFilter::isAutoResponse(Mail_Parse::splitHeaders($vars['header']))) { $autorespond = false; } //Don't auto respond to mailer daemons. if ($autorespond && (strpos(strtolower($vars['email']), 'mailer-daemon@') !== false || strpos(strtolower($vars['email']), 'postmaster@') !== false)) { $autorespond = false; } /***** See if we need to send some alerts ****/ $ticket->onNewTicket($vars['message'], $autorespond, $alertstaff); return $ticket; }
function create($vars, &$errors, $origin, $autorespond = true, $alertstaff = true) { global $cfg, $thisclient, $_FILES; //Check for 403 if ($vars['email'] && Validator::is_email($vars['email'])) { //Make sure the email address is not banned if (EmailFilter::isBanned($vars['email'])) { $errors['err'] = 'Ticket denied. Error #403'; Sys::log(LOG_WARNING, 'Ticket denied', 'Banned email - ' . $vars['email']); return 0; } //Make sure the open ticket limit hasn't been reached. (LOOP CONTROL) if ($cfg->getMaxOpenTickets() > 0 && strcasecmp($origin, 'staff') && ($client = Client::lookupByEmail($vars['email'])) && ($openTickets = $client->getNumOpenTickets()) && $opentickets >= $cfg->getMaxOpenTickets()) { $errors['err'] = "You've reached the maximum open tickets allowed."; Sys::log(LOG_WARNING, 'Ticket denied -' . $vars['email'], sprintf('Max open tickets (%d) reached for %s ', $cfg->getMaxOpenTickets(), $vars['email'])); return 0; } } // Make sure email contents should not be rejected if (($email_filter = new EmailFilter($vars)) && ($filter = $email_filter->shouldReject())) { $errors['err'] = 'Ticket denied. Error #403'; Sys::log(LOG_WARNING, 'Ticket denied', sprintf('Banned email - %s by filter "%s"', $vars['email'], $filter->getName())); return 0; } $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'); switch (strtolower($origin)) { case 'web': $fields['topicId'] = array('type' => 'int', 'required' => 1, 'error' => 'Select help topic'); break; case 'staff': $fields['deptId'] = array('type' => 'int', 'required' => 1, 'error' => 'Dept. 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'); break; case 'email': $fields['emailId'] = array('type' => 'int', 'required' => 1, 'error' => 'Email unknown'); break; default: # TODO: Return error message $errors['err'] = $errors['origin'] = 'Invalid origin given'; } $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'; } //Make sure phone extension is valid if ($vars['phone_ext']) { if (!is_numeric($vars['phone_ext']) && !$errors['phone']) { $errors['phone'] = 'Invalid phone ext.'; } elseif (!$vars['phone']) { //make sure they just didn't enter ext without phone # XXX: reconsider allowing! $errors['phone'] = 'Phone number required'; } } //Make sure the due date is valid if ($vars['duedate']) { if (!$vars['time'] || strpos($vars['time'], ':') === false) { $errors['time'] = 'Select time'; } elseif (strtotime($vars['duedate'] . ' ' . $vars['time']) === false) { $errors['duedate'] = 'Invalid duedate'; } elseif (strtotime($vars['duedate'] . ' ' . $vars['time']) <= time()) { $errors['duedate'] = 'Due date must be in the future'; } } # Perform email filter actions on the new ticket arguments XXX: Move filter to the top and check for reject... if (!$errors && $email_filter) { $email_filter->apply($vars); } # Some things will need to be unpacked back into the scope of this # function if (isset($vars['autorespond'])) { $autorespond = $vars['autorespond']; } //Any error above is fatal. if ($errors) { return 0; } // OK...just do it. $deptId = $vars['deptId']; //pre-selected Dept if any. $priorityId = $vars['priorityId']; $source = ucfirst($vars['source']); $topic = NULL; // Intenal mapping magic...see if we need to overwrite anything if (isset($vars['topicId']) && ($topic = Topic::lookup($vars['topicId']))) { //Ticket created via web by user/or staff $deptId = $deptId ? $deptId : $topic->getDeptId(); $priorityId = $priorityId ? $priorityId : $topic->getPriorityId(); if ($autorespond) { $autorespond = $topic->autoRespond(); } $source = $vars['source'] ? $vars['source'] : 'Web'; } elseif ($vars['emailId'] && !$vars['deptId'] && ($email = Email::lookup($vars['emailId']))) { //Emailed Tickets $deptId = $email->getDeptId(); $priorityId = $priorityId ? $priorityId : $email->getPriorityId(); if ($autorespond) { $autorespond = $email->autoRespond(); } $email = null; $source = 'Email'; } elseif ($vars['deptId']) { //Opened by staff. $deptId = $vars['deptId']; $source = ucfirst($vars['source']); } //Last minute checks $priorityId = $priorityId ? $priorityId : $cfg->getDefaultPriorityId(); $deptId = $deptId ? $deptId : $cfg->getDefaultDeptId(); $topicId = $vars['topicId'] ? $vars['topicId'] : 0; $ipaddress = $vars['ip'] ? $vars['ip'] : $_SERVER['REMOTE_ADDR']; //We are ready son...hold on to the rails. $extId = Ticket::genExtRandID(); $sql = 'INSERT INTO ' . TICKET_TABLE . ' SET created=NOW() ' . ' ,lastmessage= NOW()' . ' ,ticketID=' . db_input($extId) . ' ,dept_id=' . db_input($deptId) . ' ,topic_id=' . db_input($topicId) . ' ,priority_id=' . db_input($priorityId) . ' ,email=' . db_input($vars['email']) . ' ,name=' . db_input(Format::striptags($vars['name'])) . ' ,subject=' . db_input(Format::striptags($vars['subject'])) . ' ,phone="' . db_input($vars['phone'], false) . '"' . ' ,phone_ext=' . db_input($vars['phone_ext'] ? $vars['phone_ext'] : '') . ' ,ip_address=' . db_input($ipaddress) . ' ,source=' . db_input($source); //Make sure the origin is staff - avoid firebug hack! if ($vars['duedate'] && !strcasecmp($origin, 'staff')) { $sql .= ' ,duedate=' . db_input(date('Y-m-d G:i', Misc::dbtime($vars['duedate'] . ' ' . $vars['time']))); } if (!db_query($sql) || !($id = db_insert_id()) || !($ticket = Ticket::lookup($id))) { return null; } /* -------------------- POST CREATE ------------------------ */ $dept = $ticket->getDept(); 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 . ' LIMIT 1'); //TODO: RETHING what happens if this fails?? [At the moment on failure random ID is used...making stuff usable] } //post the message. $msgid = $ticket->postMessage($vars['message'], $source, $vars['mid'], $vars['header'], true); // Configure service-level-agreement for this ticket $ticket->selectSLAId($vars['slaId']); //Auto assign staff or team - auto assignment based on filter rules. if ($vars['staffId'] && !$vars['assignId']) { $ticket->assignToStaff($vars['staffId'], 'auto-assignment'); } if ($vars['teamId'] && !$vars['assignId']) { $ticket->assignToTeam($vars['teamId'], 'auto-assignment'); } /********** double check auto-response ************/ //Overwrite auto responder if the FROM email is one of the internal emails...loop control. if ($autorespond && Email::getIdByEmail($ticket->getEmail())) { $autorespond = false; } if ($autorespond && $dept && !$dept->autoRespONNewTicket()) { $autorespond = false; } # Messages that are clearly auto-responses from email systems should # not have a return 'ping' message if ($autorespond && $vars['header'] && EmailFilter::isAutoResponse(Mail_Parse::splitHeaders($vars['header']))) { $autorespond = false; } //Don't auto respond to mailer daemons. if ($autorespond && (strpos(strtolower($vars['email']), 'mailer-daemon@') !== false || strpos(strtolower($vars['email']), 'postmaster@') !== false)) { $autorespond = false; } /***** See if we need to send some alerts ****/ $ticket->onNewTicket($vars['message'], $autorespond, $alertstaff); /************ check if the user JUST reached the max. open tickets limit **********/ if ($cfg->getMaxOpenTickets() > 0 && ($client = $ticket->getClient()) && $client->getNumOpenTickets() == $cfg->getMaxOpenTickets()) { $ticket->onOpenLimit($autorespond && strcasecmp($origin, 'staff')); } /* Phew! ... time for tea (KETEPA) */ return $ticket; }
static function create($vars, &$errors, $origin, $autorespond = true, $alertstaff = true) { global $ost, $cfg, $thisclient, $_FILES; // Don't enforce form validation for email $field_filter = function ($type) use($origin) { return function ($f) use($origin, $type) { // Ultimately, only offer validation errors for web for // non-internal fields. For email, no validation can be // performed. For other origins, validate as usual switch (strtolower($origin)) { case 'email': return false; case 'staff': // Required 'Contact Information' fields aren't required // when staff open tickets return $type != 'user' || in_array($f->get('name'), array('name', 'email')); case 'web': return !$f->get('private'); default: return true; } }; }; $reject_ticket = function ($message) use(&$errors) { global $ost; $errors = array('errno' => 403, 'err' => __('This help desk is for use by authorized users only')); $ost->logWarning(_S('Ticket Denied'), $message, false); return 0; }; Signal::send('ticket.create.before', null, $vars); // Create and verify the dynamic form entry for the new ticket $form = TicketForm::getNewInstance(); $form->setSource($vars); // If submitting via email or api, ensure we have a subject and such if (!in_array(strtolower($origin), array('web', 'staff'))) { foreach ($form->getFields() as $field) { $fname = $field->get('name'); if ($fname && isset($vars[$fname]) && !$field->value) { $field->value = $field->parse($vars[$fname]); } } } if (!$form->isValid($field_filter('ticket'))) { $errors += $form->errors(); } if ($vars['uid']) { $user = User::lookup($vars['uid']); } $id = 0; $fields = array(); $fields['message'] = array('type' => '*', 'required' => 1, 'error' => __('Message content is required')); switch (strtolower($origin)) { case 'web': $fields['topicId'] = array('type' => 'int', 'required' => 1, 'error' => __('Select a help topic')); break; case 'staff': $fields['deptId'] = array('type' => 'int', 'required' => 0, 'error' => __('Department selection is required')); $fields['topicId'] = array('type' => 'int', 'required' => 1, 'error' => __('Help topic selection is required')); $fields['duedate'] = array('type' => 'date', 'required' => 0, 'error' => __('Invalid date format - must be MM/DD/YY')); case 'api': $fields['source'] = array('type' => 'string', 'required' => 1, 'error' => __('Indicate ticket source')); break; case 'email': $fields['emailId'] = array('type' => 'int', 'required' => 1, 'error' => __('Unknown system email')); break; default: # TODO: Return error message $errors['err'] = $errors['origin'] = __('Invalid ticket origin given'); } if (!Validator::process($fields, $vars, $errors) && !$errors['err']) { $errors['err'] = __('Missing or invalid data - check the errors and try again'); } //Make sure the due date is valid if ($vars['duedate']) { if (!$vars['time'] || strpos($vars['time'], ':') === false) { $errors['time'] = __('Select a time from the list'); } elseif (strtotime($vars['duedate'] . ' ' . $vars['time']) === false) { $errors['duedate'] = __('Invalid due date'); } elseif (strtotime($vars['duedate'] . ' ' . $vars['time']) <= time()) { $errors['duedate'] = __('Due date must be in the future'); } } if (!$errors) { # Perform ticket filter actions on the new ticket arguments $__form = null; if ($vars['topicId']) { if (($__topic = Topic::lookup($vars['topicId'])) && ($__form = $__topic->getForm())) { $__form = $__form->instanciate(); $__form->setSource($vars); } } try { $vars = self::filterTicketData($origin, $vars, array($form, $__form), $user); } catch (RejectedException $ex) { return $reject_ticket(sprintf(_S('Ticket rejected (%s) by filter "%s"'), $ex->vars['email'], $ex->getRejectingFilter()->getName())); } //Make sure the open ticket limit hasn't been reached. (LOOP CONTROL) if ($cfg->getMaxOpenTickets() > 0 && strcasecmp($origin, 'staff') && ($_user = TicketUser::lookupByEmail($vars['email'])) && ($openTickets = $_user->getNumOpenTickets()) && $openTickets >= $cfg->getMaxOpenTickets()) { $errors = array('err' => __("You've reached the maximum open tickets allowed.")); $ost->logWarning(sprintf(_S('Ticket denied - %s'), $vars['email']), sprintf(_S('Max open tickets (%1$d) reached for %2$s'), $cfg->getMaxOpenTickets(), $vars['email']), false); return 0; } // Allow vars to be changed in ticket filter and applied to the user // account created or detected if (!$user && $vars['email']) { $user = User::lookupByEmail($vars['email']); } if (!$user) { // Reject emails if not from registered clients (if // configured) if (strcasecmp($origin, 'email') === 0 && !$cfg->acceptUnregisteredEmail()) { list($mailbox, $domain) = explode('@', $vars['email'], 2); // Users not yet created but linked to an organization // are still acceptable if (!Organization::forDomain($domain)) { return $reject_ticket(sprintf(_S('Ticket rejected (%s) (unregistered client)'), $vars['email'])); } } $user_form = UserForm::getUserForm()->getForm($vars); if (!$user_form->isValid($field_filter('user')) || !($user = User::fromVars($user_form->getClean()))) { $errors['user'] = __('Incomplete client information'); } } } if ($vars['topicId']) { if ($topic = Topic::lookup($vars['topicId'])) { if ($topic_form = $topic->getForm()) { $TF = $topic_form->getForm($vars); $topic_form = $topic_form->instanciate(); $topic_form->setSource($vars); if (!$TF->isValid($field_filter('topic'))) { $errors = array_merge($errors, $TF->errors()); } } } else { $errors['topicId'] = 'Invalid help topic selected'; } } // Any error above is fatal. if ($errors) { return 0; } Signal::send('ticket.create.validated', null, $vars); # Some things will need to be unpacked back into the scope of this # function if (isset($vars['autorespond'])) { $autorespond = $vars['autorespond']; } # Apply filter-specific priority if ($vars['priorityId']) { $form->setAnswer('priority', null, $vars['priorityId']); } // If the filter specifies a help topic which has a form associated, // and there was previously either no help topic set or the help // topic did not have a form, there's no need to add it now as (1) // validation is closed, (2) there may be a form already associated // and filled out from the original help topic, and (3) staff // members can always add more forms now // OK...just do it. $statusId = $vars['statusId']; $deptId = $vars['deptId']; //pre-selected Dept if any. $source = ucfirst($vars['source']); // Apply email settings for emailed tickets. Email settings should // trump help topic settins if the email has an associated help // topic if ($vars['emailId'] && ($email = Email::lookup($vars['emailId']))) { $deptId = $deptId ?: $email->getDeptId(); $priority = $form->getAnswer('priority'); if (!$priority || !$priority->getIdValue()) { $form->setAnswer('priority', null, $email->getPriorityId()); } if ($autorespond) { $autorespond = $email->autoRespond(); } if (!isset($topic) && ($T = $email->getTopic()) && $T->isActive()) { $topic = $T; } $email = null; $source = 'Email'; } if (!isset($topic)) { // This may return NULL, no big deal $topic = $cfg->getDefaultTopic(); } // Intenal mapping magic...see if we need to override anything if (isset($topic)) { $deptId = $deptId ?: $topic->getDeptId(); $statusId = $statusId ?: $topic->getStatusId(); $priority = $form->getAnswer('priority'); if (!$priority || !$priority->getIdValue()) { $form->setAnswer('priority', null, $topic->getPriorityId()); } if ($autorespond) { $autorespond = $topic->autoRespond(); } //Auto assignment. if (!isset($vars['staffId']) && $topic->getStaffId()) { $vars['staffId'] = $topic->getStaffId(); } elseif (!isset($vars['teamId']) && $topic->getTeamId()) { $vars['teamId'] = $topic->getTeamId(); } //set default sla. if (isset($vars['slaId'])) { $vars['slaId'] = $vars['slaId'] ?: $cfg->getDefaultSLAId(); } elseif ($topic && $topic->getSLAId()) { $vars['slaId'] = $topic->getSLAId(); } } // Auto assignment to organization account manager if (($org = $user->getOrganization()) && $org->autoAssignAccountManager() && ($code = $org->getAccountManagerId())) { if (!isset($vars['staffId']) && $code[0] == 's') { $vars['staffId'] = substr($code, 1); } elseif (!isset($vars['teamId']) && $code[0] == 't') { $vars['teamId'] = substr($code, 1); } } // Last minute checks $priority = $form->getAnswer('priority'); if (!$priority || !$priority->getIdValue()) { $form->setAnswer('priority', null, $cfg->getDefaultPriorityId()); } $deptId = $deptId ?: $cfg->getDefaultDeptId(); $statusId = $statusId ?: $cfg->getDefaultTicketStatusId(); $topicId = isset($topic) ? $topic->getId() : 0; $ipaddress = $vars['ip'] ?: $_SERVER['REMOTE_ADDR']; $source = $source ?: 'Web'; //We are ready son...hold on to the rails. $number = $topic ? $topic->getNewTicketNumber() : $cfg->getNewTicketNumber(); $sql = 'INSERT INTO ' . TICKET_TABLE . ' SET created=NOW() ' . ' ,lastmessage= NOW()' . ' ,user_id=' . db_input($user->getId()) . ' ,`number`=' . db_input($number) . ' ,dept_id=' . db_input($deptId) . ' ,topic_id=' . db_input($topicId) . ' ,ip_address=' . db_input($ipaddress) . ' ,source=' . db_input($source); if (isset($vars['emailId']) && $vars['emailId']) { $sql .= ', email_id=' . db_input($vars['emailId']); } //Make sure the origin is staff - avoid firebug hack! if ($vars['duedate'] && !strcasecmp($origin, 'staff')) { $sql .= ' ,duedate=' . db_input(date('Y-m-d G:i', Misc::dbtime($vars['duedate'] . ' ' . $vars['time']))); } if (!db_query($sql) || !($id = db_insert_id()) || !($ticket = Ticket::lookup($id))) { return null; } /* -------------------- POST CREATE ------------------------ */ // Save the (common) dynamic form $form->setTicketId($id); $form->save(); // Save the form data from the help-topic form, if any if ($topic_form) { $topic_form->setTicketId($id); $topic_form->save(); } $ticket->loadDynamicData(); $dept = $ticket->getDept(); // Add organizational collaborators if ($org && $org->autoAddCollabs()) { $pris = $org->autoAddPrimaryContactsAsCollabs(); $members = $org->autoAddMembersAsCollabs(); $settings = array('isactive' => true); $collabs = array(); foreach ($org->allMembers() as $u) { if ($members || $pris && $u->isPrimaryContact()) { if ($c = $ticket->addCollaborator($u, $settings, $errors)) { $collabs[] = (string) $c; } } } //TODO: Can collaborators add others? if ($collabs) { //TODO: Change EndUser to name of user. $ticket->logNote(sprintf(_S('Collaborators for %s organization added'), $org->getName()), implode("<br>", $collabs), $org->getName(), false); } } //post the message. $vars['title'] = $vars['subject']; //Use the initial subject as title of the post. $vars['userId'] = $ticket->getUserId(); $message = $ticket->postMessage($vars, $origin, false); // Configure service-level-agreement for this ticket $ticket->selectSLAId($vars['slaId']); // Assign ticket to staff or team (new ticket by staff) if ($vars['assignId']) { $ticket->assign($vars['assignId'], $vars['note']); } else { // Auto assign staff or team - auto assignment based on filter // rules. Both team and staff can be assigned if ($vars['staffId']) { $ticket->assignToStaff($vars['staffId'], _S('Auto Assignment')); } if ($vars['teamId']) { // No team alert if also assigned to an individual agent $ticket->assignToTeam($vars['teamId'], _S('Auto Assignment'), !$vars['staffId']); } } // Apply requested status — this should be done AFTER assignment, // because if it is requested to be closed, it should not cause the // ticket to be reopened for assignment. if ($statusId) { $ticket->setStatus($statusId, false, false); } /********** double check auto-response ************/ //Override auto responder if the FROM email is one of the internal emails...loop control. if ($autorespond && Email::getIdByEmail($ticket->getEmail())) { $autorespond = false; } # Messages that are clearly auto-responses from email systems should # not have a return 'ping' message if (isset($vars['flags']) && $vars['flags']['bounce']) { $autorespond = false; } if ($autorespond && $message->isAutoReply()) { $autorespond = false; } //post canned auto-response IF any (disables new ticket auto-response). if ($vars['cannedResponseId'] && $ticket->postCannedReply($vars['cannedResponseId'], $message->getId(), $autorespond)) { $ticket->markUnAnswered(); //Leave the ticket as unanswred. $autorespond = false; } //Check department's auto response settings // XXX: Dept. setting doesn't affect canned responses. if ($autorespond && $dept && !$dept->autoRespONNewTicket()) { $autorespond = false; } //Don't send alerts to staff when the message is a bounce // this is necessary to avoid possible loop (especially on new ticket) if ($alertstaff && $message->isBounce()) { $alertstaff = false; } /***** See if we need to send some alerts ****/ $ticket->onNewTicket($message, $autorespond, $alertstaff); /************ check if the user JUST reached the max. open tickets limit **********/ if ($cfg->getMaxOpenTickets() > 0 && ($user = $ticket->getOwner()) && $user->getNumOpenTickets() == $cfg->getMaxOpenTickets()) { $ticket->onOpenLimit($autorespond && strcasecmp($origin, 'staff')); } /* Start tracking ticket lifecycle events */ $ticket->logEvent('created'); // Fire post-create signal (for extra email sending, searching) Signal::send('model.created', $ticket); /* Phew! ... time for tea (KETEPA) */ return $ticket; }
static function create($vars, &$errors, $origin, $autorespond = true, $alertstaff = true) { global $ost, $cfg, $thisclient, $_FILES; // Don't enforce form validation for email $field_filter = function ($type) use($origin) { return function ($f) use($origin, $type) { // Ultimately, only offer validation errors for web for // non-internal fields. For email, no validation can be // performed. For other origins, validate as usual switch (strtolower($origin)) { case 'email': return false; case 'staff': // Required 'Contact Information' fields aren't required // when staff open tickets return $type != 'user' || in_array($f->get('name'), array('name', 'email')); case 'web': return !$f->get('private'); default: return true; } }; }; $reject_ticket = function ($message) use(&$errors) { global $ost; $errors = array('errno' => 403, 'err' => __('This help desk is for use by authorized users only')); $ost->logWarning(_S('Ticket Denied'), $message, false); return 0; }; Signal::send('ticket.create.before', null, $vars); // Create and verify the dynamic form entry for the new ticket $form = TicketForm::getNewInstance(); $form->setSource($vars); // If submitting via email or api, ensure we have a subject and such if (!in_array(strtolower($origin), array('web', 'staff'))) { foreach ($form->getFields() as $field) { $fname = $field->get('name'); if ($fname && isset($vars[$fname]) && !$field->value) { $field->value = $field->parse($vars[$fname]); } } } if (!$form->isValid($field_filter('ticket'))) { $errors += $form->errors(); } /*INICIO Creado por Anthony Parisi 2016-02-01 Con las siguientes lineas de código, se crea el ticket mediante la API.*/ if (!in_array(strtolower($origin), array('web', 'staff'))) { $errors = array(); } /* FIN */ if ($vars['uid']) { $user = User::lookup($vars['uid']); } $id = 0; $fields = array(); $fields['message'] = array('type' => '*', 'required' => 1, 'error' => __('Message content is required')); switch (strtolower($origin)) { case 'web': $fields['topicId'] = array('type' => 'int', 'required' => 1, 'error' => __('Select a help topic')); break; case 'staff': $fields['deptId'] = array('type' => 'int', 'required' => 0, 'error' => __('Department selection is required')); $fields['topicId'] = array('type' => 'int', 'required' => 1, 'error' => __('Help topic selection is required')); $fields['duedate'] = array('type' => 'date', 'required' => 0, 'error' => __('Invalid date format - must be MM/DD/YY')); case 'api': $fields['source'] = array('type' => 'string', 'required' => 1, 'error' => __('Indicate ticket source')); break; case 'email': $fields['emailId'] = array('type' => 'int', 'required' => 1, 'error' => __('Unknown system email')); break; default: # TODO: Return error message $errors['err'] = $errors['origin'] = __('Invalid ticket origin given'); } if (!Validator::process($fields, $vars, $errors) && !$errors['err']) { $errors['err'] = __('Missing or invalid data - check the errors and try again'); } //Make sure the due date is valid if ($vars['duedate']) { if (!$vars['time'] || strpos($vars['time'], ':') === false) { $errors['time'] = __('Select a time from the list'); } elseif (strtotime($vars['duedate'] . ' ' . $vars['time']) === false) { $errors['duedate'] = __('Invalid due date'); } elseif (strtotime($vars['duedate'] . ' ' . $vars['time']) <= time()) { $errors['duedate'] = __('Due date must be in the future'); } } if (!$errors) { # Perform ticket filter actions on the new ticket arguments $__form = null; if ($vars['topicId']) { if (($__topic = Topic::lookup($vars['topicId'])) && ($__form = $__topic->getForm())) { $__form = $__form->instanciate(); $__form->setSource($vars); } } try { $vars = self::filterTicketData($origin, $vars, array($form, $__form), $user); } catch (RejectedException $ex) { return $reject_ticket(sprintf(_S('Ticket rejected (%s) by filter "%s"'), $ex->vars['email'], $ex->getRejectingFilter()->getName())); } //Make sure the open ticket limit hasn't been reached. (LOOP CONTROL) if ($cfg->getMaxOpenTickets() > 0 && strcasecmp($origin, 'staff') && ($_user = TicketUser::lookupByEmail($vars['email'])) && ($openTickets = $_user->getNumOpenTickets()) && $openTickets >= $cfg->getMaxOpenTickets()) { $errors = array('err' => __("You've reached the maximum open tickets allowed.")); $ost->logWarning(sprintf(_S('Ticket denied - %s'), $vars['email']), sprintf(_S('Max open tickets (%1$d) reached for %2$s'), $cfg->getMaxOpenTickets(), $vars['email']), false); return 0; } // Allow vars to be changed in ticket filter and applied to the user // account created or detected if (!$user && $vars['email']) { $user = User::lookupByEmail($vars['email']); } if (!$user) { // Reject emails if not from registered clients (if // configured) if (strcasecmp($origin, 'email') === 0 && !$cfg->acceptUnregisteredEmail()) { list($mailbox, $domain) = explode('@', $vars['email'], 2); // Users not yet created but linked to an organization // are still acceptable if (!Organization::forDomain($domain)) { return $reject_ticket(sprintf(_S('Ticket rejected (%s) (unregistered client)'), $vars['email'])); } } $user_form = UserForm::getUserForm()->getForm($vars); if (!$user_form->isValid($field_filter('user')) || !($user = User::fromVars($user_form->getClean()))) { $errors['user'] = __('Incomplete client information'); } } } if ($vars['topicId']) { if ($topic = Topic::lookup($vars['topicId'])) { if ($topic_form = $topic->getForm()) { $TF = $topic_form->getForm($vars); $topic_form = $topic_form->instanciate(); $topic_form->setSource($vars); if (!$TF->isValid($field_filter('topic'))) { $errors = array_merge($errors, $TF->errors()); } } } else { $errors['topicId'] = 'Invalid help topic selected'; } } // Any error above is fatal. if ($errors) { return 0; } Signal::send('ticket.create.validated', null, $vars); # Some things will need to be unpacked back into the scope of this # function if (isset($vars['autorespond'])) { $autorespond = $vars['autorespond']; } # Apply filter-specific priority if ($vars['priorityId']) { $form->setAnswer('priority', null, $vars['priorityId']); } // If the filter specifies a help topic which has a form associated, // and there was previously either no help topic set or the help // topic did not have a form, there's no need to add it now as (1) // validation is closed, (2) there may be a form already associated // and filled out from the original help topic, and (3) staff // members can always add more forms now // OK...just do it. $statusId = $vars['statusId']; $deptId = $vars['deptId']; //pre-selected Dept if any. $source = ucfirst($vars['source']); // Apply email settings for emailed tickets. Email settings should // trump help topic settins if the email has an associated help // topic if ($vars['emailId'] && ($email = Email::lookup($vars['emailId']))) { $deptId = $deptId ?: $email->getDeptId(); $priority = $form->getAnswer('priority'); if (!$priority || !$priority->getIdValue()) { $form->setAnswer('priority', null, $email->getPriorityId()); } if ($autorespond) { $autorespond = $email->autoRespond(); } if (!isset($topic) && ($T = $email->getTopic()) && $T->isActive()) { $topic = $T; } $email = null; $source = 'Email'; } if (!isset($topic)) { // This may return NULL, no big deal $topic = $cfg->getDefaultTopic(); } // Intenal mapping magic...see if we need to override anything if (isset($topic)) { $deptId = $deptId ?: $topic->getDeptId(); $statusId = $statusId ?: $topic->getStatusId(); $priority = $form->getAnswer('priority'); if (!$priority || !$priority->getIdValue()) { $form->setAnswer('priority', null, $topic->getPriorityId()); } if ($autorespond) { $autorespond = $topic->autoRespond(); } //Auto assignment. if (!isset($vars['staffId']) && $topic->getStaffId()) { $vars['staffId'] = $topic->getStaffId(); } elseif (!isset($vars['teamId']) && $topic->getTeamId()) { $vars['teamId'] = $topic->getTeamId(); } //set default sla. if (isset($vars['slaId'])) { $vars['slaId'] = $vars['slaId'] ?: $cfg->getDefaultSLAId(); } elseif ($topic && $topic->getSLAId()) { $vars['slaId'] = $topic->getSLAId(); } } // Auto assignment to organization account manager if (($org = $user->getOrganization()) && $org->autoAssignAccountManager() && ($code = $org->getAccountManagerId())) { if (!isset($vars['staffId']) && $code[0] == 's') { $vars['staffId'] = substr($code, 1); } elseif (!isset($vars['teamId']) && $code[0] == 't') { $vars['teamId'] = substr($code, 1); } } // Last minute checks $priority = $form->getAnswer('priority'); if (!$priority || !$priority->getIdValue()) { $form->setAnswer('priority', null, $cfg->getDefaultPriorityId()); } $deptId = $deptId ?: $cfg->getDefaultDeptId(); $statusId = $statusId ?: $cfg->getDefaultTicketStatusId(); $topicId = isset($topic) ? $topic->getId() : 0; $ipaddress = $vars['ip'] ?: $_SERVER['REMOTE_ADDR']; $source = $source ?: 'Web'; //We are ready son...hold on to the rails. $number = $topic ? $topic->getNewTicketNumber() : $cfg->getNewTicketNumber(); $sql = 'INSERT INTO ' . TICKET_TABLE . ' SET created=NOW() ' . ' ,lastmessage= NOW()' . ' ,user_id=' . db_input($user->getId()) . ' ,`number`=' . db_input($number) . ' ,dept_id=' . db_input($deptId) . ' ,topic_id=' . db_input($topicId) . ' ,ip_address=' . db_input($ipaddress) . ' ,source=' . db_input($source); if (isset($vars['emailId']) && $vars['emailId']) { $sql .= ', email_id=' . db_input($vars['emailId']); } //Make sure the origin is staff - avoid firebug hack! if ($vars['duedate'] && !strcasecmp($origin, 'staff')) { $sql .= ' ,duedate=' . db_input(date('Y-m-d G:i', Misc::dbtime($vars['duedate'] . ' ' . $vars['time']))); } if (!db_query($sql) || !($id = db_insert_id()) || !($ticket = Ticket::lookup($id))) { return null; } /* -------------------- POST CREATE ------------------------ */ // Save the (common) dynamic form $form->setTicketId($id); $form->save(); // Save the form data from the help-topic form, if any if ($topic_form) { $topic_form->setTicketId($id); $topic_form->save(); } $ticket->loadDynamicData(); $dept = $ticket->getDept(); // Add organizational collaborators if ($org && $org->autoAddCollabs()) { $pris = $org->autoAddPrimaryContactsAsCollabs(); $members = $org->autoAddMembersAsCollabs(); $settings = array('isactive' => true); $collabs = array(); foreach ($org->allMembers() as $u) { if ($members || $pris && $u->isPrimaryContact()) { if ($c = $ticket->addCollaborator($u, $settings, $errors)) { $collabs[] = (string) $c; } } } //TODO: Can collaborators add others? if ($collabs) { //TODO: Change EndUser to name of user. $ticket->logNote(sprintf(_S('Collaborators for %s organization added'), $org->getName()), implode("<br>", $collabs), $org->getName(), false); } } //post the message. $vars['title'] = $vars['subject']; //Use the initial subject as title of the post. $vars['userId'] = $ticket->getUserId(); $message = $ticket->postMessage($vars, $origin, false); // Configure service-level-agreement for this ticket $ticket->selectSLAId($vars['slaId']); // Assign ticket to staff or team (new ticket by staff) if ($vars['assignId']) { $ticket->assign($vars['assignId'], $vars['note']); } else { // Auto assign staff or team - auto assignment based on filter // rules. Both team and staff can be assigned if ($vars['staffId']) { $ticket->assignToStaff($vars['staffId'], _S('Auto Assignment')); } if ($vars['teamId']) { // No team alert if also assigned to an individual agent $ticket->assignToTeam($vars['teamId'], _S('Auto Assignment'), !$vars['staffId']); } } // Apply requested status — this should be done AFTER assignment, // because if it is requested to be closed, it should not cause the // ticket to be reopened for assignment. if ($statusId) { $ticket->setStatus($statusId, false, false); } /********** double check auto-response ************/ //Override auto responder if the FROM email is one of the internal emails...loop control. if ($autorespond && Email::getIdByEmail($ticket->getEmail())) { $autorespond = false; } # Messages that are clearly auto-responses from email systems should # not have a return 'ping' message if (isset($vars['flags']) && $vars['flags']['bounce']) { $autorespond = false; } if ($autorespond && $message->isAutoReply()) { $autorespond = false; } //post canned auto-response IF any (disables new ticket auto-response). if ($vars['cannedResponseId'] && $ticket->postCannedReply($vars['cannedResponseId'], $message->getId(), $autorespond)) { $ticket->markUnAnswered(); //Leave the ticket as unanswred. $autorespond = false; } //Check department's auto response settings // XXX: Dept. setting doesn't affect canned responses. if ($autorespond && $dept && !$dept->autoRespONNewTicket()) { $autorespond = false; } //Don't send alerts to staff when the message is a bounce // this is necessary to avoid possible loop (especially on new ticket) if ($alertstaff && $message->isBounce()) { $alertstaff = false; } /***** See if we need to send some alerts ****/ $ticket->onNewTicket($message, $autorespond, $alertstaff); /************ check if the user JUST reached the max. open tickets limit **********/ if ($cfg->getMaxOpenTickets() > 0 && ($user = $ticket->getOwner()) && $user->getNumOpenTickets() == $cfg->getMaxOpenTickets()) { $ticket->onOpenLimit($autorespond && strcasecmp($origin, 'staff')); } /* Start tracking ticket lifecycle events */ $ticket->logEvent('created'); // Fire post-create signal (for extra email sending, searching) Signal::send('model.created', $ticket); /*INICIO Anthony Parisi 2016-02-05 Con las siguientes lineas de código, se actualizan los campos de Detalle de su Solicitud en las tablas descritas en la Sentencia SQL*/ if (!in_array(strtolower($origin), array('web', 'staff'))) { //echo "<pre>"; //var_dump($vars); //die($vars['valores']); foreach ($ticket as $key => $value) { if ($key == "id") { $ticket_idAPI = $value; } if ($key == "last_message") { $last_message = $value; $datos = explode("\n", $last_message); $nombre = $vars['name']; $correo = $vars['email']; $telefono = $vars['phone']; $valores = $vars['valores']; $adicional = explode("%%", $valores); //die($adicional[4]); /*$nombre = ucwords(strtolower(substr($datos[0], 20, strlen($datos[0])-21))); $correo = strtolower(substr($datos[1], 20, strlen($datos[1])-21)); $telefono = substr($datos[2], 22, strlen($datos[2])-23); $i = 5; $mensaje = ""; while(strpos($datos[$i], "------------------------------------------------------") === false){ $mensaje .= $datos[$i]; $i++; } for($i=5;$i < (count($datos)-6);$i++){ if(strpos($datos[$i], "TIPO DE PASAJE: ") > -1) $pasaje = substr($datos[$i], 28, strlen($datos[$i])-29); elseif(strpos($datos[$i], "CIUDAD DE ORIGEN: ") > -1) $origen = substr($datos[$i], 18, strlen($datos[$i])-19); elseif(strpos($datos[$i], "CIUDAD DE DESTINO: ") > -1) $destino = substr($datos[$i], 21, strlen($datos[$i])-22); elseif(strpos($datos[$i], "FECHA DE SALIDA: ") > -1) $salida = substr($datos[$i], 17, strlen($datos[$i])-18); elseif(strpos($datos[$i], "FECHA DE REGRESO: ") > -1) $regreso = substr($datos[$i], 20, strlen($datos[$i])-21); elseif(strpos($datos[$i], "CLASE: ") > -1) $clase = substr($datos[$i], 19, strlen($datos[$i])-20); elseif(strpos($datos[$i], "AEROL") > -1) $aerolinea = substr($datos[$i], 14, strlen($datos[$i])-15); } $adultos = substr($datos[count($datos)-5], 9, strlen($datos[count($datos)-5])-10); $mayores = substr($datos[count($datos)-4], 11, strlen($datos[count($datos)-4])-12); $ninos = substr($datos[count($datos)-3], 9, strlen($datos[count($datos)-3])-10); $bebes = substr($datos[count($datos)-2], 8, strlen($datos[count($datos)-2])-9);*/ } } $detail = '{"88":"Cotizacion PopPup"}'; $mysqli = new mysqli(DBHOST, DBUSER, DBPASS, DBNAME); $mysqli->query("UPDATE `ost_form_entry_values` SET `value` = '{$detail}' WHERE field_id = '20' AND `entry_id` = (SELECT id FROM ost_form_entry WHERE object_id = '{$ticket_idAPI}' AND object_type = 'T');"); $mysqli->query("INSERT INTO `ost_ticket__cdata` SET `subject`='88', `ticket_id`= '{$ticket_idAPI}' ON DUPLICATE KEY UPDATE `subject`='88';"); $sqlUser = $mysqli->query("SELECT id FROM ost_user WHERE id = '" . $user->getId() . "' AND `org_id` = 30 LIMIT 1;"); $rowUser = mysqli_num_rows($sqlUser); if ($rowUser <= 0) { $mysqli->query("UPDATE ost_user SET `org_id` = 30, `updated` = NOW() WHERE id = " . $user->getId() . " LIMIT 1;"); } $mysqli->query("INSERT INTO \n `ost_cotizaciones` (\n `ticket_id`, \n `nombre`, \n `correo`, \n `telefono`, \n `mensaje`, \n `tipo_vuelo`, \n `origen`, \n `destino`, \n `salida`, \n `regreso`, \n `clase`, \n `aerolinea`, \n `adultos`, \n `mayores`, \n `ninos`, \n `bebe`) \n VALUES (\n '{$ticket_idAPI}', \n '{$nombre}', \n '{$correo}', \n '{$telefono}', \n '{$adicional['0']}', \n '{$adicional['1']}', \n '{$adicional['2']}', \n '{$adicional['3']}', \n '{$adicional['4']}', \n '{$adicional['5']}', \n '{$adicional['6']}', \n '{$adicional['7']}', \n '{$adicional['8']}', \n '{$adicional['9']}', \n '{$adicional['10']}', \n '{$adicional['11']}');"); } /* FIN */ /* Phew! ... time for tea (KETEPA) */ return $ticket; }