<?php /** * class that handles most ticket related functions. * the ticket class is used for most ticketing related functions, it also holds some wrapper functions. * @author Daan Janssens, mentored by Matthew Lagoe */ class Ticket{ private $tId; /**< The id of ticket */ private $timestamp; /**< Timestamp of the ticket */ private $title; /**< Title of the ticket */ private $status; /**< Status of the ticket (0 = waiting on user reply, 1 = waiting on support, (2= not used atm), 3 = closed */ private $queue; /**< (not in use atm) */ private $ticket_category; /**< the id of the category belonging to the ticket */ private $author; /**< The ticket_users id */ private $priority; /**< The priority of the ticket where 0 = low, 3= supadupahigh */ ////////////////////////////////////////////Functions//////////////////////////////////////////////////// /** * check if a ticket exists. * @param $id the id of the ticket to be checked. * @return true if the ticket exists, else false. */ public static function ticketExists($id) { $dbl = new DBLayer("lib"); //check if ticket exists if( $dbl->select("`ticket`", array('ticket_id' => $id), "`TId` = :ticket_id")->rowCount() ){ return true; }else{ return false; } } /** * return an array of the possible statuses * @return an array containing the string values that represent the different statuses. */ public static function getStatusArray() { return Array("Waiting on user reply","Waiting on support","Waiting on Dev reply","Closed"); } /** * return an array of the possible priorities * @return an array containing the string values that represent the different priorities. */ public static function getPriorityArray() { return Array("Low","Normal","High","Super Dupa High"); } /** * return an entire ticket. * returns the ticket object and an array of all replies to that ticket. * @param $id the id of the ticket. * @param $view_as_admin true if the viewer of the ticket is a mod, else false (depending on this it will also show the hidden comments) * @return an array containing the 'ticket_obj' and a 'reply_array', which is an array containing all replies to that ticket. */ public static function getEntireTicket($id,$view_as_admin) { $ticket = new Ticket(); $ticket->load_With_TId($id); $reply_array = Ticket_Reply::getRepliesOfTicket($id, $view_as_admin); return Array('ticket_obj' => $ticket,'reply_array' => $reply_array); } /** * return all tickets of a specific user. * an array of all tickets created by a specific user are returned by this function. * @param $author the id of the user of whom we want all tickets from. * @return an array containing all ticket objects related to a user. */ public static function getTicketsOf($author) { $dbl = new DBLayer("lib"); $statement = $dbl->execute("SELECT * FROM ticket INNER JOIN ticket_user ON ticket.Author = ticket_user.TUserId and ticket_user.ExternId=:id", array('id' => $author)); $row = $statement->fetchAll(); $result = Array(); foreach($row as $ticket){ $instance = new self(); $instance->setTId($ticket['TId']); $instance->setTimestamp($ticket['Timestamp']); $instance->setTitle($ticket['Title']); $instance->setStatus($ticket['Status']); $instance->setQueue($ticket['Queue']); $instance->setTicket_Category($ticket['Ticket_Category']); $instance->setAuthor($ticket['Author']); $result[] = $instance; } return $result; } /** * function that creates a new ticket. * A new ticket will be created, in case the extra_info != 0 and the http request came from ingame, then a ticket_info page will be created. * A log entry will be written, depending on the $real_authors value. In case the for_support_group parameter is set, the ticket will be forwarded immediately. * Also the mail handler will create a new email that will be sent to the author to notify him that his ticket is freshly created. * @param $title the title we want to give to the ticket. * @param $content the content we want to give to the starting post of the ticket. * @param $category the id of the category that should be related to the ticket. * @param $author the person who's id will be stored in the database as creator of the ticket. * @param $real_author should be the same id, or a moderator/admin who creates a ticket for another user (this is used for logging purposes). * @param $for_support_group in case you directly want to forward the ticket after creating it. (default value = 0 = don't forward) * @param $extra_info used for creating an ticket_info page related to the ticket, this only happens when the ticket is made ingame. * @return the created tickets id. */ public static function create_Ticket( $title, $content, $category, $author, $real_author, $for_support_group = 0, $extra_info = 0) { //create the new ticket! $ticket = new Ticket(); $values = array("Title" => $title, "Timestamp"=>0, "Status"=> 1, "Queue"=> 0, "Ticket_Category" => $category, "Author" => $author, "Priority" => 0); $ticket->set($values); $ticket->create(); $ticket_id = $ticket->getTId(); //if ingame then add an extra info if(Helpers::check_if_game_client() && $extra_info != 0){ $extra_info['Ticket'] = $ticket_id; Ticket_Info::create_Ticket_Info($extra_info); } //write a log entry if ( $author == $real_author){ Ticket_Log::createLogEntry( $ticket_id, $author, 1); }else{ Ticket_Log::createLogEntry( $ticket_id, $real_author, 2, $author); } Ticket_Reply::createReply($content, $author, $ticket_id, 0, $author); //forwards the ticket directly after creation to the supposed support group if($for_support_group){ Ticket::forwardTicket(0, $ticket_id, $for_support_group); } //send email that new ticket has been created Mail_Handler::send_ticketing_mail($ticket->getAuthor(), $ticket, $content, "NEW", $ticket->getForwardedGroupId()); return $ticket_id; } /** * updates the ticket's status. * A log entry about this will be created only if the newStatus is different from the current status. * @param $ticket_id the id of the ticket of which we want to change the status. * @param $newStatus the new status value (integer) * @param $author the user (id) that performed the update status action */ public static function updateTicketStatus( $ticket_id, $newStatus, $author) { $ticket = new Ticket(); $ticket->load_With_TId($ticket_id); if ($ticket->getStatus() != $newStatus){ $ticket->setStatus($newStatus); Ticket_Log::createLogEntry( $ticket_id, $author, 5, $newStatus); } $ticket->update(); } /** * updates the ticket's status & priority. * A log entry about this will be created only if the newStatus is different from the current status and also when the newPriority is different from the current priority. * @todo break this function up into a updateStatus (already exists) and updatePriority function and perhaps write a wrapper function for the combo. * @param $ticket_id the id of the ticket of which we want to change the status & priority * @param $newStatus the new status value (integer) * @param $newPriority the new priority value (integer) * @param $author the user (id) that performed the update */ public static function updateTicketStatusAndPriority( $ticket_id, $newStatus, $newPriority, $author) { $ticket = new Ticket(); $ticket->load_With_TId($ticket_id); if ($ticket->getStatus() != $newStatus){ $ticket->setStatus($newStatus); Ticket_Log::createLogEntry( $ticket_id, $author, 5, $newStatus); } if ($ticket->getPriority() != $newPriority){ $ticket->setPriority($newPriority); Ticket_Log::createLogEntry( $ticket_id, $author, 6, $newPriority); } $ticket->update(); } /** * return the latest reply of a ticket * @param $ticket_id the id of the ticket. * @return a ticket_reply object. */ public static function getLatestReply( $ticket_id) { $dbl = new DBLayer("lib"); $statement = $dbl->execute("SELECT * FROM ticket_reply WHERE Ticket =:id ORDER BY TReplyId DESC LIMIT 1 ", array('id' => $ticket_id)); $reply = new Ticket_Reply(); $reply->set($statement->fetch()); return $reply; } /** * return the attachments list * @param $ticket_id the id of the ticket. * @return a ticket_reply object. */ public static function getAttachments( $ticket_id) { $dbl = new DBLayer("lib"); $statement = $dbl->select("`ticket_attachments`",array('ticket_TId' => $ticket_id), "`ticket_TId` =:ticket_TId ORDER BY Timestamp DESC"); $fetchall = $statement->fetchall(); $base = 0; foreach ($fetchall as &$value) { $webUser = new WebUsers($value['Uploader']); $fetchall[$base]['Username'] = $webUser->getUsername(); $bytes = $fetchall[$base]['Filesize']; $precision = 2; $units = array('B', 'KB', 'MB', 'GB', 'TB'); $bytes = max($bytes, 0); $pow = floor(($bytes ? log($bytes) : 0) / log(1024)); $pow = min($pow, count($units) - 1); $bytes /= pow(1024, $pow); $fetchall[$base]['Filesize'] = round($bytes, $precision) . ' ' . $units[$pow];; $base++; } return $fetchall; } /** * create a new reply for a ticket. * A reply will only be added if the content isn't empty and if the ticket isn't closed. * The ticket creator will be notified by email that someone else replied on his ticket. * @param $content the content of the reply * @param $author the author of the reply * @param $ticket_id the id of the ticket to which we want to add the reply. * @param $hidden boolean that specifies if the reply should only be shown to mods/admins or all users. */ public static function createReply($content, $author, $ticket_id, $hidden){ //if not empty if(! ( Trim ( $content ) === '' )){ $content = filter_var($content, FILTER_SANITIZE_STRING); $ticket = new Ticket(); $ticket->load_With_TId($ticket_id); //if status is not closed if($ticket->getStatus() != 3){ Ticket_Reply::createReply($content, $author, $ticket_id, $hidden, $ticket->getAuthor()); //notify ticket author that a new reply is added! if($ticket->getAuthor() != $author){ Mail_Handler::send_ticketing_mail($ticket->getAuthor(), $ticket, $content, "REPLY", $ticket->getForwardedGroupId()); } }else{ //TODO: Show error message that ticket is closed } }else{ //TODO: Show error content is empty } } /** * assign a ticket to a user. * Checks if the ticket exists, if so then it will try to assign the user to it, a log entry will be written about this. * @param $user_id the id of user trying to be assigned to the ticket. * @param $ticket_id the id of the ticket that we try to assign to the user. * @return SUCCESS_ASSIGNED, TICKET_NOT_EXISTING or ALREADY_ASSIGNED */ public static function assignTicket($user_id, $ticket_id){ if(self::ticketExists($ticket_id)){ $returnvalue = Assigned::assignTicket($user_id, $ticket_id); Ticket_Log::createLogEntry( $ticket_id, $user_id, 7); return $returnvalue; }else{ return "TICKET_NOT_EXISTING"; } } /** * unassign a ticket of a user. * Checks if the ticket exists, if so then it will try to unassign the user of it, a log entry will be written about this. * @param $user_id the id of user trying to be assigned to the ticket. * @param $ticket_id the id of the ticket that we try to assign to the user. * @return SUCCESS_UNASSIGNED, TICKET_NOT_EXISTING or NOT_ASSIGNED */ public static function unAssignTicket($user_id, $ticket_id){ if(self::ticketExists($ticket_id)){ $returnvalue = Assigned::unAssignTicket($user_id, $ticket_id); Ticket_Log::createLogEntry( $ticket_id, $user_id, 9); return $returnvalue; }else{ return "TICKET_NOT_EXISTING"; } } /** * forward a ticket to a specific support group. * Checks if the ticket exists, if so then it will try to forward the ticket to the support group specified, a log entry will be written about this. * if no log entry should be written then the user_id should be 0, else te $user_id will be used in the log to specify who forwarded it. * @param $user_id the id of user trying to forward the ticket. * @param $ticket_id the id of the ticket that we try to forward to a support group. * @param $group_id the id of the support group. * @return SUCCESS_FORWARDED, TICKET_NOT_EXISTING or INVALID_SGROUP */ public static function forwardTicket($user_id, $ticket_id, $group_id){ if(self::ticketExists($ticket_id)){ if(isset($group_id) && $group_id != ""){ //forward the ticket $returnvalue = Forwarded::forwardTicket($group_id, $ticket_id); if($user_id != 0){ //unassign the ticket incase the ticket is assined to yourself self::unAssignTicket($user_id, $ticket_id); //make a log entry of this action Ticket_Log::createLogEntry( $ticket_id, $user_id, 8, $group_id); } return $returnvalue; }else{ return "INVALID_SGROUP"; } }else{ return "TICKET_NOT_EXISTING"; } } ////////////////////////////////////////////Methods//////////////////////////////////////////////////// /** * A constructor. * Empty constructor */ public function __construct() { } /** * sets the object's attributes. * @param $values should be an array of the form array('TId' => ticket_id, 'Title' => title, 'Status'=> status, 'Timestamp' => ts, 'Queue' => queue, * 'Ticket_Category' => tc, 'Author' => author, 'Priority' => priority). */ public function set($values){ if(isset($values['TId'])){ $this->tId = $values['TId']; } $this->title = $values['Title']; $this->status = $values['Status']; $this->timestamp = $values['Timestamp']; $this->queue = $values['Queue']; $this->ticket_category = $values['Ticket_Category']; $this->author = $values['Author']; $this->priority = $values['Priority']; } /** * creates a new 'ticket' entry. * this method will use the object's attributes for creating a new 'ticket' entry in the database. */ public function create(){ $dbl = new DBLayer("lib"); $this->tId = $dbl->executeReturnId("ticket", Array('Title' => $this->title, 'Status' => $this->status, 'Queue' => $this->queue, 'Ticket_Category' => $this->ticket_category, 'Author' => $this->author, 'Priority' => $this->priority), array('Timestamp'=>'now()')); } /** * loads the object's attributes. * loads the object's attributes by giving a TId (ticket id). * @param $id the id of the ticket that should be loaded */ public function load_With_TId( $id) { $dbl = new DBLayer("lib"); $statement = $dbl->select("ticket", array('id' => $id), "TId=:id"); $row = $statement->fetch(); $this->tId = $row['TId']; $this->timestamp = $row['Timestamp']; $this->title = $row['Title']; $this->status = $row['Status']; $this->queue = $row['Queue']; $this->ticket_category = $row['Ticket_Category']; $this->author = $row['Author']; $this->priority = $row['Priority']; } /** * update the objects attributes to the db. */ public function update(){ $dbl = new DBLayer("lib"); $dbl->update("ticket", Array('Timestamp' => $this->timestamp, 'Title' => $this->title, 'Status' => $this->status, 'Queue' => $this->queue, 'Ticket_Category' => $this->ticket_category, 'Author' => $this->author, 'Priority' => $this->priority), "TId=$this->tId"); } /** * check if a ticket has a ticket_info page or not. * @return true or false */ public function hasInfo(){ return Ticket_Info::TicketHasInfo($this->getTId()); } ////////////////////////////////////////////Getters//////////////////////////////////////////////////// /** * get tId attribute of the object. */ public function getTId(){ return $this->tId; } /** * get timestamp attribute of the object in the format defined in the outputTime function of the Helperclass. */ public function getTimestamp(){ return Helpers::outputTime($this->timestamp); } /** * get title attribute of the object. */ public function getTitle(){ return $this->title; } /** * get status attribute of the object. */ public function getStatus(){ return $this->status; } /** * get status attribute of the object in the form of text (string). */ public function getStatusText(){ $statusArray = Ticket::getStatusArray(); return $statusArray[$this->getStatus()]; } /** * get category attribute of the object in the form of text (string). */ public function getCategoryName(){ $category = Ticket_Category::constr_TCategoryId($this->getTicket_Category()); return $category->getName(); } /** * get queue attribute of the object. */ public function getQueue(){ return $this->queue; } /** * get ticket_category attribute of the object (int). */ public function getTicket_Category(){ return $this->ticket_category; } /** * get author attribute of the object (int). */ public function getAuthor(){ return $this->author; } /** * get priority attribute of the object (int). */ public function getPriority(){ return $this->priority; } /** * get priority attribute of the object in the form of text (string). */ public function getPriorityText(){ $priorityArray = Ticket::getPriorityArray(); return $priorityArray[$this->getPriority()]; } /** * get the user assigned to the ticket. * or return 0 in case not assigned. */ public function getAssigned(){ $user_id = Assigned::getUserAssignedToTicket($this->getTId()); if ($user_id == ""){ return 0; }else{ return $user_id; } } /** * get the name of the support group to whom the ticket is forwarded * or return 0 in case not forwarded. */ public function getForwardedGroupName(){ $group_id = Forwarded::getSGroupOfTicket($this->getTId()); if ($group_id == ""){ return 0; }else{ return Support_Group::getGroup($group_id)->getName(); } } /** * get the id of the support group to whom the ticket is forwarded * or return 0 in case not forwarded. */ public function getForwardedGroupId(){ $group_id = Forwarded::getSGroupOfTicket($this->getTId()); if ($group_id == ""){ return 0; }else{ return $group_id; } } ////////////////////////////////////////////Setters//////////////////////////////////////////////////// /** * set tId attribute of the object. * @param $id integer id of the ticket */ public function setTId($id){ $this->tId = $id; } /** * set timestamp attribute of the object. * @param $ts timestamp of the ticket */ public function setTimestamp($ts){ $this->timestamp = $ts; } /** * set title attribute of the object. * @param $t title of the ticket */ public function setTitle($t){ $this->title = $t; } /** * set status attribute of the object. * @param $s status of the ticket(int) */ public function setStatus($s){ $this->status = $s; } /** * set queue attribute of the object. * @param $q queue of the ticket */ public function setQueue($q){ $this->queue = $q; } /** * set ticket_category attribute of the object. * @param $tc ticket_category id of the ticket(int) */ public function setTicket_Category($tc){ $this->ticket_category = $tc; } /** * set author attribute of the object. * @param $a author of the ticket */ public function setAuthor($a){ $this->author = $a; } /** * set priority attribute of the object. * @param $p priority of the ticket */ public function setPriority($p){ $this->priority = $p; } /** * function that creates a ticket Attachment. */ public static function add_Attachment($TId,$filename,$author,$tempFile){ global $FILE_STORAGE_PATH; $length = mt_rand(20, 25); $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$-_.+!*\'(),'; $randomString = ''; for ($i = 0; $i < $length; $i++) { $randomString .= $characters[rand(0, strlen($characters) - 1)]; } $targetFile = $FILE_STORAGE_PATH . $randomString . "/" . $filename; if(file_exists($targetFile)) { return self::add_Attachment($TId,$filename,$author,$tempFile); } $ticket = new Ticket(); $ticket->load_With_TId($TId); //create the attachment! try { $dbl = new DBLayer("lib"); $dbl->insert("`ticket_attachments`", Array('ticket_TId' => $TId, 'Filename' => $filename, 'Filesize' => filesize($tempFile), 'Uploader' => $author, 'Path' => $randomString . "/" . $filename)); } catch (Exception $e) { return $false; } mkdir($FILE_STORAGE_PATH . $randomString); $return = move_uploaded_file($tempFile,$targetFile); if ($return == false) { $dbl->delete("`ticket_attachments`", array('Path' => $randomString . "/" . $filename), "`Path` = :Path"); } //write a log entry Ticket_Log::createLogEntry( $TId, $author, 10); return $return; } }