v7‰PNG  IHDR Ÿ f Õ†C1 sRGB ®Îé gAMA ± üa pHYs à ÃÇo¨d GIDATx^íÜL”÷ð÷Yçªö("Bh_ò«®¸¢§q5kÖ*:þ0A­ºšÖ¥]VkJ¢M»¶f¸±8\k2íll£1]q®ÙÔ‚ÆT db.xml000064400000006416152101601110005646 0ustar00
library/HelpdeskMessage.php000064400000004614152101601110011756 0ustar00_ticket)) { $this->_ticket = $this->getDi()->helpdeskTicketTable->load($this->ticket_id); } return $this->_ticket; } public function setAttachments($attachments) { $this->attachments = $this->serializeIds($attachments); } public function getAttachments() { return $this->unserializeIds($this->attachments); } public function loadGetAttachments() { if (is_null($this->_attachments)) $this->_attachments = $this->getDi()->uploadTable->loadIds($this->getAttachments()); return $this->_attachments; } public function delete() { foreach ($this->loadGetAttachments() as $att) { /* @var $att Upload */ if ($att->prefix == Bootstrap_Helpdesk::ATTACHMENT_UPLOAD_PREFIX) $att->delete(); } parent::delete(); } } class HelpdeskMessageTable extends Am_Table { protected $_key = 'message_id'; protected $_table = '?_helpdesk_message'; protected $_recordClass = 'HelpdeskMessage'; public function insert(array $values, $returnInserted = false) { if (empty($values['dattm'])) $values['dattm'] = $this->getDi()->sqlDateTime; return parent::insert($values, $returnInserted); } function selectLast($num) { return $this->selectObjects("SELECT m.*, u.user_id, u.name_f AS u_name_f, u.name_l AS u_name_l, u.login AS u_login, u.email AS u_email, a.admin_id, a.name_f AS a_name_f, a.name_l AS a_name_l, a.login AS a_login, a.email AS a_email, t.ticket_mask as ticket_mask, t.subject as subject FROM ?_helpdesk_message m LEFT JOIN ?_helpdesk_ticket t USING (ticket_id) LEFT JOIN ?_user u ON t.user_id = u.user_id LEFT JOIN ?_admin a ON m.admin_id = a.admin_id ORDER BY m.dattm DESC LIMIT ?d", $num); } }library/HelpdeskCategory.php000064400000002547152101601110012152 0ustar00getTable()->getName(); $max = $this->getAdapter()->selectCell("SELECT MAX(sort_order) FROM {$table_name}"); $this->sort_order = $max + 1; return parent::insert($reload); } public function delete() { $ret = parent::delete(); $table_name = $this->getTable()->getName(); $this->getAdapter()->query("UPDATE {$table_name} SET sort_order=sort_order-1 WHERE sort_order>?", $this->sort_order); return $ret; } } class HelpdeskCategoryTable extends Am_Table { protected $_key = 'category_id'; protected $_table = '?_helpdesk_category'; protected $_recordClass = 'HelpdeskCategory'; function getOptions($include_disabled=false) { return $this->getAdapter()->selectCol("SELECT category_id AS ARRAY_KEY, title FROM ?_helpdesk_category WHERE 1 {AND is_disabled=?} ORDER BY sort_order", $include_disabled ? DBSIMPLE_SKIP : 0); } }library/HelpdeskFaq.php000064400000002333152101601110011075 0ustar00getTable()->getName(); $max = $this->getAdapter()->selectCell("SELECT MAX(sort_order) FROM {$table_name}"); $this->sort_order = $max + 1; return parent::insert($reload); } public function delete() { $ret = parent::delete(); $table_name = $this->getTable()->getName(); $this->getAdapter()->query("UPDATE {$table_name} SET sort_order=sort_order-1 WHERE sort_order>?", $this->sort_order); return $ret; } } class HelpdeskFaqTable extends Am_Table { protected $_key = 'faq_id'; protected $_table = '?_helpdesk_faq'; protected $_recordClass = 'HelpdeskFaq'; function getCategories() { return $this->_db->selectCol("SELECT DISTINCT category, category AS ? FROM ?_helpdesk_faq WHERE category IS NOT NULL ORDER BY category", DBSIMPLE_ARRAY_KEY); } } library/Am/Report/Helpdesk.php000064400000001266152101601110012261 0ustar00title = ___('Count of User Messages in Helpdesk'); } public function getPointField() { return 'hm.dattm'; } /** @return Am_Query */ public function getQuery() { $q = new Am_Query($this->getDi()->helpdeskMessageTable, 'hm'); $q->clearFields(); $q->addField('COUNT(message_id)', 'cnt'); $q->addWhere('admin_id IS NULL'); return $q; } function getLines() { $ret = array(); $ret[] = new Am_Report_Line('cnt', ___('Count of Messages')); return $ret; } }library/Am/Helpdesk/Strategy/Admin/User.php000064400000003273152101601110014556 0ustar00getDi()->router;; return $router->assemble(array( 'module' => 'helpdesk', 'controller' => $this->getControllerName(), 'user_id' => $this->getUserId() ) + $params, $route, true); } public function setUserId($user_id) { $this->user_id = $user_id; } public function getUserId() { return $this->user_id; } public function createNewTicketForm() { $form = parent::createNewTicketForm(); $user = $this->getDi()->userTable->load($this->getUserId()); $text = HTML_QuickForm2_Factory::createElement('html', 'loginOrEmail'); $text->setLabel(___('User')) ->setHtml(sprintf('
%s %s (%s)
', $user->name_f, $user->name_l, $user->login )); $text->toggleFrozen(true); $form->insertBefore($text, $form->getElementById('loginOrEmail')); $form->removeChild( $form->getElementById('loginOrEmail') ); $loginOrEmail = HTML_QuickForm2_Factory::createElement('hidden', 'loginOrEmail'); $loginOrEmail->setValue($user->login); $form->addElement($loginOrEmail); $user_id = HTML_QuickForm2_Factory::createElement('hidden', 'user_id'); $user_id->setValue($user->pk()); $form->addElement($user_id); return $form; } } library/Am/Helpdesk/Strategy/User.php000064400000016226152101601110013530 0ustar00_identity = $user_id ? $user_id : $this->getDi()->auth->getUserId(); } public function isMessageAvalable($message) { return!($message->type == 'comment' && $message->admin_id); } public function isMessageForReply($message) { if ($message->type == 'comment') { return false; } else { return (boolean) $message->admin_id; } } public function fillUpMessageIdentity($message) { return $message; } public function fillUpTicketIdentity($ticket, $request) { $ticket->user_id = $this->getIdentity(); return $ticket; } public function getTicketStatusAfterReply($message) { if ($message->type == 'comment') { return $message->getTicket()->status; } else { return 'awaiting_admin_response'; } } public function onAfterInsertMessage($message, $ticket) { if ($this->getDi()->config->get('helpdesk.notify_new_message_admin', 1)) { $user = $this->getUser($message->getTicket()->user_id); $recepients[] = Am_Mail_Template::TO_ADMIN; $exists = array($this->getDi()->config->get('admin_email') => 1); if (($owner = $message->getTicket()->getOwner()) && !isset($exists[$owner->email])) { $recepients[] = $owner; $exists[$owner->email] = 1; } foreach ($message->getTicket()->getWatchers() as $w) { if (!isset($exists[$w->email])) { $recepients[] = $w; $exists[$w->email] = 1; } } foreach ($recepients as $recepient) { if ($et = Am_Mail_Template::load('helpdesk.notify_new_message_admin')) { $et->setTicket($message->getTicket()); $et->setUser($user); $et->setMessage($message); $et->setUrl($this->getDi()->url('helpdesk/admin/ticket/'.$message->getTicket()->ticket_mask,null,false,true)); $et->send($recepient); } } } } public function onAfterInsertTicket($ticket) { if ($this->getDi()->config->get('helpdesk.new_ticket')) { $user = $this->getUser($ticket->user_id); if ($user->unsubscribed) return; $et = Am_Mail_Template::load('helpdesk.new_ticket', $user->lang); if ($et) { $et->setTicket($ticket); $et->setUser($user); $et->setUrl(sprintf('%s/helpdesk/ticket/%s', $this->getDi()->config->get('root_surl'), $ticket->ticket_mask) ); $et->send($user); } } } public function onViewTicket($ticket) { if ($ticket->has_new) { $ticket->updateQuick('has_new', 0); } } public function getAdminName($message) { if ($this->getDi()->modules->get('helpdesk')->getConfig('disclosure_admin')) { $admin = $this->getAdmin($message->admin_id); return $admin ? $admin->getName() : ___('Administrator'); } else { return ___('Administrator'); } } public function getTemplatePath() { return 'helpdesk'; } public function getIdentity() { return $this->_identity; } public function canViewTicket($ticket) { return $ticket->user_id == $this->getIdentity(); } public function canViewMessage($message) { return $message->getTicket()->user_id == $this->getIdentity(); } public function canEditTicket($ticket) { return $ticket->user_id == $this->getIdentity() && $ticket->status != HelpdeskTicket::STATUS_CLOSED; } public function canEditMessage($message) { return $message->type == 'comment' && ($message->getTicket()->user_id == $this->getIdentity()); } public function canUseSnippets() { return false; } public function canUseFaq() { return false; } public function canEditOwner($ticket) { return false; } public function canEditWatcher($ticket) { return false; } public function canViewOwner($ticket) { return false; } public function canEditCategory($ticket) { return false; } public function createForm() { $form = new Am_Form(); $form->addCsrf(); $form->setAttribute('class', 'am-helpdesk-form'); return $form; } function getCategoryOptions() { $op = $this->getDi()->helpdeskCategoryTable->getOptions(); $user = $this->getUser($this->getIdentity()); foreach (array_keys($op) as $id) { if (!$this->getDi()->resourceAccessTable->userHasAccess($user, $id, HelpdeskCategory::ACCESS_TYPE)) { unset($op[$id]); } } return $op; } public function createNewTicketForm() { $form = parent::createNewTicketForm(); if ($this->getDi()->helpdeskFaqTable->countBy()) { $id = $form->getId(); $s_url = json_encode($this->getDi()->url('helpdesk/faq/suggest',null,false)); $form->addScript()->setScript(<<'); } jQuery("#am-helpdesk-faq-q-result").empty(); return; } jQuery.get($s_url, {q:jQuery(this).val()}, function(html){ jQuery("#am-helpdesk-faq-q-result").empty().append(html); }) return false; }); CUT ); } return $form; } public function addUpload($form) { if (!$this->getDi()->modules->get('helpdesk')->getConfig('does_not_allow_attachments')) { $t = Am_Html::escape(___('Add Attachments')); $form->addHtml()->setHtml(<<$t CUT ); $form->addUpload('attachments', array('multiple' => 1), array('prefix' => Bootstrap_Helpdesk::ATTACHMENT_UPLOAD_PREFIX, 'secure' => true)) ->setLabel(___('Attachments')) ->setJsOptions(<<assembleUrl(array( 'ticket' => $ticket->ticket_mask ), 'helpdesk-ticket'); } public function newUrl() { return $this->assembleUrl(array(), 'helpdesk-new'); } protected function getControllerName() { return 'index'; } }library/Am/Helpdesk/Strategy/Abstract.php000064400000017132152101601110014352 0ustar00_di = $di; } /** * @return Am_Di */ protected function getDi() { return $this->_di; } function onAfterInsertTicket($ticket) { } public function assembleUrl($params, $route = 'default') { $router = $this->getDi()->router;; return $router->assemble(array( 'module' => 'helpdesk', 'controller' => $this->getControllerName(), ) + $params, $route, true); } abstract public function ticketUrl($ticket); abstract public function newUrl(); /** * @return Am_Helpdesk_Strategy_Abstract */ public static function create(Am_Di $di) { return defined('AM_ADMIN') ? ($di->request->getControllerName() == 'admin-user' ? new Am_Helpdesk_Strategy_Admin_User($di) : new Am_Helpdesk_Strategy_Admin($di) ) : new Am_Helpdesk_Strategy_User($di); } function getCategoryOptions() { return $this->getDi()->helpdeskCategoryTable->getOptions(); } /** * @return Am_Form */ public function createNewTicketForm() { $form = $this->createForm(); if ($options = $this->getCategoryOptions()) { $form->addAdvradio('category_id') ->setLabel(___('Category of question')) ->loadOptions($options) ->addRule('required'); $fields = $this->getDi()->helpdeskTicketTable->customFields()->getAll(); foreach ($this->getDi()->helpdeskCategoryTable->findByIsDisabled(0) as $c) { foreach (Am_Record::unserializeList($c->fields) as $fn) { if (isset($fields[$fn])) { $fields[$fn]->name = sprintf('category[%d][%s]', $c->pk(), $_ = $fields[$fn]->name); $fields[$fn]->addToQF2($form, array(), array(), HTML_QuickForm2_Rule::ONBLUR_CLIENT); $fields[$fn]->name = $_; } } } $form->addScript() ->setScript(<<getDi()->helpdeskTicketTable->customFields()->getAll()) { foreach ($fields as $field) { $field->name = sprintf('additional[%s]', $_ = $field->name); $field->addToQF2($form, array(), array(), HTML_QuickForm2_Rule::ONBLUR_CLIENT); $field->name = $_; } } $subject = $form->addText('subject', array('class' => 'row-wide el-wide')) ->setLabel(___('Subject')); $subject->addRule('required'); $subject->addRule('maxlength', ___('Your subject is too verbose'), 255); $subject->addRule('nonempty', ___('Subject can not be empty')); $content = $form->addTextarea('content', array('class' => 'row-wide el-wide', 'rows' => 12)) ->setLabel(___('Message')); $content->addRule('required'); $content->addRule('nonempty', ___('Message can not be empty')); $this->addUpload($form); return $form; } function isShowAvatar() { return $this->getDi()->modules->get('helpdesk')->getConfig('show_gravatar') || ($this->getDi()->plugins_misc->isEnabled('avatar') && $this->getDi()->modules->get('helpdesk')->getConfig('show_avatar')); } public function getAvatar($message) { if ($this->getDi()->plugins_misc->isEnabled('avatar') && $this->getDi()->modules->get('helpdesk')->getConfig('show_avatar')) { if ($message->admin_id) { return $this->getAdminAvatar($message); } else { return $this->getUserAvatar($message); } } elseif ($this->getDi()->modules->get('helpdesk')->getConfig('show_gravatar')) { if ($message->admin_id) { return $this->getAdminGravatar($message); } else { return $this->getUserGravatar($message); } } else { return ''; } } public function getAdminGravatar($message) { $admin = $this->getAdmin($message->admin_id); return $admin ? sprintf('', '//www.gravatar.com/avatar/' . md5(strtolower(trim($admin->email))) . '?s=40&d=mm') : ''; } public function getUserGravatar($message) { $user = $this->getUser($message->getTicket()->user_id); return $user ? sprintf('', '//www.gravatar.com/avatar/' . md5(strtolower(trim($user->email))) . '?s=40&d=mm') : ''; } public function getAdminAvatar($message) { $admin = $this->getAdmin($message->admin_id); return $admin ? sprintf('', $this->getDi()->url('misc/avatar/' . $admin->avatar)) : ''; } public function getUserAvatar($message) { $user = $this->getUser($message->getTicket()->user_id); return $user ? sprintf('', $this->getDi()->url('misc/avatar/' . $user->avatar)) : ''; } public function getName($message) { return $message->admin_id ? $this->getAdminName($message) : $this->getUserName($message); } public function getUserName($message) { $user = $this->getUser($message->getTicket()->user_id); $name = trim("{$user->name_f} {$user->name_l}"); return sprintf('%s%s', $user->login, $name ? sprintf(' (%s)', $name) : '' ); } protected function getAdmin($admin_id) { return $this->getDi()->adminTable->load($admin_id, false); } protected function getUser($user_id) { return $this->getDi()->userTable->load($user_id); } }library/Am/Helpdesk/Strategy/Admin.php000064400000015726152101601110013646 0ustar00type == 'comment' && !$message->admin_id); } public function isMessageForReply($message) { if ($message->type == 'comment') { return false; } else { return!$message->admin_id; } } public function fillUpMessageIdentity($message) { $message->admin_id = $this->getIdentity(); return $message; } public function fillUpTicketIdentity($ticket, $request) { //loginOrEmail was already validated in form //and we must find user with such login or email //in any case $user = $this->getDi()->userTable->findFirstByLogin($request->get('loginOrEmail')); if (!$user) { $user = $this->getDi()->userTable->findFirstByEmail($request->get('loginOrEmail')); } $ticket->user_id = $user->user_id; return $ticket; } public function getTicketStatusAfterReply($message) { if ($message->type == 'comment') { return $message->getTicket()->status; } else { return 'awaiting_user_response'; } } public function onAfterInsertMessage($message, $ticket) { if ($message->type == 'message') { $ticket->updateQuick('has_new', 1); } if ($message->type == 'message' && $this->getDi()->config->get('helpdesk.notify_new_message', 1)) { $user = $this->getUser($message->getTicket()->user_id); if ($user->unsubscribed) return; $et = Am_Mail_Template::load('helpdesk.notify_new_message', $user->lang); if ($et) { $et->setTicket($message->getTicket()); $et->setUser($user); $et->setMessage($message); $et->setUrl($this->getDi()->url('helpdesk/ticket/'.$message->getTicket()->ticket_mask,null,false,true)); $et->send($user); } } } public function onViewTicket($ticket) { //nop } /** * @return Am_Form */ public function createNewTicketForm() { $form = parent::createNewTicketForm(); $element = HTML_QuickForm2_Factory::createElement('text', 'loginOrEmail'); $element->setId('loginOrEmail') ->setLabel(___('Username/Email')) ->addRule('callback', ___('Can not find user with such username or email'), array($this, 'checkUser')); //prepend element to form $formElements = $form->getElements(); $form->insertBefore($element, $formElements[0]); $from = HTML_QuickForm2_Factory::createElement('select', 'from'); $from->setLabel(___('Create ticket as')); $from->loadOptions(array( 'admin' => ___('Admin'), 'user' => ___('Customer') )); $form->insertBefore($from, $element); $form->addScript('script')->setScript(<<getId(); $snippets = ___('Snippets'); $form->addScript('snippets')->setScript(<<
$snippets') jQuery('#snippets-link').bind('click', function(){ var \$this = jQuery(this); var div = jQuery('
'); div.load(amUrl('/helpdesk/admin/p/view/displaysnippets'), {}, function(){ div.dialog({ autoOpen: true, modal : true, title : "", width : 700, position : ['center', 'center'] }); div.find('.grid-wrap').bind('load', function() { jQuery(this).find('a.am-helpdesk-insert-snippet').unbind().click(function(){ var \$target = \$this.closest('div.am-form').find('textarea[name=content]'); \$target.insertAtCaret(jQuery(this).data('snippet-content')) div.dialog('close'); }) }) }) }) CUT ); return $form; } public function addUpload($form) { $t = Am_Html::escape(___('Add Attachments')); $form->addHtml()->setHtml(<<$t CUT ); $form->addUpload('attachments', array('multiple' => 1), array('prefix' => Bootstrap_Helpdesk::ADMIN_ATTACHMENT_UPLOAD_PREFIX, 'secure' => true)) ->setLabel(___('Attachments')); } public function getAdminName($message) { $admin = $this->getAdmin($message->admin_id); return $admin ? $admin->login : ___('Administrator has been removed, id [%d]', $message->admin_id); } public function getTemplatePath() { return 'admin/helpdesk'; } public function getIdentity() { $admin = $this->getDi()->authAdmin->getUser(); return $admin->pk(); } public function canViewTicket($ticket) { return true; } public function canViewMessage($message) { return true; } public function canEditTicket($ticket) { return true; } public function canEditMessage($message) { return ($message->type == 'comment' && (boolean) $message->admin_id) || ($this->getDi()->modules->get('helpdesk')->getConfig('can_edit') && $message->admin_id && $this->getDi()->authAdmin->getUserId() == $message->admin_id && $message->dattm > sqlTime('-5 minute') ); } public function canUseSnippets() { return true; } public function canUseFaq() { return true; } public function canEditOwner($ticket) { return true; } public function canEditWatcher($ticket) { return true; } public function canViewOwner($ticket) { return true; } public function canEditCategory($ticket) { return true; } public function checkUser($loginOrEmail) { $user = $this->getDi()->userTable->findFirstByLogin($loginOrEmail); if (!$user) { $user = $this->getDi()->userTable->findFirstByEmail($loginOrEmail); } return (boolean) $user; } public function createForm() { $form = new Am_Form_Admin(); $form->setAttribute('class', 'am-helpdesk-form'); return $form; } public function ticketUrl($ticket) { return $this->assembleUrl(array( 'ticket' => $ticket->ticket_mask ), 'helpdesk-ticket-admin'); } public function newUrl() { return $this->assembleUrl(array(), 'helpdesk-new-admin'); } protected function getControllerName() { return 'admin'; } }library/Am/Helpdesk/Controller.php000064400000054543152101601110013137 0ustar00hasPermission(Bootstrap_Helpdesk::ADMIN_PERM_ID); } public function init() { $this->strategy = $this->getDi()->helpdeskStrategy; $type = defined('AM_ADMIN') ? 'admin' : 'user'; $this->getView()->headLink()->appendStylesheet($this->getView()->_scriptCss('helpdesk-' . $type . '.css')); $this->getView()->registerHelper(new Am_View_Helper_HelpdeskGetTicketField($this->getDi()->helpdeskTicketTable->customFields()->getAll()), 'helpdeskGetTicketField'); parent::init(); } protected function isGridRequest($gridId) { foreach ($this->getRequest()->getParams() as $key => $val) if (substr($key, 0, strlen($gridId)) == $gridId) return true; return false; } public function newAction() { if (!$this->getModule()->getConfig('live')) return; Zend_Session::writeClose(); set_time_limit(0); while (@ob_end_clean()); $message = $this->getDi()->helpdeskMessageTable->load($this->getDi()->security->reveal($this->getParam('id'))); if (!$this->strategy->canViewMessage($message)) { throw new Am_Exception_AccessDenied(___('Access Denied')); } $ticket = $message->getTicket(); if (!$this->strategy->canViewTicket($ticket)) { throw new Am_Exception_AccessDenied(___('Access Denied')); } while (!($messages = $this->getDi()->helpdeskMessageTable->selectObjects("SELECT * " . "FROM ?_helpdesk_message WHERE ticket_id=? AND message_id>? ORDER BY message_id DESC", $ticket->pk(), $message->pk() ))) { sleep(2); } $this->strategy->onViewTicket($ticket); $out = ''; $message_id = null; $this->view->strategy = $this->strategy; $this->view->ticket = $ticket; foreach ($messages as $message) { $message_id = $message_id ?: $message->pk(); $this->view->message = $message; $out .= $this->view->render($this->strategy->getTemplatePath() . '/_message.phtml'); } $url = json_encode($this->strategy->newUrl(). '?' . http_build_query(array( 'id' => $this->getDi()->security->obfuscate($message_id)))); $html = json_encode($out); echo <<getDi()->helpdeskMessageTable->load($this->getDi()->security->reveal($this->getParam('message_id'))); if (!$this->strategy->canViewMessage($message)) { throw new Am_Exception_AccessDenied(___('Access Denied')); } $upload = $this->getDi()->uploadTable->load($this->getDi()->security->reveal($this->getParam('id'))); if (!in_array($upload->pk(), $message->getAttachments())) { throw new Am_Exception_AccessDenied(___('Access Denied')); } if (!in_array($upload->prefix, array( Bootstrap_Helpdesk::ATTACHMENT_UPLOAD_PREFIX, Bootstrap_Helpdesk::ADMIN_ATTACHMENT_UPLOAD_PREFIX))) { throw new Am_Exception_AccessDenied(___('Access Denied')); } $this->_helper->sendFile($upload->getFullPath(), $upload->mime, array( 'filename' => $upload->getName() )); } public function surrenderAction() { $ticketIdentity = $this->getParam('ticket'); $ticket = $this->getDi()->helpdeskTicketTable->load($ticketIdentity); if (!$this->strategy->canEditOwner($ticket)) { throw new Am_Exception_AccessDenied(___('Access Denied')); } if ($ticket->owner_id == $this->strategy->getIdentity()) { $ticket->owner_id = null; $ticket->save(); } $this->redirectTicket($ticket); } public function takeAction() { $ticketIdentity = $this->getParam('ticket'); $ticket = $this->getDi()->helpdeskTicketTable->load($ticketIdentity); if (!$this->strategy->canEditOwner($ticket)) { throw new Am_Exception_AccessDenied(___('Access Denied')); } $id = $this->getParam('id'); $id = $id ? $this->getDi()->security->reveal($id) : $this->strategy->getIdentity(); $ticket->owner_id = $id; $ticket->save(); if (($this->strategy->getIdentity() != $id) && $this->getModule()->getConfig('notify_assign')) { $admin = $this->getDi()->adminTable->load($id); $et = Am_Mail_Template::load('helpdesk.notify_assign'); $et->setTicket($ticket); $et->setAdmin($admin); $et->setUrl($this->getDi()->url('helpdesk/admin/ticket/'.$ticket->ticket_mask,null,false,2)); $et->send($admin->email); } $this->redirectTicket($ticket); } public function editcategoryAction() { $ticketIdentity = $this->getParam('ticket'); $ticket = $this->getDi()->helpdeskTicketTable->load($ticketIdentity); if (!$this->strategy->canEditCategory($ticket)) { throw new Am_Exception_AccessDenied(___('Access Denied')); } $ticket->category_id = $this->getDi()->security->reveal($this->getParam('id')); $ticket->save(); $this->redirectTicket($ticket); } public function lockAction() { if (defined('AM_ADMIN') && AM_ADMIN) { $ticketIdentity = $this->getParam('ticket'); /* @var $ticket HelpdeskTicket */ $ticket = $this->getDi()->helpdeskTicketTable->load($ticketIdentity); $ticket->lock($this->getDi()->authAdmin->getUser()); } } public function viewAction() { $ticketIdentity = $this->getParam('ticket'); $ticket = $this->getDi()->helpdeskTicketTable->load($ticketIdentity); if (!$this->strategy->canViewTicket($ticket)) { throw new Am_Exception_AccessDenied(___('Access Denied')); } $this->strategy->onViewTicket($ticket); $grid = new Am_Helpdesk_Grid_Admin($this->getRequest(), $this->getView()); $grid->getDataSource()->getDataSourceQuery()->addWhere('m.user_id=?d', $ticket->user_id); $grid->actionsClear(); $grid->removeField('m_login'); $grid->removeField('avatar'); $grid->removeField('gravatar'); $grid->addCallback(Am_Grid_ReadOnly::CB_TR_ATTRIBS, function(& $ret, $record) use ($ticket) { if ($record->pk() == $ticket->pk()) $ret['class'] = isset($ret['class']) ? $ret['class'] . ' emphase' : 'emphase'; }); if ($this->getDi()->helpdeskTicketTable->countByUserId($ticket->user_id) < 10) { $grid->addCallback(Am_Grid_ReadOnly::CB_RENDER_CONTENT, function(&$out, $g){ $out = preg_replace('/.*?/is', '', $out); }); $grid->addCallback(Am_Grid_ReadOnly::CB_RENDER_TITLE, function(&$out, $g){ $out = ''; }); } $grid->isAjax($this->isAjax() && $this->isGridRequest('_admin')); if ($grid->isAjax()) { echo $grid->run(); return; } $category = $ticket->getCategory(); $t = $this->getView(); $t->assign('ticket', $ticket); $t->assign('category', $category); $t->assign('user', $ticket->getUser()); $t->assign('strategy', $this->strategy); $t->assign('historyGrid', $grid->render()); $t->assign('customFields', $this->getDi()->helpdeskTicketTable->customFields()->getAll()); $content = $t->render($this->strategy->getTemplatePath() . '/ticket.phtml'); if ($this->_request->isXmlHttpRequest()) { header('Content-type: text/html; charset=UTF-8'); echo $content; } else { $this->view->assign('content', $content); $this->view->display($this->strategy->getTemplatePath() . '/index.phtml'); } } public function replyAction() { $ticket = $this->getDi()->helpdeskTicketTable->load($this->getParam('ticket')); if (!$this->strategy->canEditTicket($ticket)) { throw new Am_Exception_AccessDenied(___('Access Denied')); } $message = null; $type = $this->getParam('type', 'message'); if ($message_id = $this->getDi()->security->reveal($this->getParam('message_id'))) { $message = $this->getDi()->helpdeskMessageTable->load($message_id); switch ($type) { case 'message' : if (!$this->strategy->canViewMessage($message)) { throw new Am_Exception_AccessDenied(___('Access Denied')); } break; case 'comment' : if (!$this->strategy->canEditMessage($message)) { throw new Am_Exception_AccessDenied(___('Access Denied')); } break; default : throw new Am_Exception_InputError('Unknown message type : ' . $type); } } /* @var $replyForm Am_Form */ $replyForm = $this->getReplyForm( $this->getParam('ticket'), $message, $type ); if ($this->isPost()) { $replyForm->setDataSources(array($this->getRequest())); $values = $replyForm->getValue(); $message_id = $this->getParam('message_id', null); $message_id = $message_id ? $this->getDi()->security->reveal($message_id) : $message_id; $this->reply($ticket, $message_id, $values); $this->getRequest()->set('ticket', $ticket->ticket_mask); if ($this->_request->isXmlHttpRequest()) { return; } else { return $this->redirectTicket($ticket); } } $content = (string) $replyForm; if ($this->_request->isXmlHttpRequest()) { header('Content-type: text/html; charset=UTF-8'); echo $content; } else { $this->view->assign('content', $content); $this->view->display($this->strategy->getTemplatePath() . '/index.phtml'); } } public function changestatusAction() { $ticketIdentity = $this->getParam('ticket'); $ticket = $this->getDi()->helpdeskTicketTable->load($ticketIdentity); if (!$this->strategy->canEditTicket($ticket)) { throw new Am_Exception_AccessDenied(___('Access Denied')); } $ticket->status = $this->getParam('status'); $ticket->save(); return $this->redirectTicket($ticket); } public function displaysnippetsAction() { if (!$this->strategy->canUseSnippets()) { throw new Am_Exception_AccessDenied(); } $ticket = $this->getDi()->helpdeskTicketTable->load($this->getParam('ticket'), false); $tpl = null; if ($ticket) { $tpl = new Am_SimpleTemplate; $tpl->assign('user', $ticket->getUser()); } $ds = new Am_Query($this->getDi()->helpdeskSnippetTable); $grid = new Am_Grid_Editable('_snippet', ___('Snippets'), $ds, $this->getRequest(), $this->view, $this->getDi()); $grid->addField('title', ___('Title'))->setRenderFunction( function ($record, $fieldName, $grid) use ($tpl) { $c = $record->content; if ($tpl) { $c = $tpl->render($c); } return sprintf('%s', Am_Html::escape($c), Am_Html::escape($record->title)); }); $grid->setForm(array($this, 'createForm')); $grid->actionGet('insert')->setTarget(null); $grid->setPermissionId(Bootstrap_Helpdesk::ADMIN_PERM_ID); $grid->isAjax($this->isAjax() && $this->isGridRequest('_snippet')); echo $grid->run(); } public function displayfaqAction() { if (!$this->strategy->canUseFaq()) { throw new Am_Exception_AccessDenied(); } $ds = new Am_Query($this->getDi()->helpdeskFaqTable); $grid = new Am_Grid_ReadOnly('_helpdesk_faq', ___('FAQ'), $ds, $this->getRequest(), $this->view, $this->getDi()); $grid->addField('title', ___('Title'))->setRenderFunction(array($this, 'renderFaqTitle')); $grid->addField('category', ___('Category')); $grid->setPermissionId(Bootstrap_Helpdesk::ADMIN_PERM_ID); $grid->isAjax($this->isAjax() && $this->isGridRequest('_helpdesk_faq')); echo $grid->run(); } public function displayassignAction() { if (!$this->strategy->canEditOwner(null)) { throw new Am_Exception_AccessDenied(); } $ds = new Am_Query($this->getDi()->adminTable); $grid = new Am_Grid_ReadOnly('_helpdesk_assign', ___('Admins'), $ds, $this->getRequest(), $this->view, $this->getDi()); $grid->addField('login', ___('Name'))->setRenderFunction(array($this, 'renderAssignTitle')); $grid->setPermissionId(Bootstrap_Helpdesk::ADMIN_PERM_ID); $grid->isAjax($this->isAjax() && $this->isGridRequest('_helpdesk_assign')); echo $grid->run(); } public function displayeditcategoryAction() { if (!$this->strategy->canEditCategory(null)) { throw new Am_Exception_AccessDenied(); } $ds = new Am_Query($this->getDi()->helpdeskCategoryTable); $grid = new Am_Grid_ReadOnly('_helpdesk_category', ___('Categories'), $ds, $this->getRequest(), $this->view, $this->getDi()); $grid->addField('title', ___('Title'))->setRenderFunction(array($this, 'renderEditCategoryTitle')); $grid->setPermissionId(Bootstrap_Helpdesk::ADMIN_PERM_ID); $grid->isAjax($this->isAjax() && $this->isGridRequest('_helpdesk_category')); echo $grid->run(); } public function editwatcherAction() { $ticketIdentity = $this->getParam('ticket'); $ticket = $this->getDi()->helpdeskTicketTable->load($ticketIdentity); if (!$this->strategy->canEditWatcher($ticket)) { throw new Am_Exception_AccessDenied(); } $options = array(); foreach (Am_Di::getInstance()->adminTable->findBy() as $admin) { $options[$admin->pk()] = sprintf('%s (%s %s)', $admin->login, $admin->name_f, $admin->name_l); } $form = new Am_Form_Admin; $form->addMagicSelect('watcher_ids') ->setLabel(___("Watchers\n" . 'notify the following admins ' . 'about new messages in this ticket')) ->loadOptions($options); $form->addHidden('ticket') ->setValue($ticketIdentity); $form->addSaveButton(); if (!$form->isSubmitted()) { $form->setDataSources(array(new HTML_QuickForm2_DataSource_Array(array( 'watcher_ids' => explode(',', $ticket->watcher_ids) )))); } if ($form->isSubmitted() && $form->validate()) { $vars = $form->getValue(); $ticket->watcher_ids = implode(",", $vars['watcher_ids']); $ticket->save(); if (!$this->_request->isXmlHttpRequest()) { return $this->redirectTicket($ticket); } } echo $form; } public function renderFaqTitle($record, $fieldName, $grid) { return sprintf('%s', $this->getDi()->rurl('helpdesk/faq/i/'.urlencode($record->title)), Am_Html::escape($record->title)); } public function renderAssignTitle($record, $fieldName, $grid) { return sprintf('%s', $this->getDi()->app->obfuscate($record->pk()), Am_Html::escape(sprintf('%s (%s %s)', $record->login, $record->name_f, $record->name_l))); } public function renderEditCategoryTitle($record, $fieldName, $grid) { return sprintf('%s', $this->getDi()->app->obfuscate($record->pk()), Am_Html::escape($record->title)); } public function createForm() { $form = new Am_Form_Admin(); $form->addText('title', array('class' => 'el-wide')) ->setLabel(___('Title')) ->addRule('required'); $form->addTextarea('content', array('class' => 'el-wide', 'rows' => 10)) ->setLabel(___('Content')) ->addRule('required'); return $form; } protected function redirectTicket($ticket) { $url = $this->strategy->ticketUrl($ticket); $this->_response->redirectLocation($url); } private function editMessage($message_id, $value) { $message = $this->getDi()->helpdeskMessageTable->load($message_id); if (!$this->strategy->canEditMessage($message)) { throw new Am_Exception_AccessDenied(___('Access Denied')); } $message->content = $value['content']; $message->save(); } private function addMessage($ticket, $value) { $message = $this->getDi()->helpdeskMessageRecord; $message->content = $value['content']; $message->ticket_id = $ticket->ticket_id; $message->type = $value['type']; $message->setAttachments($value['attachments']); $message = $this->strategy->fillUpMessageIdentity($message); $message->save(); $this->strategy->onAfterInsertMessage($message, $ticket); $ticket->status = $this->strategy->getTicketStatusAfterReply($message); $ticket->updated = $this->getDi()->sqlDateTime; $ticket->save(); if (isset($value['_close']) && $value['_close'] && $this->strategy->caneditTicket($ticket)) { $ticket->status = HelpdeskTicket::STATUS_CLOSED; $ticket->save(); } } private function reply($ticket, $message_id, $values) { if ($message_id) { $this->editMessage($message_id, $values); } else { $this->addMessage($ticket, $values); } } private function getReplyForm($ticket, $message = null, $type = 'message') { $content = ''; $form = $this->strategy->createForm(); if (!is_null($message) && $type == 'message') { if (!$this->getModule()->getConfig('does_not_quote_in_reply')) { $content = explode("\n", $message->content); $content = array_map(function($v) { return '>'.$v; }, $content); $content = "\n\n" . implode("\n", $content); } } elseif (!is_null($message) && $type == 'comment') { $content = $message->content; $form->addHidden('message_id') ->setValue($this->getDi()->app->obfuscate($message->message_id)); } if ($type == 'message' && defined('AM_ADMIN') && $this->getModule()->getConfig('add_signature')) { $content = "\n\n" . $this->expandPlaceholders($this->getModule()->getConfig('signature')) . $content; } $form->addHidden('type') ->setValue($type); $row_num = min(15, count(explode("\n", $content))+1); $form->addTextarea('content', array('rows' => $row_num, 'class' => 'no-label el-wide', 'placeholder' => $type == 'comment' ? ___('Write your comment...') : ___('Write your reply...'))) ->setValue($content) ->addRule('required'); $form->setAction($this->strategy->assembleUrl(array( 'page_id' => 'view', 'action' => 'reply', 'ticket' => $ticket, 'type' => $type ), 'inside-pages')); if ($type != 'comment') { $this->strategy->addUpload($form); } if ($this->strategy->canEditTicket($ticket)) { $form->addAdvCheckbox('_close', null, array('content' => ___('Close This Ticket After Response'))); } $btns = $form->addGroup(); $btns->setSeparator(' '); $btns->addSubmit('submit', array('value' => ___('Send Message'))); $btns->addInputButton('discard', array('value' => ___('Discard'))); return $form; } protected function expandPlaceholders($text) { $admin = $this->getDi()->authAdmin->getUser(); return str_replace(array( '%name_f%', '%name_l%' ), array( $admin->name_f, $admin->name_l ), $text); } } class Am_View_Helper_HelpdeskGetTicketField extends Zend_View_Helper_Abstract { protected $customFields = array(); function __construct($customFields) { $this->customFields = $customFields; } public function helpdeskGetTicketField(HelpdeskTicket $ticket, $field_name) { return $this->formatValue($this->getValue($ticket, $field_name), $field_name); } protected function getValue(HelpdeskTicket $ticket, $field_name) { return $this->customFields[$field_name]->sql ? $ticket->{$field_name} : $ticket->data()->get($field_name); } protected function formatValue($val, $field_name) { if (isset($this->customFields[$field_name])) { $field = $this->customFields[$field_name]; switch($field->getType()) { case 'date': $res = amDate($val); break; case 'select': case 'radio': case 'checkbox': case 'multi_select': $val = (array)$val; foreach ($val as $k=>$v) $val[$k] = @$field->options[$v]; $res = implode(", ", $val); break; default: $res = $val; } } else { $res = $val; } return $res; } }library/Am/Helpdesk/Grid.php000064400000030562152101601110011674 0ustar00status = HelpdeskTicket::STATUS_CLOSED; $record->save(); } } class Am_Grid_Editable_Helpdesk extends Am_Grid_Editable { protected $foundRowsBeforeFilter = 0; protected $eventId = 'gridHelpdesk'; function init() { $this->foundRowsBeforeFilter = $this->dataSource->getFoundRows(); $this->addCallback(Am_Grid_ReadOnly::CB_RENDER_TABLE, array($this, 'skipTable')); } function renderFilter() { if ($this->foundRowsBeforeFilter) { return parent::renderFilter(); } } function skipTable(& $out) { if (!$this->foundRowsBeforeFilter) { $out = ''; } } public function getPermissionId() { return Bootstrap_Helpdesk::ADMIN_PERM_ID; } } class Am_Grid_Filter_Helpdesk extends Am_Grid_Filter_Abstract { protected $language = null; protected $varList = array('filter_q', 'has_new'); protected function applyFilter() { $query = $this->grid->getDataSource()->getDataSourceQuery(); if ($filter = $this->getParam('filter_q')) { $condition = new Am_Query_Condition_Field('subject', 'LIKE', '%' . $filter . '%'); $condition->_or(new Am_Query_Condition_Field('ticket_mask', 'LIKE', '%' . $filter . '%')); $query->add($condition); } if ($this->getParam('has_new')) { $query->addWhere('t.has_new=?', 1); } } function renderInputs() { $filter = $this->renderInputText(array( 'placeholder' => ___('Subject or Ticket#'), 'name' => 'filter_q')); return $filter; } function getTitle() { return ''; } } class Am_Grid_Filter_Helpdesk_Adv extends Am_Grid_Filter_Helpdesk { protected $language = null; protected $varList = array('filter_q', 'filter_c', 'has_new'); protected function applyFilter() { parent::applyFilter(); $query = $this->grid->getDataSource()->getDataSourceQuery(); if ($filter = $this->getParam('filter_c')) { $query->addWhere('t.category_id=?', $filter); } } function renderInputs() { $filter = parent::renderInputs(); $categoryOptions = Am_Di::getInstance()->helpdeskCategoryTable->getOptions(); if ($categoryOptions) { $categoryOptions = array('' => ___('All Categories')) + $categoryOptions; $filter .= ' '; $filter .= $this->renderInputSelect('filter_c', $categoryOptions); } return $filter; } function getTitle() { return ''; } } class Am_Grid_Filter_Helpdesk_Adv_WithStatus extends Am_Grid_Filter_Helpdesk_Adv { protected $varList = array('filter_q', 'filter_s', 'filter_c', 'has_new'); protected function applyFilter() { parent::applyFilter(); $query = $this->grid->getDataSource()->getDataSourceQuery(); if ($filter = $this->getParam('filter_s')) { $query->addWhere('t.status IN (?a)', $filter); } } function renderInputs() { $categoryOptions = Am_Di::getInstance()->helpdeskCategoryTable->getOptions(); $width = $categoryOptions ? '45' : '90'; $filter = $this->renderInputText(array( 'placeholder' => ___('Subject or Ticket#'), 'name' => 'filter_q', 'style' => "width:$width%")); if ($categoryOptions) { $categoryOptions = array('' => ___('All Categories')) + $categoryOptions; $filter .= ' '; $filter .= $this->renderInputSelect('filter_c', $categoryOptions, array( 'style' => "width:$width%" )); } $statusOptions = HelpdeskTicket::getStatusOptions(); unset($statusOptions[HelpdeskTicket::STATUS_CLOSED]); $filter .= '
'; $filter .= $this->renderInputCheckboxes('filter_s', $statusOptions); return $filter; } } class Am_Grid_Action_Ticket extends Am_Grid_Action_Abstract { protected $type = self::NORECORD; // this action does not operate on existing records protected $strategy = null; public function __construct($id = null, $title = null) { $this->title = ___('Submit New Ticket'); parent::__construct($id, $title); } public function run() { $form = $this->grid->getForm(); if ($form->isSubmitted() && $form->validate()) { $values = $form->getValue(); if (defined('AM_ADMIN') && AM_ADMIN && isset($values['from']) && $values['from'] == 'user') { $user = Am_Di::getInstance()->userTable->findFirstByLogin($values['loginOrEmail']); if (!$user) $user = Am_Di::getInstance()->userTable->findFirstByEmail($values['loginOrEmail']); if (!$user) throw new Am_Exception_InputError("User not found with username or email equal to {$values['loginOrEmail']}"); $this->switchStrategy(new Am_Helpdesk_Strategy_User(Am_Di::getInstance(), $user->pk())); } $ticket = Am_Di::getInstance()->helpdeskTicketRecord; if (isset($values['category_id']) && isset($values['category'][$values['category_id']])) { $ticket->setForInsert($values['category'][$values['category_id']]); } elseif (isset($values['additional'])) { $ticket->setForInsert($values['additional']); } $ticket->subject = $values['subject']; $ticket->created = Am_Di::getInstance()->sqlDateTime; $ticket->updated = Am_Di::getInstance()->sqlDateTime; $ticket->category_id = isset($values['category_id']) ? $values['category_id'] : null; if (($category = $ticket->getCategory()) && ($category->owner_id || $category->watcher_ids)) { $ticket->owner_id = $category->owner_id; $ticket->watcher_ids = $category->watcher_ids; } $ticket = $this->getStrategy()->fillUpTicketIdentity($ticket, $this->grid->getCompleteRequest()); // mask will be generated on insertion $ticket->insert(); $this->getStrategy()->onAfterInsertTicket($ticket); $content = $values['content']; if (defined('AM_ADMIN') && AM_ADMIN) { $user = $ticket->getUser(); $tpl = new Am_SimpleTemplate; $tpl->assign('user', $user); $content = $tpl->render($content); } $message = Am_Di::getInstance()->helpdeskMessageRecord; $message->content = $content; $message->ticket_id = $ticket->pk(); $message->dattm = Am_Di::getInstance()->sqlDateTime; $message = $this->getStrategy()->fillUpMessageIdentity($message); $message->setAttachments(@$values['attachments']); $message->insert(); $this->getStrategy()->onAfterInsertMessage($message, $ticket); $this->restoreStrategy(); echo $this->renderTicketSubmited($ticket); } else { echo $this->renderTitle(); echo $form; } } /** @return Am_Helpdesk_Strategy_Abstract */ protected function getStrategy() { return is_null($this->strategy) ? Am_Di::getInstance()->helpdeskStrategy : $this->strategy; } public function switchStrategy(Am_Helpdesk_Strategy_Abstract $strategy) { $this->strategy = $strategy; } public function restoreStrategy() { if (!is_null($this->strategy)) { $this->strategy = null; } } protected function renderTicketSubmited($ticket) { $out = sprintf('

%s

', ___('Ticket has been submited')); $out .= sprintf('

%s #%s

', ___('Reference number is:'), $this->getStrategy()->ticketUrl($ticket), $ticket->ticket_mask ); return $out; } } abstract class Am_Helpdesk_Grid extends Am_Grid_Editable_Helpdesk { public function __construct(Am_Mvc_Request $request, Am_View $view) { $id = explode('_', get_class($this)); $id = strtolower(array_pop($id)); parent::__construct('_' . $id, $this->getGridTitle(), $this->createDs(), $request, $view); if ($f = $this->createFilter()) { $this->setFilter($f); } $this->setRecordTitle(array($this, 'getTicketRecordTitle')); } protected function createFilter() { return new Am_Grid_Filter_Helpdesk_Adv_WithStatus; } abstract function getStatusIconId($id, $record); public function getTicketRecordTitle(HelpdeskTicket $ticket = null) { return $ticket ? sprintf('%s (#%s: %s)', ___('Ticket'), $ticket->ticket_mask, $ticket->subject) : ___('Ticket'); } public function cbGetTrAttribs(& $ret, $record) { if ($this->isNotImportant($record)) { $ret['class'] = isset($ret['class']) ? $ret['class'] . ' disabled' : 'disabled'; } } protected function isNotImportant($record) { return false; } public function initActions() { //nop } public function createForm() { return $this->getDi()->helpdeskStrategy->createNewTicketForm(); } public function renderSubject($r) { $url = $this->getDi()->helpdeskStrategy->ticketUrl($r); $category = $r->category_id && $r->c_title ? sprintf('
%s', Am_Html::escape($r->c_title)) : ''; return sprintf('%s %d %s%s', $url, Am_Html::escape($r->subject), $r->msg_cnt, Am_Html::escape(mb_substr(preg_replace('/(\s{2,})/m', ' ', strip_tags(trim($r->msg_last))), 0, 70)) . '…', $category ); } public function renderStatus($record) { $statusOptions = HelpdeskTicket::getStatusOptions(); list($status) = explode('_', $record->status); $status = $this->getStatusIconId($status, $record); return sprintf('%s', $this->getDi()->view->icon($status, $statusOptions[$record->status]) ); } public function renderTime($record, $fieldName) { return sprintf('', amDatetime($record->$fieldName), date('c', amstrtotime($record->$fieldName)), $this->getView()->getElapsedTime($record->$fieldName)); } public function renderUser($record, $fieldName) { $name = trim("{$record->m_name_f} {$record->m_name_l}"); return sprintf('%s%s', $this->getView()->userUrl($record->user_id), $record->m_login, $name ? sprintf(' (%s)', Am_Html::escape($name)) : '' ); } protected function createDS() { $query = new Am_Query(Am_Di::getInstance()->helpdeskTicketTable); $query->addField('COUNT(msg.message_id)', 'msg_cnt') ->addField('(SELECT content FROM ?_helpdesk_message ' . 'WHERE ticket_id = t.ticket_id ' . 'ORDER BY dattm DESC LIMIT 1)', 'msg_last') ->addField('m.login AS m_login') ->addField('m.name_f AS m_name_f') ->addField('m.name_l AS m_name_l') ->addField('m.email AS m_email') ->leftJoin('?_helpdesk_message', 'msg', 'msg.ticket_id=t.ticket_id') ->addWhere('msg.type=?', 'message') ->leftJoin('?_user', 'm', 't.user_id=m.user_id') ->leftJoin('?_helpdesk_category', 'c', 't.category_id=c.category_id') ->addField('c.title', 'c_title') ->addOrder('updated', true); if (Am_Di::getInstance()->plugins_misc->isEnabled('avatar')) { $query->addField('m.avatar', 'm_avatar'); } return $query; } public function getGridTitle() { return ___('Tickets'); } }library/Am/Helpdesk/Grid/Admin/Dashboard.php000064400000001516152101601110014610 0ustar00addWhere('t.status<>?', HelpdeskTicket::STATUS_CLOSED); return $q; } public function initActions() { parent::initActions(); $this->actionAdd(new Am_Grid_Action_Ticket()); $this->actionAdd(new Am_Grid_Action_Delete()); if ($cnt = $this->getDi()->helpdeskTicketTable->countByStatus(HelpdeskTicket::STATUS_CLOSED)) { $this->actionAdd(new Am_Grid_Action_Url('archive', ___('Closed Tickets') . " ($cnt)", $this->getDi()->url('helpdesk/admin/archive'))) ->setType(Am_Grid_Action_Abstract::NORECORD) ->setTarget('_top') ->setCssClass('link'); } } }library/Am/Helpdesk/Grid/Admin/Archive.php000064400000002011152101601110014271 0ustar00addWhere('t.status=?', HelpdeskTicket::STATUS_CLOSED); return $q; } public function getGridTitle() { return ___('Archive'); } public function initActions() { parent::initActions(); $this->actionAdd(new Am_Grid_Action_Delete()); $this->actionDelete('ticket'); if ($cnt = $this->getDi()->helpdeskTicketTable->countBy(array( 'status' => '<>' . HelpdeskTicket::STATUS_CLOSED))) { $this->actionAdd(new Am_Grid_Action_Url('dashboard', ___('Dashboard') . " ($cnt)", $this->getDi()->url('helpdesk/admin'))) ->setType(Am_Grid_Action_Abstract::NORECORD) ->setTarget('_top') ->setCssClass('link'); } } } library/Am/Helpdesk/Grid/Admin.php000064400000006152152101601110012722 0ustar00getDataSource(); $ds->leftJoin('?_admin', 'a', 't.owner_id=a.admin_id') ->addField("CONCAT(a.login, ' (',a.name_f, ' ', a.name_l, ')')", 'owner'); if ($this->getDi()->plugins_misc->isEnabled('avatar') && $this->getDi()->modules->get('helpdesk')->getConfig('show_avatar')) { $this->addField(new Am_Grid_Field('avatar', '', false, '', array($this, 'renderAvatar'), '1%')); } elseif ($this->getDi()->modules->get('helpdesk')->getConfig('show_gravatar')) { $this->addField(new Am_Grid_Field('gravatar', '', false, '', array($this, 'renderGravatar'), '1%')); } $this->addField(new Am_Grid_Field('m_login', ___('User'), true, '', array($this, 'renderUser'))); $this->addField(new Am_Grid_Field('subject', ___('Subject'), true, '', array($this, 'renderSubject'))); $this->addField(new Am_Grid_Field_Date('created', ___('Created')))->setFormatDate(); $this->addField(new Am_Grid_Field('updated', ___('Updated'), true, '', array($this, 'renderTime'))); if ($this->getDi()->db->selectCell("SELECT COUNT(*) FROM ?_helpdesk_ticket WHERE owner_id IS NOT NULL")) { $this->addField(new Am_Grid_Field('owner_id', ___('Owner'), true, '', array($this, 'renderOwner'))); } $this->addField(new Am_Grid_Field('ticket_mask', ___('Ticket#'), true)); $this->addField(new Am_Grid_Field('status', ___('Status'), true, '', array($this, 'renderStatus'), '1%')); $this->addCallback(Am_Grid_ReadOnly::CB_TR_ATTRIBS, array($this, 'cbGetTrAttribs')); } public function initActions() { parent::initActions(); $this->actionAdd(new Am_Grid_Action_Delete); $this->actionAdd(new Am_Grid_Action_Group_CloseTicket); $this->actionAdd(new Am_Grid_Action_Group_Delete); } public function getStatusIconId($id, $record) { return ($id == 'awaiting' && $record->status == HelpdeskTicket::STATUS_AWAITING_ADMIN_RESPONSE ? $id . '-me' : $id); } public function renderOwner($record) { return $record->owner_id ? sprintf('%s', Am_Html::escape(str_replace(' ( )', '', $record->owner))) : ''; } public function renderGravatar($record) { return sprintf('
', '//www.gravatar.com/avatar/' . md5(strtolower(trim($record->m_email))) . '?s=40&d=mm'); } public function renderAvatar($record) { return sprintf('
', $this->getDi()->url('misc/avatar/' . $record->m_avatar)); } protected function isNotImportant($record) { return $record->status == HelpdeskTicket::STATUS_AWAITING_USER_RESPONSE; } }library/Am/View/Helper/Skip.php000064400000004334152101601110012305 0ustar00 $v) { if (preg_match('/^\s*>\s*>/', trim($v))) { $s_arr[$k] = 1; } else { $s_arr[$k] = 0; } } //add one none skiped line at the end //in order to resolve problem if last line should be skiped too $arr[] = ''; $arr = array_map(array('Am_Html', 'escape'), $arr); $s_arr[] = 0; //remove empty lines beetween skiped lines $prev = 0; $empty_lines = array(); foreach ($s_arr as $k => $v) { if (trim($arr[$k]) == '') { $empty_lines[] = $k; } elseif ($v && $prev) { foreach ($empty_lines as $key) { $s_arr[$key] = 1; } $empty_lines = array(); $prev = 1; } elseif ($v) { $empty_lines = array(); $prev = 1; } else { $prev = 0; } } //skip $skiped = 0; $skiped_lines = array(); $label_lines_skipped = ___('lines skipped'); foreach ($s_arr as $k => $v) { if ($v) { $skiped_lines[] = $arr[$k]; if (!$skiped) { $first_skiped_line = $k; } else { unset($arr[$k]); } $skiped++; } elseif ($skiped) { $arr[$first_skiped_line] = '
...' . $skiped . ' ' . $label_lines_skipped . '...
' . implode("\n", $skiped_lines) . '
'; $skiped = 0; $skiped_lines = array(); } } $string = implode("\n", $arr); return $string; } }library/Am/View/Helper/Hyperlinks.php000064400000000473152101601110013527 0ustar00".?,)]{0,1}(\s|$))|(&(quot|gt);))#i'; return preg_replace($pattern, '$1$3', $string); } }library/SetupForms.php000064400000015032152101601110011015 0ustar00setTitle(___('Helpdesk')); $this->data['help-id'] = 'Setup/Helpdesk'; } function initElements() { $fieldSetNotifications = $this->addFieldset() ->setLabel(___('Notifications')); $fieldSetNotifications->addElement('email_checkbox', 'helpdesk.notify_new_message', null, array('help-id' => '#Enabling.2FDisabling_Customer_Notifications')) ->setLabel(___("Send Notification about New Messages to Customer\n" . "aMember will email a notification to user " . "each time admin responds to a user ticket")); $this->setDefault('helpdesk.notify_new_message', 1); $fieldSetNotifications->addElement('email_checkbox', 'helpdesk.notify_new_message_admin') ->setLabel(___("Send Notification about New Messages to Admin\n" . "aMember will email a notification to admin " . "each time user responds to a ticket")); $this->setDefault('helpdesk.notify_new_message_admin', 1); $fieldSetNotifications->addElement('email_checkbox', 'helpdesk.new_ticket') ->setLabel(___("New Ticket Autoresponder to Customer\n" . "aMember will email an autoresponder to user " . "each time user create new ticket")); $fieldSetNotifications->addElement('email_checkbox', 'helpdesk.notify_assign') ->setLabel(___("Send Notification When Ticket is Assigned to Admin\n" . "aMember will email a notification to admin " . "each time ticket is assigned to him")); $fieldSetConversation = $this->addFieldset() ->setLabel(___('Conversation')); $fieldSetConversation->addAdvCheckbox('helpdesk.can_edit') ->setLabel(___("Admin Can Edit His Messages\n" . "within 5 minutes after post")); $fieldSetConversation->addAdvCheckbox('helpdesk.add_signature') ->setLabel(___('Add Signature to Response')); $fieldSetConversation->addTextarea('helpdesk.signature', array('rows'=>3, 'class'=>'el-wide')) ->setLabel(___("Signature Text\n" . "You can use the following placeholders %name_f%, %name_l% " . "it will be expanded to first and last name of admin in operation")); $this->addScript('script') ->setScript(<<addAdvCheckbox('helpdesk.disclosure_admin') ->setLabel(___("Disclosure Admin real name in user interface\n" . "otherwise only word Administrator is shown")); $fieldSetConversation->addAdvCheckbox('helpdesk.does_not_quote_in_reply') ->setLabel(___('Does Not Quote Message in Reply')); $fieldSetConversation->addAdvCheckbox('helpdesk.does_not_allow_attachments') ->setLabel(___('Does Not Allow to Upload Attachments for Users')); $gr = $fieldSetConversation->addGroup() ->setLabel(___("Autoclose Tickets Due to Inactivity")); $gr->addAdvCheckbox('helpdesk.autoclose') ->setId('helpdesk_autoclose'); $gr->addStatic()->setContent(sprintf(' %s ', ___("after"))); $gr->addText('helpdesk.autoclose_period', array('class'=>'helpdesk_autoclose_hours', 'size' => 3, 'placeholder'=>70)); $gr->addStatic()->setContent(sprintf(' %s ', ___("hours"))); $fieldSetConversation->addElement('email_checkbox', 'helpdesk.notify_autoclose') ->setLabel(___("Send Autoclose Notification to User\n" . "aMember will email an autoresponder to user " . "when ticket is closed due to inactivity")); $this->addScript()->setScript(<<addFieldset() ->setLabel(___('Features')); $fieldSetFeatures->addAdvCheckbox('helpdesk.live') ->setLabel(___("Enable Live Conversation (experimental)\n" . "update conversation instantly without page reload (can consume more server resources)")); $fieldSetFeatures->addAdvCheckbox('helpdesk.show_gravatar') ->setId('gravatar') ->setLabel(___("Show Gravatars in Ticket Conversation\n" . 'more details about gravatar can be found %shere%s', '', '')); if (Am_Di::getInstance()->plugins_misc->isEnabled('avatar')) { $fieldSetFeatures->addAdvCheckbox('helpdesk.show_avatar') ->setId('avatar') ->setLabel(___("Show Avatars in Ticket Conversation\n" . 'this option has priority over gravatar if enabled')); $this->addScript()->setScript(<<addAdvCheckbox('helpdesk.does_not_require_login') ->setLabel(___("Does Not Require Login to Access FAQ Section\n" . 'make it public')); $fieldSetFeatures->addAdvCheckbox('helpdesk.does_not_show_faq_tab') ->setLabel(___('Does Not Show FAQ Tab in Member Area')); $fieldSetFeatures->addAdvCheckbox('helpdesk.show_faq_search') ->setLabel(___('Show Search Function in FAQ')); $this->addHtmlEditor('helpdesk.intro', null, array('showInPopup' => true)) ->setLabel(___("Intro Text on Helpdesk Page")); $this->setDefault('helpdesk.intro', 'We answer customer tickets Mon-Fri, 10am - 5pm EST. You can also call us by phone if you have an urgent question.'); } } library/HelpdeskTicket.php000064400000012106152101601110011610 0ustar00 ___('New'), 'awaiting_admin_response' => ___('Awaiting Admin Response'), 'awaiting_user_response' => ___('Awaiting User Response'), 'closed' => ___('Closed') ); } public function getMessages() { return $this->getDi()->helpdeskMessageTable->findBy( array('ticket_id' => $this->pk()), null, null, "dattm DESC"); } /** * @return User */ public function getUser() { return $this->getDi()->userTable->load($this->user_id); } /** * @return Admin */ public function getOwner() { return $this->owner_id ? $this->getDi()->adminTable->load($this->owner_id, false) : null; } public function getWatchers() { $res = array(); foreach (explode(',', $this->watcher_ids) as $id) { if ($id && $admin = $this->getDi()->adminTable->load($id, false)) { $res[] = $admin; } } return $res; } /** * @return HelpdeskCategory */ public function getCategory() { return $this->category_id ? $this->getDi()->helpdeskCategoryTable->load($this->category_id, false) : null; } public function isLocked(Admin $admin) { return $this->lock_until && ($this->lock_until > sqlTime('now')) && ($this->lock_admin_id != $admin->pk()); } public function lock(Admin $admin) { $this->updateQuick(array( 'lock_until' => sqlTime('+2 minutes'), 'lock_admin_id' => $admin->pk(), 'lock_admin' => sprintf('%s (%s %s)', $admin->login, $admin->name_f, $admin->name_l) )); } protected function _generateMask() { if (!empty($this->ticket_mask)) return; $this->ticket_mask = $this->getDi()->security->randomString(3, 'ABCDEFGJIKLMNOPQRSTUVWXYZ') . '-' . rand(100000, 999999); } /** * before record insertion generate new ticket mask. if the generated mask is not unique, * try 20 times to generate new mask, then throw exception * @return type */ public function insert($reload = true) { $event = new Am_Event(Bootstrap_Helpdesk::EVENT_TICKET_BEFORE_INSERT, array( 'ticket' => $this )); $this->getDi()->hook->call($event); $maxAttempts = 20; for ($i = 0; $i <= $maxAttempts; $i++) { try { $this->_generateMask(); parent::insert($reload); $event = new Am_Event(Bootstrap_Helpdesk::EVENT_TICKET_AFTER_INSERT, array( 'ticket' => $this )); $this->getDi()->hook->call($event); return $this; } catch (Am_Exception_Db_NotUnique $e) { if ($i >= $maxAttempts) throw new Am_Exception_InternalError("Could not generate new ticket mask after [$i] attempts"); $this->ticket_mask = null; } } } public function delete() { foreach ($this->getMessages() as $msg) { $msg->delete(); } parent::delete(); } } class HelpdeskTicketTable extends Am_Table_WithData { protected $_key = 'ticket_id'; protected $_table = '?_helpdesk_ticket'; protected $_recordClass = 'HelpdeskTicket'; public function insert(array $values, $returnInserted = false) { if (empty($values['created'])) $values['created'] = $this->getDi()->sqlDateTime; return parent::insert($values, $returnInserted); } public function load($keyOrTicketId, $throwExceptions = true) { if (preg_match('/^\d+$/', trim($keyOrTicketId), $matches)) return parent::load($matches[0], $throwExceptions); else { $keyOrTicketId = filterId($keyOrTicketId); $found = $this->findFirstByTicketMask($keyOrTicketId); if (!$found && $throwExceptions) throw new Am_Exception_InternalError("Ticket with mask [$keyOrTicketId] not found"); return $found; } } public function clearOld($date) { foreach ($this->findByUpdated('<' . $date) AS $ticket) { $ticket->delete(); } } }library/HelpdeskSnippet.php000064400000000644152101601110012013 0ustar00 helpdesk.notify_new_message 1 en text %site_title%: New Message for Your Ticket [#%ticket.ticket_mask%] You have received a new message in helpdesk for your ticket [%ticket.subject%] Follow a link below to view this message: %url% helpdesk.notify_new_message_admin 2 en text %site_title%: New Message for Ticket [#%ticket.ticket_mask%] You have received a new message in helpdesk for ticket [%ticket.subject%] Follow a link below to view this message: %url% helpdesk.new_ticket 1 en text %site_title%: New Ticket [#%ticket.ticket_mask%] You created ticket [%ticket.subject%] in our helpdesk system. Thank you for your enquiry. We will respond within 24 hours. Follow a link below to view your ticket: %url% helpdesk.notify_assign 2 en text %site_title%: Ticket [#%ticket.ticket_mask%] is assigned to you Ticket [%ticket.subject%] is assigned to you. Follow a link below to view this ticket: %url% helpdesk.notify_autoclose 1 en text %site_title%: Ticket [#%ticket.ticket_mask%] has been closed automatically Your ticket [%ticket.subject%] has been closed automatically due to inactivity. If the issue hasn't been resolved to your satisfaction yet please let us know. Follow a link below to view this ticket: %url% Bootstrap.php000064400000046136152101601110007230 0ustar00getDi()->uploadTable->defineUsage(self::ATTACHMENT_UPLOAD_PREFIX, 'helpdesk_message', 'attachments', UploadTable::STORE_IMPLODE, "Ticket [%ticket_id%]", '/helpdesk/admin/p/index/index'); $this->getDi()->uploadTable->defineUsage(self::ADMIN_ATTACHMENT_UPLOAD_PREFIX, 'helpdesk_message', 'attachments', UploadTable::STORE_IMPLODE, "Ticket [%ticket_id%]", '/helpdesk/admin/p/index/index'); } function renderNotification() { if ($user_id = $this->getDi()->auth->getUserId()) { $cnt = $this->getDi()->db->selectCell("SELECT COUNT(ticket_id) FROM ?_helpdesk_ticket WHERE has_new=? AND user_id=?", 1, $user_id); if ($cnt) { return '
' . ___('You have %s%d ticket(s)%s that require your attention', sprintf('', $this->getDi()->url('helpdesk',array('_user_has_new'=>1))), $cnt, '') . '
'; } } } function onSetupEmailTemplateTypes(Am_Event $event) { $ticket = array( 'ticket.ticket_mask' => 'Ticket Mask', 'ticket.subject' => 'Ticket Subject', ); $event->addReturn(array( 'id' => 'helpdesk.notify_new_message', 'title' => 'Notify New Message', 'mailPeriodic' => Am_Mail::USER_REQUESTED, 'vars' => $ticket + array('url' => 'Url of Page with Message', 'user'), ), 'helpdesk.notify_new_message'); $event->addReturn(array( 'id' => 'helpdesk.notify_new_message', 'title' => 'Notify New Message', 'mailPeriodic' => Am_Mail::USER_REQUESTED, 'isAdmin' => true, 'vars' => $ticket + array('url' => 'Url of Page with Message', 'user'), ), 'helpdesk.notify_new_message_admin'); $event->addReturn(array( 'id' => 'helpdesk.new_ticket', 'title' => 'Autoresponder New Ticket', 'mailPeriodic' => Am_Mail::USER_REQUESTED, 'vars' => $ticket + array('url' => 'Url of Page with Ticket', 'user'), ), 'helpdesk.new_ticket'); $event->addReturn(array( 'id' => 'helpdesk.notify_assign', 'title' => 'Notify Ticket is Assigned to Admin', 'mailPeriodic' => Am_Mail::ADMIN_REQUESTED, 'vars' => $ticket + array('url' => 'Url of Page with Ticket', 'admin'), 'isAdmin' => true, ), 'helpdesk.notify_assign'); $event->addReturn(array( 'id' => 'helpdesk.notify_autoclose', 'title' => 'Notify User about Ticket Autoclose', 'mailPeriodic' => Am_Mail::USER_REQUESTED, 'vars' => array('user') + $ticket + array('url' => 'Url of Page with Ticket'), ), 'helpdesk.notify_autoclose'); } function onGetUploadPrefixList(Am_Event $event) { $event->addReturn(array( Am_Upload_Acl::IDENTITY_TYPE_ADMIN => array( self::ADMIN_PERM_ID => Am_Upload_Acl::ACCESS_ALL ) ), self::ADMIN_ATTACHMENT_UPLOAD_PREFIX); if (!$this->getConfig('does_not_allow_attachments')) { $event->addReturn(array( Am_Upload_Acl::IDENTITY_TYPE_ADMIN => array( self::ADMIN_PERM_ID => Am_Upload_Acl::ACCESS_ALL ), Am_Upload_Acl::IDENTITY_TYPE_USER => Am_Upload_Acl::ACCESS_WRITE | Am_Upload_Acl::ACCESS_READ_OWN ), self::ATTACHMENT_UPLOAD_PREFIX); } } function onLoadAdminDashboardWidgets(Am_Event $event) { $event->addReturn(new Am_Widget('helpdesk-messages', ___('Last Messages in Helpdesk'), array($this, 'renderWidget'), Am_Widget::TARGET_ANY, array($this, 'createWidgetConfigForm'), self::ADMIN_PERM_ID)); } function onAdminAfterDelete(Am_Event $e) { $this->getDi()->db->query("UPDATE ?_helpdesk_ticket SET owner_id = NULL WHERE owner_id=?", $e->getAdmin()->pk()); $this->getDi()->db->query("UPDATE ?_helpdesk_ticket SET lock_admin_id = NULL, lock_admin = NULL, lock_until = NULL WHERE lock_admin_id=?", $e->getAdmin()->pk()); } function createWidgetConfigForm() { $form = new Am_Form_Admin(); $form->addInteger('num') ->setLabel(___('Number of Messages to display')) ->setValue(5); return $form; } function renderWidget(Am_View $view, $config = null) { $view->num = is_null($config) ? 5 : $config['num']; return $view->render('admin/helpdesk/widget/messages.phtml'); } function onClearItems(Am_Event $event) { $event->addReturn(array( 'method' => array($this->getDi()->helpdeskTicketTable, 'clearOld'), 'title' => 'Helpdesk Tickets', 'desc' => 'records with last update date early than Date to Purge' ), 'helpdesk_tickets'); } function onAdminNotice(Am_Event $e) { /* @var $admin Admin */ $admin = $this->getDi()->authAdmin->getUser(); if (!$admin->hasPermission(self::ADMIN_PERM_ID)) return; $cnt = $this->getDi()->helpdeskTicketTable ->countByStatus(array( HelpdeskTicket::STATUS_AWAITING_ADMIN_RESPONSE, HelpdeskTicket::STATUS_NEW)); if ($cnt) { $e->addReturn(___('You have %s%d ticket(s)%s that require your attention', sprintf('', $this->getDi()->url('helpdesk/admin?_dashboard_filter_s[]=new&_dashboard_filter_s[]=awaiting_admin_response')), $cnt, '')); } } function onUserMerge(Am_Event $event) { $target = $event->getTarget(); $source = $event->getSource(); $this->getDi()->db->query('UPDATE ?_helpdesk_ticket SET user_id=? WHERE user_id=?', $target->pk(), $source->pk()); } function onAdminMenu(Am_Event $event) { $cntMy = $this->getDi()->helpdeskTicketTable->countBy(array( 'owner_id' => $this->getDi()->authAdmin->getUserId(), 'status' => array( HelpdeskTicket::STATUS_AWAITING_ADMIN_RESPONSE, HelpdeskTicket::STATUS_NEW))); $cntDashboard = $this->getDi()->helpdeskTicketTable ->countByStatus(array( HelpdeskTicket::STATUS_AWAITING_ADMIN_RESPONSE, HelpdeskTicket::STATUS_NEW)); $event->getMenu()->addPage(array( 'label' => ___('Helpdesk'), 'uri' => '#', 'id' => 'helpdesk', 'resource' => self::ADMIN_PERM_ID, 'pages' => array( array( 'label' => ___('Dashboard') . ($cntDashboard ? " (($cntDashboard))" : ''), 'controller' => 'admin', 'action' => 'index', 'module' => 'helpdesk', 'id' => 'helpdesk-ticket', 'resource' => self::ADMIN_PERM_ID ), array( 'label' => ___('My Tickets') . ($cntMy ? " (($cntMy))" : ''), 'controller' => 'admin-my', 'action' => 'index', 'module' => 'helpdesk', 'id' => 'helpdesk-ticket-my', 'resource' => self::ADMIN_PERM_ID ), array( 'label' => ___('Categories'), 'controller' => 'admin-category', 'action' => 'index', 'module' => 'helpdesk', 'id' => 'helpdesk-category', 'resource' => self::ADMIN_PERM_CATEGORY ), array( 'label' => ___('Fields'), 'controller' => 'admin-fields', 'action' => 'index', 'module' => 'helpdesk', 'id' => 'helpdesk-fields', 'resource' => self::ADMIN_PERM_CATEGORY ), array( 'label' => ___('FAQ'), 'controller' => 'admin-faq', 'action' => 'index', 'module' => 'helpdesk', 'id' => 'helpdesk-faq', 'resource' => self::ADMIN_PERM_FAQ )) )); } function onUserMenu(Am_Event $event) { $page = $helpdeskPage = array( 'id' => 'helpdesk', 'label' => ___('Helpdesk'), 'controller' => 'index', 'action' => 'index', 'module' => 'helpdesk', 'order' => 600, ); if (!$this->getConfig('does_not_show_faq_tab') && $this->getDi()->helpdeskFaqTable->countBy()) { $page = array( 'id' => 'helpdesk-root', 'label' => ___('Support'), 'uri' => 'javascript:;', 'order' => 600, 'pages' => array( $helpdeskPage, array( 'id' => 'helpdesk-faq', 'label' => ___('FAQ'), 'controller' => 'faq', 'action' => 'index', 'module' => 'helpdesk', 'order' => 601, ) ) ); } $event->getMenu()->addPage($page); } function onUserTabs(Am_Event_UserTabs $event) { extract($this->getDi()->db->selectRow("SELECT COUNT(*) AS cnt_all, COUNT(IF(status IN ('new', 'awaiting_admin_response'), ticket_id, NULL)) AS cnt_open FROM ?_helpdesk_ticket WHERE user_id=?", $event->getUserId())); $event->getTabs()->addPage(array( 'id' => 'helpdesk', 'module' => 'helpdesk', 'controller' => 'admin-user', 'action' => 'index', 'params' => array( 'user_id' => $event->getUserId() ), 'label' => ___('Tickets') . sprintf(' (%s)', $cnt_all ? $cnt_open . '/' . $cnt_all: 0), 'order' => 1000, 'resource' => self::ADMIN_PERM_ID, )); } function onGetPermissionsList(Am_Event $event) { $event->addReturn(___('Helpdesk: Can operate with helpdesk tickets'), self::ADMIN_PERM_ID); $event->addReturn(___('Helpdesk: FAQ'), self::ADMIN_PERM_FAQ); $event->addReturn(___('Helpdesk: Categories'), self::ADMIN_PERM_CATEGORY); } function onUserAfterDelete(Am_Event_UserAfterDelete $event) { $this->getDi()->db->query("DELETE FROM ?_helpdesk_message WHERE ticket_id IN (SELECT ticket_id FROM ?_helpdesk_ticket WHERE user_id=?)", $event->getUser()->user_id); $this->getDi()->db->query("DELETE FROM ?_helpdesk_ticket WHERE user_id=?", $event->getUser()->user_id); } function onHourly() { if ($this->getConfig('autoclose')) { $period = $this->getConfig('autoclose_period', 72); $thresholdDate = sqlTime("-$period hours"); foreach($this->getDi()->db->selectPage($total, " SELECT * FROM ?_helpdesk_ticket WHERE status=? AND updated < ? ", HelpdeskTicket::STATUS_AWAITING_USER_RESPONSE, $thresholdDate) as $row) { $ticket = $this->getDi()->helpdeskTicketRecord->fromRow($row); $ticket->status = HelpdeskTicket::STATUS_CLOSED; $ticket->updated = $this->getDi()->sqlDateTime; $ticket->save(); $user = $ticket->getUser(); if ($this->getConfig('notify_autoclose')) { $et = Am_Mail_Template::load('helpdesk.notify_autoclose', $user->lang); $et->setUser($user); $et->setTicket($ticket); $et->setUrl($this->getDi()->url('helpdesk/ticket/'.$ticket->ticket_mask,null,false,true)); $et->send($user); } } } } function onInitFinished() { $this->getDi()->blocks->add(new Am_Block('member/main/top', null, 'helpdesk-notification', null, array($this, 'renderNotification'))); $this->getDi()->register('helpdeskStrategy', 'Am_Helpdesk_Strategy_Abstract') ->setConstructor('create') ->setArguments(array($this->getDi())); $router = $this->getDi()->router;; $router->addRoute('helpdesk-item', new Am_Mvc_Router_Route( 'helpdesk/faq/i/:title', array( 'module' => 'helpdesk', 'controller' => 'faq', 'action' => 'item' ) )); $router->addRoute('helpdesk-category', new Am_Mvc_Router_Route( 'helpdesk/faq/c/:cat', array( 'module' => 'helpdesk', 'controller' => 'faq', 'action' => 'index' ) )); $router->addRoute('helpdesk-ticket', new Am_Mvc_Router_Route( 'helpdesk/ticket/:ticket', array( 'module' => 'helpdesk', 'controller' => 'index', 'action' => 'view', 'page_id' => 'view' ) )); $router->addRoute('helpdesk-ticket-admin', new Am_Mvc_Router_Route( 'helpdesk/admin/ticket/:ticket', array( 'module' => 'helpdesk', 'controller' => 'admin', 'action' => 'view', 'page_id' => 'view' ) )); $router->addRoute('helpdesk-new', new Am_Mvc_Router_Route( 'helpdesk/ticket/new', array( 'module' => 'helpdesk', 'controller' => 'index', 'action' => 'new', 'page_id' => 'view' ) )); $router->addRoute('helpdesk-new-admin', new Am_Mvc_Router_Route( 'helpdesk/admin/ticket/new', array( 'module' => 'helpdesk', 'controller' => 'admin', 'action' => 'new', 'page_id' => 'view' ) )); } function onBuildDemo(Am_Event $event) { $subjects = array( 'Please help', 'Urgent question', 'I have a problem', 'Important question', 'Pre-sale inquiry', ); $questions = array( "My website is now working. Can you help?", "I have a problem with website script.\nWhere can I find documentation?", "I am unable to place an order, my credit card is not accepted.", ); $answers = array( "Please call us to phone# 1-800-222-3334", "We are looking to your problem, and it will be resolved within 4 hours", ); $user = $event->getUser(); $now = $this->getDi()->time; $added = amstrtotime($user->added); /* @var $user User */ while (rand(0, 10) < 4) { $created = min($now, $added + rand(60, $now - $added)); $ticket = $this->getDi()->helpdeskTicketRecord; $ticket->status = HelpdeskTicket::STATUS_AWAITING_ADMIN_RESPONSE; $ticket->subject = $subjects[rand(0, count($subjects) - 1)]; $ticket->user_id = $user->pk(); $ticket->created = sqlTime($created); $ticket->updated = sqlTime($created); $ticket->insert(); // $msg = $this->getDi()->helpdeskMessageRecord; $msg->content = $questions[rand(0, count($questions) - 1)]; $msg->type = 'message'; $msg->ticket_id = $ticket->pk(); $msg->dattm = sqlTime($created); $msg->insert(); // if (rand(0, 10) < 6) { $msg = $this->getDi()->helpdeskMessageRecord; $msg->content = $answers[rand(0, count($answers) - 1)]; $msg->type = 'message'; $msg->ticket_id = $ticket->pk(); $msg->dattm = sqlTime(min($created + rand(60, 3600 * 24), $now)); $msg->admin_id = $this->getDi()->adminTable->findFirstBy()->pk(); $msg->insert(); if (rand(0, 10) < 6) $ticket->status = HelpdeskTicket::STATUS_AWAITING_USER_RESPONSE; else $ticket->status = HelpdeskTicket::STATUS_CLOSED; $ticket->updated = $msg->dattm; $ticket->update(); } } } function onLoadReports() { require_once 'Am/Report/Helpdesk.php'; } function onDbUpgrade(Am_Event $e) { if (version_compare($e->getVersion(), '4.2.20') < 0) { echo "Fix FAQ categories..."; if (ob_get_level ()) ob_end_flush(); $this->getDi()->db->query("UPDATE ?_helpdesk_faq SET category=? WHERE category=?", null, ''); echo "Done
\n"; echo "Add default Order to Helpdesk FAQ..."; $this->getDi()->db->query("SET @i = 0"); $this->getDi()->db->query("UPDATE ?_helpdesk_faq SET sort_order=(@i:=@i+1)"); echo "Done
\n"; echo "Add default Order to Helpdesk Categories..."; $this->getDi()->db->query("SET @i = 0"); $this->getDi()->db->query("UPDATE ?_helpdesk_category SET sort_order=(@i:=@i+1)"); echo "Done
\n"; } if (version_compare($e->getVersion(), '5.0.5') <= 0) { echo "Update Ticket Status..."; $this->getDi()->db->query("UPDATE ?_helpdesk_ticket SET has_new=1 WHERE status IN (?a)", array(HelpdeskTicket::STATUS_AWAITING_USER_RESPONSE)); echo "Done
\n"; } if (version_compare($e->getVersion(), '5.1.6') <= 0) { if (!$this->getDi()->db->selectCell("SELECT COUNT(*) FROM ?_resource_access WHERE resource_type=?", HelpdeskCategory::ACCESS_TYPE)) { //idempotent action echo "Setup Default Protection for Categories..."; foreach($this->getDi()->helpdeskCategoryTable->findBy() as $cat) { $this->getDi()->resourceAccessTable ->setAccess($cat->pk(), HelpdeskCategory::ACCESS_TYPE, array( ResourceAccess::FN_FREE => array( json_encode(array( 'start' => null, 'stop' => null, 'text' => ___('Free Access') ))) )); } echo "Done
\n"; } } } }module.xml000064400000000261152101601110006536 0ustar00 helpdesk Helpdesk Customer support helpdesk 5.0.6 controllers/AdminFieldsController.php000064400000002766152101601110014045 0ustar00hasPermission(Bootstrap_Helpdesk::ADMIN_PERM_CATEGORY); } protected function getTable() { return $this->getDi()->helpdeskTicketTable; } public function createGrid() { $grid = parent::createGrid(); $grid->addCallback(Am_Grid_Editable::CB_AFTER_DELETE, array($this, 'afterDelete')); $grid->setPermissionId(Bootstrap_Helpdesk::ADMIN_PERM_CATEGORY); return $grid; } public function createForm() { $form = new Am_Form_Admin_CustomField_Ticket($this->grid->getRecord()); $form->setTable($this->getTable()); return $form; } public function afterDelete($record) { foreach ($this->getDi()->helpdeskCategoryTable->findBy(array()) as $c) { $fields = $c->unserializeList($c->fields); if (in_array($record->name, $fields)) { $fields = array_diff($fields, array($record->name)); $c->fields = $c->serializeList($fields); $c->save(); } } } }controllers/AdminMyController.php000064400000003010152101601110013203 0ustar00addWhere('t.owner_id=?d', Am_Di::getInstance()->authAdmin->getUserId()); $q->addWhere('t.status<>?', HelpdeskTicket::STATUS_CLOSED); return $q; } public function getGridTitle() { return ___('Tickets Assigned to Me'); } public function initGridFields() { parent::initGridFields(); $this->removeField('owner_id'); } public function initActions() { parent::initActions(); $this->actionAdd(new Am_Grid_Action_Delete()); } } class Helpdesk_AdminMyController extends Am_Mvc_Controller_Pages { public function checkAdminPermissions(Admin $admin) { return $admin->hasPermission(Bootstrap_Helpdesk::ADMIN_PERM_ID); } function preDispatch() { $this->view->headLink()->appendStylesheet($this->view->_scriptCss('helpdesk-admin.css')); $this->setActiveMenu('helpdesk-ticket-my'); parent::preDispatch(); } public function initPages() { $this->addPage('Am_Helpdesk_Grid_My', 'index', ___('Tickets')) ->addPage(array($this, 'createController'), 'view', ___('Conversation')); } public function renderTabs() { return ''; } public function createController($id, $title, $grid) { return new Am_Helpdesk_Controller($grid->getRequest(), $grid->getResponse(), $this->_invokeArgs); } }controllers/FaqController.php000064400000005207152101601110012366 0ustar00getModule()->getConfig('does_not_require_login')) { $this->getDi()->auth->requireLogin($this->getDi()->url('helpdesk/faq',null,false,2)); } $this->view->headLink()->appendStylesheet($this->view->_scriptCss('helpdesk-user.css')); if ($this->getDi()->auth->getUser() && ($page = $this->getDi()->navigationUser->findOneBy('id', 'helpdesk-faq'))) { $page->setActive(true); } parent::preDispatch(); } public function indexAction() { $this->view->categories = $this->getDi()->helpdeskFaqTable->getCategories(); $this->view->catActive = $this->getParam('cat'); $this->view->faq = $this->getDi()->helpdeskFaqTable->findBy(array( 'category' => $this->getParam('cat', null)), null, null, 'sort_order'); if ($this->getParam('cat')) { $this->view->getHelper('breadcrumbs')->setPath(array($this->getDi()->url('helpdesk/faq',null,false) => ___('FAQ'))); } $this->view->display('helpdesk/faq.phtml'); } public function itemAction() { $path = array($this->getDi()->url('helpdesk/faq',null,false) => ___('FAQ')); $faq = $this->getDi()->helpdeskFaqTable->findFirstByTitle($this->getParam('title')); if ($faq->category) { $path[$this->getDi()->url('helpdesk/faq/c/' . urldecode($faq->category),null,false)] = $faq->category; } $this->view->getHelper('breadcrumbs')->setPath($path); $this->view->faq = $faq; $this->view->display('helpdesk/faq-item.phtml'); } public function searchAction() { $result = $this->getDi()->db->selectPage($total, "SELECT * FROM ?_helpdesk_faq WHERE MATCH(`title`,`content`) AGAINST (? IN NATURAL LANGUAGE MODE) LIMIT 10", $this->getParam('q')); $items = array(); foreach ($result as $row) $items[] = $this->getDi()->helpdeskFaqTable->createRecord($row); $this->view->items = $items; $this->view->display('helpdesk/_search-result.phtml'); } public function suggestAction() { $result = $this->getDi()->db->selectPage($total, "SELECT * FROM ?_helpdesk_faq WHERE MATCH(`title`,`content`) AGAINST (? IN NATURAL LANGUAGE MODE) LIMIT 10", $this->getParam('q')); $items = array(); foreach ($result as $row) $items[] = $this->getDi()->helpdeskFaqTable->createRecord($row); $this->view->items = $items; $this->view->display('helpdesk/_suggest.phtml'); } }controllers/AdminFaqController.php000064400000013617152101601110013343 0ustar00helpdeskFaqTable->getCategories()); $catoptions = array_merge(array('' => ___('-- Without A Category --')), $catoptions); $this->addSelect('category', array(), array('intrinsic_validation' => false, 'options' => $catoptions)) ->setLabel('Category'); $label_add_category = ___('add category'); $label_title_error = ___('Enter title for your new category'); $this->addScript() ->setScript(<< $label_add_category")); jQuery("select[name='category']").change(function(){ jQuery(this).toggle(jQuery(this).find('option').length > 1); }).change(); jQuery(document).on('click',"a#add-category", function(){ var ret = prompt("$label_title_error", ""); if (!ret) return; var \$sel = jQuery("select#category").append( jQuery("").val(ret).html(ret)); \$sel.val(ret).change(); }); }) CUT ); $this->addText('title', array('class' => 'el-wide')) ->setLabel(___('Title')); $this->addHtmlEditor('content') ->setLabel(___('Content')); } } class Am_Grid_Filter_HelpdeskFaq extends Am_Grid_Filter_Abstract { public function getTitle() { return ___('Filter By Title or Category'); } protected function applyFilter() { if ($this->isFiltered()) { $q = $this->grid->getDataSource(); /* @var $q Am_Query */ $q->addWhere('title LIKE ? OR category LIKE ?', '%' . $this->vars['filter'] . '%', '%' . $this->vars['filter'] . '%'); } } public function renderInputs() { return $this->renderInputText(); } } class Am_Grid_Action_EditFaqCategory extends Am_Grid_Action_Abstract { protected $type = self::NORECORD; protected $url; protected $attributes = array( 'target' => '_top' ); public function getUrl($record = null, $id = null) { return Am_Di::getInstance()->url('helpdesk/admin-faq/category',null,false); } public function run() { //nop } } class Am_Grid_Action_Back extends Am_Grid_Action_Abstract { protected $type = self::NORECORD; protected $url; protected $attributes = array( 'target' => '_top' ); public function getUrl($record = null, $id = null) { return Am_Di::getInstance()->url('helpdesk/admin-faq',null,false); } public function run() { //nop } } class Am_Grid_DataSource_FaqCategory extends Am_Grid_DataSource_Array { public function updateRecord($record, $valuesFromForm) { Am_Di::getInstance()->db->query('UPDATE ?_helpdesk_faq SET category=? WHERE category=?', $valuesFromForm['name'], $record->name); } } class Helpdesk_AdminFaqController extends Am_Mvc_Controller_Grid { public function checkAdminPermissions(Admin $admin) { return $admin->hasPermission(Bootstrap_Helpdesk::ADMIN_PERM_FAQ); } public function createGrid() { $ds = new Am_Query($this->getDi()->helpdeskFaqTable); $ds->setOrder('sort_order'); $grid = new Am_Grid_Editable('_helpdesk_faq', ___('FAQ'), $ds, $this->_request, $this->view); $grid->addField(new Am_Grid_Field('title', ___('Title'), true, '', null, '50%')); $grid->addField(new Am_Grid_Field('category', ___('Category'))); $grid->addField('_link', ___('Link'), false)->setRenderFunction(array($this, 'renderLink')); $grid->setForm('Am_Form_Admin_HelpdeskFaq'); $grid->setFilter(new Am_Grid_Filter_HelpdeskFaq()); $grid->addCallback(Am_Grid_Editable::CB_VALUES_FROM_FORM, array($this, 'valuesFromForm')); $grid->setPermissionId(Bootstrap_Helpdesk::ADMIN_PERM_FAQ); $grid->actionAdd(new Am_Grid_Action_Sort_HelpdeskFaq()); if ($this->getDi()->helpdeskFaqTable->getCategories()) { $grid->actionAdd(new Am_Grid_Action_EditFaqCategory('faq-edit-category', ___('Edit Categories'))) ->setCssClass('link'); } return $grid; } public function categoryAction() { $ret = array(); foreach ($this->getDi()->helpdeskFaqTable->getCategories() as $category) { $cat = new stdClass(); $cat->name = $category; $ret[] = $cat; } $ds = new Am_Grid_DataSource_FaqCategory($ret); $grid = new Am_Grid_Editable('_helpdesk_faq_category', ___('Categories'), $ds, $this->_request, $this->view); $grid->setPermissionId(Bootstrap_Helpdesk::ADMIN_PERM_FAQ); $grid->addField(new Am_Grid_Field('name', ___('Title'))); $grid->actionsClear(); $grid->actionAdd(new Am_Grid_Action_Back('faq-edit-category-back', ___('Back to FAQ List'))) ->setCssClass('link'); $grid->actionAdd(new Am_Grid_Action_LiveEdit('name')); $grid->runWithLayout('admin/layout.phtml'); } public function valuesFromForm(& $ret, HelpdeskFaq $record) { if (!isset($ret['category']) || !$ret['category']) $ret['category'] = null; } public function renderLink(Am_Record $record) { $url = Am_Di::getInstance()->url('helpdesk/faq/i/'.urlencode($record->title)); return $this->renderTd(sprintf('%s', $url, ___('link')), false); } } class Am_Grid_Action_Sort_HelpdeskFaq extends Am_Grid_Action_Sort_Abstract { protected function setSortBetween($item, $after, $before) { $this->_simpleSort(Am_Di::getInstance()->helpdeskFaqTable, $item, $after, $before); } }controllers/AdminCategoryController.php000064400000012270152101601110014403 0ustar00addText('title', array('size' => 40)) ->setLabel(___('Title')); $options = array(); foreach (Am_Di::getInstance()->adminTable->findBy() as $admin) { $options[$admin->pk()] = sprintf('%s (%s %s)', $admin->login, $admin->name_f, $admin->name_l); } $this->addSelect('owner_id') ->setLabel(___("Owner\n". 'set the following admin as owner of ticket')) ->loadOptions(array('' => '') + $options); $this->addMagicSelect('watcher_ids') ->setLabel(___("Watchers\n" . 'notify the following admins ' . 'about new messages in this category')) ->loadOptions($options); $options = array(); foreach(Am_Di::getInstance()->helpdeskTicketTable->customFields()->getAll() as $f) { $options[$f->getName()] = $f->title; } $url = Am_Di::getInstance()->url('helpdesk/admin-fields'); $this->addSortableMagicSelect('fields') ->setLabel(___("Fields\n" . "You can add new fields %shere%s", '', '')) ->loadOptions($options); $this->addElement(new Am_Form_Element_ResourceAccess) ->setName('_access') ->setLabel(___("Access Permissions\n" . 'this category will be available only for users ' . 'with proper access permission')) ->setAttribute('without_free_without_login', 'true'); } } class Am_Grid_Action_Sort_HelpdeskCategory extends Am_Grid_Action_Sort_Abstract { protected function setSortBetween($item, $after, $before) { $this->_simpleSort(Am_Di::getInstance()->helpdeskCategoryTable, $item, $after, $before); } } class Helpdesk_AdminCategoryController extends Am_Mvc_Controller_Grid { public function checkAdminPermissions(Admin $admin) { return $admin->hasPermission(Bootstrap_Helpdesk::ADMIN_PERM_CATEGORY); } public function preDispatch() { parent::preDispatch(); $this->view->headScript()->appendFile($this->view->_scriptJs("resourceaccess.js")); } public function createGrid() { $ds = new Am_Query($this->getDi()->helpdeskCategoryTable); $ds->leftJoin('?_admin', 'a', 't.owner_id=a.admin_id') ->addField("CONCAT(a.login, ' (',a.name_f, ' ', a.name_l, ')')", 'owner'); $ds->setOrder('sort_order'); $grid = new Am_Grid_Editable('_helpdesk_category', ___("Ticket Categories"), $ds, $this->_request, $this->view); $grid->addField(new Am_Grid_Field('title', ___('Title'))); $grid->addField(new Am_Grid_Field('fields', ___('Fields'))) ->setGetFunction(function($r, $grid, $fieldname, $field){ return implode(', ', $r->unserializeList($r->{$fieldname})); }); $grid->addField(new Am_Grid_Field('owner_id', ___('Owner'), true, '', array($this, 'renderOwner'))); $grid->addField(new Am_Grid_Field_IsDisabled); $grid->setForm('Am_Form_Admin_HelpdeskCategory'); $grid->addCallback(Am_Grid_Editable::CB_BEFORE_SAVE, array($this, 'beforeSave')); $grid->setPermissionId(Bootstrap_Helpdesk::ADMIN_PERM_CATEGORY); $grid->actionAdd(new Am_Grid_Action_Sort_HelpdeskCategory()); $grid->setFormValueCallback('watcher_ids', array('RECORD', 'unserializeIds'), array('RECORD', 'serializeIds')); $grid->setFormValueCallback('fields', array('RECORD', 'unserializeList'), array('RECORD', 'serializeList')); $grid->addCallback(Am_Grid_Editable::CB_AFTER_DELETE, array($this, 'afterDelete')); $grid->addCallback(Am_Grid_Editable::CB_AFTER_SAVE, array($this, 'afterSave')); $grid->addCallback(Am_Grid_Editable::CB_VALUES_TO_FORM, array($this, 'valuesToForm')); return $grid; } public function renderOwner($record) { return $record->owner_id ? sprintf('%s', Am_Html::escape($record->owner)) : ''; } public function beforeSave(& $values, $record) { $values['owner_id'] = $values['owner_id'] ? $values['owner_id'] : null; } public function valuesToForm(& $ret, $record) { $ret['_access'] = $record->isLoaded() ? $this->getDi()->resourceAccessTable->getAccessList($record->pk(), HelpdeskCategory::ACCESS_TYPE) : array( ResourceAccess::FN_FREE => array( json_encode(array( 'start' => null, 'stop' => null, 'text' => ___('Free Access') )))); } public function afterSave(array & $values, $record) { $this->getDi()->resourceAccessTable->setAccess($record->pk(), HelpdeskCategory::ACCESS_TYPE, $values['_access']); } public function afterDelete($record) { $this->getDi()->resourceAccessTable->clearAccess($record->pk(), HelpdeskCategory::ACCESS_TYPE); } }controllers/AdminController.php000064400000002733152101601110012710 0ustar00hasPermission(Bootstrap_Helpdesk::ADMIN_PERM_ID); } function preDispatch() { $this->view->headLink()->appendStylesheet($this->view->_scriptCss('helpdesk-admin.css')); $this->setActiveMenu('helpdesk-ticket'); parent::preDispatch(); } public function initPages() { $this->addPage('Am_Helpdesk_Grid_Admin_Dashboard', 'index', ___('Tickets')) ->addPage(array($this, 'createController'), 'view', ___('Conversation')); } public function renderTabs() { return ''; } public function createController($id, $title, $grid) { return new Am_Helpdesk_Controller($grid->getRequest(), $grid->getResponse(), $this->_invokeArgs); } public function archiveAction() { $grid = new Am_Helpdesk_Grid_Admin_Archive($this->getRequest(), $this->view); $grid->runWithLayout('admin/layout.phtml'); } }controllers/AdminUserController.php000064400000004230152101601110013541 0ustar00user_id = $this->getCompleteRequest()->get('user_id', 0); if ($this->user_id) { $this->getDataSource()->getDataSourceQuery()->addWhere('t.user_id=?d', $this->user_id); } } public function initActions() { parent::initActions(); $this->actionAdd(new Am_Grid_Action_Ticket()); } } class Helpdesk_AdminUserController extends Am_Mvc_Controller_Pages { protected $layout = 'admin/user-layout.phtml'; public function checkAdminPermissions(Admin $admin) { return $admin->hasPermission(Bootstrap_Helpdesk::ADMIN_PERM_ID); } function preDispatch() { $this->getDi()->navigationUserTabs->setActive('helpdesk'); $this->getDi()->helpdeskStrategy->setUserId( $this->getRequest()->getParam('user_id', 0) ); $this->view->headLink()->appendStylesheet($this->view->_scriptCss('helpdesk-admin.css')); $this->setActiveMenu('users-browse'); parent::preDispatch(); } public function initPages() { $this->addPage('Am_Helpdesk_Grid_UserTab', 'index', ___('Tickets')) ->addPage(array($this, 'createController'), 'view', ___('Conversation')); } public function renderTabs() { return ''; } public function createController($id, $title, $grid) { return new Am_Helpdesk_Controller($grid->getRequest(), $grid->getResponse(), $this->_invokeArgs); } }controllers/IndexController.php000064400000006166152101601110012733 0ustar00addCallback(Am_Grid_ReadOnly::CB_TR_ATTRIBS, function(&$attrs, $r){ if ($r->has_new) { $attrs['class'] = isset($attrs['class']) ? $attrs['class'] . ' emphase' : 'emphase'; } }); $uid = $this->getDi()->auth->getUserId(); if ($this->getDi()->helpdeskTicketTable->countByUserId($uid) < 10) { $this->addCallback(Am_Grid_ReadOnly::CB_RENDER_CONTENT, function(&$out, $g){ $out = preg_replace('/.*?/is', '', $out); }); } parent::init(); } public function initGridFields() { $this->addField(new Am_Grid_Field('subject', ___('Subject'), true, '', array($this, 'renderSubject'))); $this->addField(new Am_Grid_Field('updated', ___('Updated'), true, '', array($this, 'renderTime'))); $this->addField(new Am_Grid_Field('ticket_mask', '#', true)); $this->addField(new Am_Grid_Field('status', ___('Status'), true, '', array($this, 'renderStatus'), '1%')); $this->addCallback(Am_Grid_ReadOnly::CB_TR_ATTRIBS, array($this, 'cbGetTrAttribs')); } protected function createFilter() { return new Am_Grid_Filter_Helpdesk; } public function getStatusIconId($id, $record) { return $id == 'awaiting' && $record->status == HelpdeskTicket::STATUS_AWAITING_USER_RESPONSE ? $id . '-me' : $id; } protected function isNotImportant($record) { return $record->status == HelpdeskTicket::STATUS_CLOSED; } public function initActions() { parent::initActions(); $this->actionAdd(new Am_Grid_Action_Ticket()); } public function createDs() { $query = parent::createDS(); $query->addWhere('t.user_id=?', Am_Di::getInstance()->auth->getUserId() ); return $query; } } class Helpdesk_IndexController extends Am_Mvc_Controller_Pages { protected $layout = 'member/layout.phtml'; function preDispatch() { $this->getDi()->auth->requireLogin($this->getDi()->url('helpdesk',null,false,2)); $this->view->headLink()->appendStylesheet($this->view->_scriptCss('helpdesk-user.css')); $this->view->headScript()->appendFile($this->view->_scriptJs('jquery/jquery.form.js')); if ($page = $this->getDi()->navigationUser->findOneBy('id', 'helpdesk')) { $page->setActive(true); } parent::preDispatch(); } public function initPages() { $this->addPage('Am_Helpdesk_Grid_User', 'index', ___('Tickets')) ->addPage(array($this, 'createController'), 'view', ___('Conversation')); } public function renderTabs() { $intro = $this->getDi()->config->get('helpdesk.intro'); return $intro ? sprintf('
%s
', $intro) : ''; } public function createController($id, $title, $grid) { return new Am_Helpdesk_Controller($grid->getRequest(), $grid->getResponse(), $this->_invokeArgs); } }views/helpdesk/_message.phtml000064400000007647152101601110012333 0ustar00isMessageAvalable($message)) : ?> loadGetAttachments(); ?>
name;}, $uploads))); ?>" src="_scriptImg('attachment.png')) ?>" />
isShowAvatar()) :?>
getAvatar($message); ?>
getName($message)) ?> · , content))), 0, 120)) ?>…
hyperlinks($this->skip($message->content)) ?>
    loadGetAttachments() as $upload) : ?>
  • name) ?> (getSizeReadable()) ?>)
canEditMessage($message)) : ?>
isMessageForReply($message) && $strategy->canEditTicket($ticket)) : ?>
_script($strategy->getTemplatePath() . '/_reply-panel.phtml'); ?>
views/helpdesk/_reply-panel.phtml000064400000001360152101601110013121 0ustar00
canUseSnippets() || $strategy->canUseFaq()) : ?>
canUseSnippets()): ?>
canUseFaq()): ?>
views/helpdesk/faq.phtml000064400000002117152101601110011302 0ustar00setLayout('member/layout.phtml'); /* @var $di Am_Di */ $di; ?> modules->get('helpdesk')->getConfig('show_faq_search')) : ?> render('helpdesk/_search-form.phtml') ?>
views/helpdesk/_search-result.phtml000064400000000723152101601110013454 0ustar00views/helpdesk/faq-item.phtml000064400000000130152101601110012227 0ustar00title; $this->setLayout('member/layout.phtml'); echo $faq->content;views/helpdesk/_suggest.phtml000064400000000561152101601110012354 0ustar00 views/helpdesk/index.phtml000064400000000166152101601110011644 0ustar00layoutNoTitle = true; if ($this->switchLayout) { $this->setLayout($this->switchLayout); } echo @$content;views/helpdesk/_select-status-form.phtml000064400000001177152101601110014440 0ustar00
formSelect('status', $ticket->status, null, HelpdeskTicket::getStatusOptions()) ?>
views/helpdesk/_search-form.phtml000064400000001775152101601110013111 0ustar00
views/helpdesk/ticket.phtml000064400000047343152101601110012030 0ustar00modules->loadGet('helpdesk')->getConfig('live'); ?>

subject) ?> #ticket_mask) ?> · title) ?>

isLocked($di->authAdmin->getUser())) : ?>
  • lock_admin); ?>
_script($strategy->getTemplatePath() . '/_history.phtml'); ?> comment) : ?>
comment) ?>
    $field) : ?> helpdeskGetTicketField($ticket, $fn)) : ?>
  • title) ?>:
_script($strategy->getTemplatePath() . '/_select-status-form.phtml'); } ?>
: created)) ?> owner_id && $strategy->canViewOwner($ticket)) : ?> getOwner() ?> : name_f || $owner->name_l) : ?> login) ?> (name_f $owner->name_l")) ?>) login) ?>
canEditTicket($ticket)) : ?>
status == HelpdeskTicket::STATUS_CLOSED) : ?>
canEditOwner($ticket)) : ?> owner_id && $ticket->owner_id == $di->authAdmin->getUserId()) : ?>
owner_id): ?>
canEditWatcher($ticket)) : ?>
canEditCategory($ticket) && $di->helpdeskCategoryTable->getOptions(true)) : ?>
_script($strategy->getTemplatePath() . '/_reply-panel.phtml'); ?>
getMessages() as $message) { if (!$js_added && $isLive) { $js = json_encode($strategy->newUrl() . '?' . http_build_query(array( 'id' => $this->obfuscate($message->pk()) ))); $this->placeholder("head-finish")->append(<< jQuery(function(){ amHelpdeskUpdate($js); }); CUT ); $js_added = true; } include $this->_script($strategy->getTemplatePath() . '/_message.phtml'); } ?>
views/public/css/helpdesk-user.css000064400000013251152101601110013222 0ustar00/* Helpdesk FAQ */ .am-helpdesk-faq-list { margin-left: 2em; } .am-helpdesk-faq-list .am-helpdesk-faq-list-item { list-style: decimal; padding-bottom: 0.5em; } .am-helpdesk-faq-search-result { padding-top: 1em; } /* Helpdesk */ .am-helpdesk { width: 100%; display: inline-block; text-align: left; margin-top: 0.5em; } .am-helpdesk h3 { text-align: left; padding-top: 0; margin-top: 0; } /* Ticket */ .am-helpdesk-ticket { margin-bottom: 0.5em; } .am-helpdesk-ticket .am-helpdesk-ticket-info { padding: 0.4em 0; } .am-helpdesk-ticket-header { overflow: hidden; } .am-helpdesk-ticket-status { float: right; } .am-helpdesk-ticket-actions-conteiner { overflow: hidden; -moz-border-radius: 3px; -webkit-border-radius: 3px; border-radius: 3px; border: #ccc 1px solid; margin-top: 0.5em; } .am-helpdesk-ticket-actions { overflow: hidden; } .am-helpdesk-ticket-action { display: inline-block; padding: 0.5em; -moz-border-radius: 3px 3px 0 0; -webkit-border-radius: 3px 3px 0 0; border-radius: 3px 3px 0 0; } .am-helpdesk-ticket-action.am-helpdesk-action-active { background-color: #dbdbdb; } .am-helpdesk-ticket-action-fold-all { padding-left: 0.5em; line-height: 0.6em; font-size: 1.3em; float: right; } .am-helpdesk-ticket-action-fold-all a { text-decoration: none; } .am-helpdesk-ticket-fields { padding-bottom: 0.5em; } /* Reply Panel */ .am-helpdesk-reply-panel { padding: 0.5em; background: #dbdbdb; display: none; -moz-border-radius: 0 0 3px 3px; -webkit-border-radius: 0 0 3px 3px; border-radius: 0 0 3px 3px; } .am-helpdesk-reply-panel-tools { overflow: hidden; padding: 0.5em 0; } .am-helpdesk-reply-panel-tool { float: left; padding-right: 0.5em; } .am-helpdesk-reply-panel-content .am-form div.row.no-label .element { padding: 0 0 0.5em; } .am-helpdesk-reply-panel-content .am-form div.row.no-label .element textarea { font-family: monospace; line-height: 140%; resize: vertical; border: none; padding: 1em; } .am-helpdesk-reply-panel-content .am-form div.row.no-label .element textarea:focus { background: white; border: none; } .am-helpdesk-reply-panel-content .am-form { margin: 0; } .am-helpdesk-reply-panel-content .am-form form { background: none; border: 0; box-shadow: none; } .am-helpdesk-reply-panel-content .am-form div.row { border: 0; } .am-helpdesk-reply-panel-content .am-form .element-title, .am-helpdesk-reply-panel-content .am-form .element { padding-top: 0.4em; padding-bottom: 0.4em; } .am-helpdesk-reply-panel-content .am-form #row-attachments-0 { display: none; } .am-helpdesk-form #row-attachments-0 { display: none; } /* Message */ .am-helpdesk-message { margin-bottom: 0.5em; border-radius: 3px; border: #dbdbdb 1px solid; } .am-helpdesk-message.am-helpdesk-message-inbound { background: #fff9ea; } .am-helpdesk-message.am-helpdesk-message-outbound { background: #fff; } .am-helpdesk-message.am-helpdesk-message-comment { background: #e8f5e9; } .am-helpdesk-message-brief { display: none; } .am-helpdesk-message-has-attachments { float: right; } .am-helpdesk-message-closed .am-helpdesk-message-brief { display: inline; } .am-helpdesk-message-closed .am-helpdesk-message-full { display: none; } .am-helpdesk-message-closed .am-helpdesk-message-header { opacity: 1; } .am-helpdesk-message-outbound.am-helpdesk-message-closed .am-helpdesk-message-header { -moz-border-radius: 3px; -webkit-border-radius: 3px; border-radius: 3px; } .am-helpdesk-message-header { -moz-border-radius: 3px 3px 0 0; -webkit-border-radius: 3px 3px 0 0; border-radius: 3px 3px 0 0; padding: 0.5em; margin: 0; overflow: hidden; opacity: 0.8; } .am-helpdesk-message-author { font-weight: bold; } .am-helpdesk-message-author-avatar { float: left; width: 40px; height: 40px; overflow: hidden; border-radius: 50%; margin-right: 1em; } .am-helpdesk-message-content { padding: 0.5em; margin: 0; } .am-helpdesk-message-content pre { color: #4d4948; margin: 0; white-space: pre-wrap; word-wrap: break-word; line-height: 150%; font-family: monospace; font-size: 12px; } .am-helpdesk ul.am-helpdesk-message-attachments { margin: 0.5em 0 0; } .am-helpdesk ul.am-helpdesk-message-attachments li.am-helpdesk-message-attachments-item { list-style-type: none; } .am-helpdesk ul.am-helpdesk-message-attachments li.am-helpdesk-message-attachments-item:before { content: "\2013\00a0"; } .am-helpdesk-message-action { display: inline-block; padding: 0.5em; -moz-border-radius: 3px 3px 0 0; -webkit-border-radius: 3px 3px 0 0; border-radius: 3px 3px 0 0; } .am-helpdesk-message-action.am-helpdesk-action-active { background-color: #dbdbdb; } .am-helpdesk-message-action-fold { padding-left: 0.5em; line-height: 0.6em; font-size: 1.3em; float: right; } .am-helpdesk-message-action-fold a { text-decoration: none; } /* History */ .am-helpdesk-history { border-bottom: 1px solid #a1a1a1; margin-bottom: 0.5em; } .am-helpdesk-history h1 { font-size: 1.4rem; margin-bottom: 0.5em; } .am-helpdesk-history-content { display: none; border-top: 1px solid #a1a1a1; padding-top: 0.5em; } .am-helpdesk-history-title { overflow: hidden; margin-bottom: 0.5em; } .am-helpdesk-history-title-action { float: right; } .am-helpdesk-history-title-action a { display: block; padding-right: 10px; background: url("../img/arrow.png") no-repeat center right; } ul.am-helpdesk-faq-cat .am-helpdesk-faq-cat-item { list-style-type: none; } .am-helpdesk-grid-msg-cnt { background: #babec0; color: white; padding: 1px 4px; font-size: 10px; line-height: 1; text-transform: uppercase; border-radius: 6px; } .am-helpdesk-grid-msg { color: #888; } views/public/css/helpdesk-admin.css000064400000012712152101601110013335 0ustar00/* Helpdesk */ .am-helpdesk { width: 100%; display: inline-block; text-align: left; margin-top: 0.5em; } .am-helpdesk h3 { text-align: left; padding-top: 0; margin-top: 0; } /* Ticket */ .am-helpdesk-ticket { margin-bottom: 0.5em; } .am-helpdesk-ticket .am-helpdesk-ticket-info { padding: 0.4em 0; } .am-helpdesk-ticket-header { overflow: hidden; } .am-helpdesk-ticket-status { float: right; } .am-helpdesk-ticket-actions-conteiner { overflow: hidden; -moz-border-radius: 3px; -webkit-border-radius: 3px; border-radius: 3px; border: #ccc 1px solid; margin-top: 0.5em; } .am-helpdesk-ticket-actions { overflow: hidden; } .am-helpdesk-ticket-action { display: inline-block; padding: 0.5em; -moz-border-radius: 3px 3px 0 0; -webkit-border-radius: 3px 3px 0 0; border-radius: 3px 3px 0 0; } .am-helpdesk-ticket-action.am-helpdesk-action-active { background-color: #dbdbdb; } .am-helpdesk-ticket-action-fold-all { padding-left: 0.5em; line-height: 0.6em; font-size: 1.3em; float: right; } .am-helpdesk-ticket-action-fold-all a { text-decoration: none; } .am-helpdesk-ticket-fields { padding-bottom: 0.5em; } /* Reply Panel */ .am-helpdesk-reply-panel { padding: 0.5em; background: #dbdbdb; display: none; -moz-border-radius: 0 0 3px 3px; -webkit-border-radius: 0 0 3px 3px; border-radius: 0 0 3px 3px; } .am-helpdesk-reply-panel-tools { overflow: hidden; padding: 0.5em 0; } .am-helpdesk-reply-panel-tool { float: left; padding-right: 0.5em; } .am-helpdesk-reply-panel-content .am-form div.row.no-label .element { padding: 0 0 0.5em; } .am-helpdesk-reply-panel-content .am-form div.row.no-label .element textarea { font-family: monospace; line-height: 140%; resize: vertical; border: none; padding: 1em; } .am-helpdesk-reply-panel-content .am-form div.row.no-label .element textarea:focus { background: white; border: none; } .am-helpdesk-reply-panel-content .am-form { margin: 0; } .am-helpdesk-reply-panel-content .am-form form { background: none; border: 0; box-shadow: none; } .am-helpdesk-reply-panel-content .am-form div.row { border: 0; } .am-helpdesk-reply-panel-content .am-form .element-title, .am-helpdesk-reply-panel-content .am-form .element { padding-top: 0.4em; padding-bottom: 0.4em; } .am-helpdesk-reply-panel-content .am-form #row-attachments-0 { display: none; } .am-helpdesk-form #row-attachments-0 { display: none; } /* Message */ .am-helpdesk-message { margin-bottom: 0.5em; border-radius: 3px; border: #dbdbdb 1px solid; } .am-helpdesk-message.am-helpdesk-message-inbound { background: #fff9ea; } .am-helpdesk-message.am-helpdesk-message-outbound { background: #fff; } .am-helpdesk-message.am-helpdesk-message-comment { background: #e8f5e9; } .am-helpdesk-message-brief { display: none; } .am-helpdesk-message-has-attachments { float: right; } .am-helpdesk-message-closed .am-helpdesk-message-brief { display: inline; } .am-helpdesk-message-closed .am-helpdesk-message-full { display: none; } .am-helpdesk-message-closed .am-helpdesk-message-header { opacity: 1; } .am-helpdesk-message-outbound.am-helpdesk-message-closed .am-helpdesk-message-header { -moz-border-radius: 3px; -webkit-border-radius: 3px; border-radius: 3px; } .am-helpdesk-message-header { -moz-border-radius: 3px 3px 0 0; -webkit-border-radius: 3px 3px 0 0; border-radius: 3px 3px 0 0; padding: 0.5em; margin: 0; overflow: hidden; opacity: 0.8; } .am-helpdesk-message-author { font-weight: bold; } .am-helpdesk-message-author-avatar { float: left; width: 40px; height: 40px; overflow: hidden; border-radius: 50%; margin-right: 1em; } .am-helpdesk-message-content { padding: 0.5em; margin: 0; } .am-helpdesk-message-content pre { color: #4d4948; margin: 0; white-space: pre-wrap; word-wrap: break-word; line-height: 150%; font-family: monospace; font-size: 12px; } .am-helpdesk ul.am-helpdesk-message-attachments { margin: 0.5em 0 0; } .am-helpdesk ul.am-helpdesk-message-attachments li.am-helpdesk-message-attachments-item { list-style-type: none; } .am-helpdesk ul.am-helpdesk-message-attachments li.am-helpdesk-message-attachments-item:before { content: "\2013\00a0"; } .am-helpdesk-message-action { display: inline-block; padding: 0.5em; -moz-border-radius: 3px 3px 0 0; -webkit-border-radius: 3px 3px 0 0; border-radius: 3px 3px 0 0; } .am-helpdesk-message-action.am-helpdesk-action-active { background-color: #dbdbdb; } .am-helpdesk-message-action-fold { padding-left: 0.5em; line-height: 0.6em; font-size: 1.3em; float: right; } .am-helpdesk-message-action-fold a { text-decoration: none; } /* History */ .am-helpdesk-history { border-bottom: 1px solid #a1a1a1; margin-bottom: 0.5em; } .am-helpdesk-history h1 { font-size: 1.4rem; margin-bottom: 0.5em; } .am-helpdesk-history-content { display: none; border-top: 1px solid #a1a1a1; padding-top: 0.5em; } .am-helpdesk-history-title { overflow: hidden; margin-bottom: 0.5em; } .am-helpdesk-history-title-action { float: right; } .am-helpdesk-history-title-action a { display: block; padding-right: 10px; background: url("../img/arrow.png") no-repeat center right; } ul.am-helpdesk-faq-cat .am-helpdesk-faq-cat-item { list-style-type: none; } .am-helpdesk-grid-msg-cnt { background: #babec0; color: white; padding: 1px 4px; font-size: 10px; line-height: 1; text-transform: uppercase; border-radius: 6px; } .am-helpdesk-grid-msg { color: #888; } views/public/img/arrow.png000064400000000122152101601110011552 0ustar00PNG  IHDRIDATxc` &LTb (AeIENDB`views/admin/helpdesk/_message.phtml000064400000007032152101601110013407 0ustar00isMessageAvalable($message)) : ?>
[]
modules->get('helpdesk')->getConfig('show_gravatar')) :?>
admin_id) { echo $strategy->getAdminGravatar($message); } else { echo $strategy->getUserGravatar($message); } ?>
admin_id) { p($strategy->getAdminName($message)); } else { p($strategy->getUserName($message)); } ?>,
hyperlinks($this->skip($message->content)) ?>
loadGetAttachments() as $upload) : ?> – name) ?> (getSizeReadable()) ?>)
type == 'comment') : ?>
isMessageForReply($message) && $strategy->canEditTicket($ticket)) : ?>
_script($strategy->getTemplatePath() . '/_reply-panel.phtml'); ?>
views/admin/helpdesk/_reply-panel.phtml000064400000001360152101601110014211 0ustar00
canUseSnippets() || $strategy->canUseFaq()) : ?>
canUseSnippets()): ?>
canUseFaq()): ?>
views/admin/helpdesk/widget/messages.phtml000064400000004653152101601110014724 0ustar00helpdeskMessageTable->selectLast($num); ?>

admin_id) : ?> a_name_f || $m->a_name_l) : ?> a_name_f) ?> a_name_l) ?> (a_login) ?>) a_login) ?> u_name_f || $m->u_name_l) : ?> u_name_f) ?> u_name_l) ?> (u_login) ?>) u_login) ?> · · subject) ?>

views/admin/helpdesk/index.phtml000064400000000166152101601110012734 0ustar00layoutNoTitle = true; if ($this->switchLayout) { $this->setLayout($this->switchLayout); } echo @$content;views/admin/helpdesk/_history.phtml000064400000001355152101601110013466 0ustar00
login) ?> getName())) : ?> (getName()) ?>) productTable->getProductTitles($user->getActiveProductIds()))) ?>
views/admin/helpdesk/_select-status-form.phtml000064400000001177152101601110015530 0ustar00
formSelect('status', $ticket->status, null, HelpdeskTicket::getStatusOptions()) ?>
views/admin/helpdesk/ticket.phtml000064400000035310152101601110013107 0ustar00layoutNoTitle = true ?>

()

isLocked($di->authAdmin->getUser())) : ?>
  • lock_admin); ?>
login) ?> (getName()) ?>)
comment) : ?>
comment) ?>
_script($strategy->getTemplatePath() . '/_select-status-form.phtml'); } ?>

subject) ?> [#ticket_mask) ?>] title) ?> created)) ?>

owner_id && $strategy->canViewOwner($ticket)) : ?> getOwner() ?>

Owner: login) ?> (name_f) ?> name_l) ?>)

canEditTicket($ticket)) : ?>
status == HelpdeskTicket::STATUS_CLOSED) : ?>
canEditOwner($ticket)) : ?> owner_id && $ticket->owner_id == $di->authAdmin->getUserId()) : ?>
owner_id): ?>
canEditCategory($ticket) && $di->helpdeskCategoryTable->getOptions(true)) : ?>
[]
_script($strategy->getTemplatePath() . '/_reply-panel.phtml'); ?>
getMessages() as $message) { include $this->_script($strategy->getTemplatePath() . '/_message.phtml'); } ?>