diff --git a/include/class.config.php b/include/class.config.php index b0373f6e9d9679b2ec93e8b8179efbdf2b2167fc..c70a21d881e65a04acd81df917ec1d1891e68d3e 100644 --- a/include/class.config.php +++ b/include/class.config.php @@ -165,6 +165,8 @@ class OsticketConfig extends Config { 'clients_only' => false, 'client_registration' => 'closed', 'accept_unregistered_email' => true, + 'default_help_topic' => 0, + 'help_topic_sort_mode' => 'a', ); function OsticketConfig($section=null) { @@ -426,6 +428,30 @@ class OsticketConfig extends Config { return $this->defaultPriority; } + function getDefaultTopicId() { + return $this->get('default_help_topic'); + } + + function getTopicSortMode() { + return $this->get('help_topic_sort_mode'); + } + + function setTopicSortMode($mode) { + $modes = static::allTopicSortModes(); + if (!isset($modes[$mode])) + throw new InvalidArgumentException($mode + .': Unsupport help topic sort mode'); + + $this->update('help_topic_sort_mode', $mode); + } + + static function allTopicSortModes() { + return array( + 'a' => 'Alphabetically', + 'm' => 'Manually', + ); + } + function getDefaultTemplateId() { return $this->get('default_template_id'); } @@ -938,6 +964,7 @@ class OsticketConfig extends Config { return $this->updateAll(array( 'random_ticket_ids'=>$vars['random_ticket_ids'], 'default_priority_id'=>$vars['default_priority_id'], + 'default_help_topic'=>$vars['default_help_topic'], 'default_sla_id'=>$vars['default_sla_id'], 'max_open_tickets'=>$vars['max_open_tickets'], 'autolock_minutes'=>$vars['autolock_minutes'], diff --git a/include/class.topic.php b/include/class.topic.php index ad3b21a416f147ba443d2417c786f1bb7c6299b2..7ef0ad412bc944d5ddf00699d4725cabe2902d59 100644 --- a/include/class.topic.php +++ b/include/class.topic.php @@ -78,6 +78,15 @@ class Topic { return $this->ht['name']; } + function getFullName() { + return self::getTopicName($this->getId()); + } + + static function getTopicName($id) { + $names = static::getHelpTopics(); + return $names[$id]; + } + function getDeptId() { return $this->ht['dept_id']; } @@ -144,6 +153,16 @@ class Topic { return $this->getHashtable(); } + function setSortOrder($i) { + if ($i != $this->ht['sort']) { + $sql = 'UPDATE '.TOPIC_TABLE.' SET `sort`='.db_input($i) + .' WHERE `topic_id`='.db_input($this->getId()); + return (db_query($sql) && db_affected_rows() == 1); + } + // Noop + return true; + } + function update($vars, &$errors) { if(!$this->save($this->getId(), $vars, $errors)) @@ -169,23 +188,39 @@ class Topic { return self::save(0, $vars, $errors); } - function getHelpTopics($publicOnly=false) { - - $topics=array(); - $sql='SELECT ht.topic_id, CONCAT_WS(" / ", ht2.topic, ht.topic) as name ' - .' FROM '.TOPIC_TABLE. ' ht ' - .' LEFT JOIN '.TOPIC_TABLE.' ht2 ON(ht2.topic_id=ht.topic_pid) ' - .' WHERE ht.isactive=1'; - - if($publicOnly) - $sql.=' AND ht.ispublic=1'; - - $sql.=' ORDER BY name'; - if(($res=db_query($sql)) && db_num_rows($res)) - while(list($id, $name)=db_fetch_row($res)) - $topics[$id]=$name; + static function getHelpTopics($publicOnly=false) { + global $cfg; + static $names; + + if ($names) return $names; + + $sql = 'SELECT topic_id, topic_pid, ispublic, topic FROM '.TOPIC_TABLE + . ' WHERE isactive=1'; + + $sql .= ' ORDER BY ' + . ($cfg->getTopicSortMode() == 'm' ? '`sort`' : '`topic_id`'); + $res = db_query($sql); + + // Fetch information for all topics, in declared sort order + $topics = array(); + while (list($id, $pid, $pub, $topic) = db_fetch_row($res)) + $topics[$id] = array('pid'=>$pid, 'public'=>$pub, + 'topic'=>$topic); + + // Resolve parent names + foreach ($topics as $id=>$info) { + if ($publicOnly && !$info['public']) + continue; + $name = $info['topic']; + while ($info['pid'] && ($info = $topics[$info['pid']])) { + $name = sprintf('%s / %s', $info['topic'], $name); + } + $names[$id] = $name; + } - return $topics; + if ($cfg->getTopicSortMode() == 'a') + uasort($names, function($a, $b) { return strcmp($a, $b); }); + return $names; } function getPublicHelpTopics() { @@ -203,7 +238,7 @@ class Topic { return $id; } - function lookup($id) { + static function lookup($id) { return ($id && is_numeric($id) && ($t= new Topic($id)) && $t->getId()==$id)?$t:null; } diff --git a/include/client/open.inc.php b/include/client/open.inc.php index 26b6d30edf9ab857dd1fb5b25f63bcfbc5a22c3e..415eacabc5fda233296723eea60a538b67d88bbf 100644 --- a/include/client/open.inc.php +++ b/include/client/open.inc.php @@ -10,6 +10,9 @@ if($thisclient && $thisclient->isValid()) { $info=($_POST && $errors)?Format::htmlchars($_POST):$info; $form = null; +if (!$info['topicId']) + $info['topicId'] = $cfg->getDefaultTopicId(); + if ($info['topicId'] && ($topic=Topic::lookup($info['topicId']))) { $form = $topic->getForm(); if ($_POST && $form) { diff --git a/include/staff/email.inc.php b/include/staff/email.inc.php index e8d3a430e74c3f66a40dc374c1974b2dd3a9fa6d..acfcb4c64aff9ce23eb31d61e998aa7ef5766bcd 100644 --- a/include/staff/email.inc.php +++ b/include/staff/email.inc.php @@ -129,14 +129,11 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info); <select name="topic_id"> <option value="0" selected="selected">— None —</option> <?php - $sql='SELECT topic_id, topic FROM '.TOPIC_TABLE.' T ORDER by topic'; - if(($res=db_query($sql)) && db_num_rows($res)){ - while(list($id,$name)=db_fetch_row($res)){ - $selected=($info['topic_id'] && $id==$info['topic_id'])?'selected="selected"':''; - echo sprintf('<option value="%d" %s>%s</option>',$id,$selected,$name); - } - } - ?> + $topics = Topic::getHelpTopics(); + while (list($id,$topic) = each($topics)) { ?> + <option value="<?php echo $id; ?>"<?php echo ($info['topic_id']==$id)?'selected':''; ?>><?php echo $topic; ?></option> + <?php + } ?> </select> <i class="help-tip icon-question-sign" href="#new_ticket_help_topic"></i> </span> diff --git a/include/staff/helptopics.inc.php b/include/staff/helptopics.inc.php index 8395a29e3d723ed881405cfb8d06f96bbad728bc..3a4a9f760d80665c4d565647cf0111b9952d17af 100644 --- a/include/staff/helptopics.inc.php +++ b/include/staff/helptopics.inc.php @@ -1,7 +1,6 @@ <?php if(!defined('OSTADMININC') || !$thisstaff->isAdmin()) die('Access Denied'); -$qstr=''; $sql='SELECT topic.* ' .', IF(ptopic.topic_pid IS NULL, topic.topic, CONCAT_WS(" / ", ptopic.topic, topic.topic)) as name ' .', dept.dept_name as department ' @@ -11,34 +10,13 @@ $sql='SELECT topic.* ' .' LEFT JOIN '.DEPT_TABLE.' dept ON (dept.dept_id=topic.dept_id) ' .' LEFT JOIN '.TICKET_PRIORITY_TABLE.' pri ON (pri.priority_id=topic.priority_id) '; $sql.=' WHERE 1'; -$sortOptions=array('name'=>'name','status'=>'topic.isactive','type'=>'topic.ispublic', - 'dept'=>'department','priority'=>'priority','updated'=>'topic.updated'); -$orderWays=array('DESC'=>'DESC','ASC'=>'ASC'); -$sort=($_REQUEST['sort'] && $sortOptions[strtolower($_REQUEST['sort'])])?strtolower($_REQUEST['sort']):'name'; -//Sorting options... -if($sort && $sortOptions[$sort]) { - $order_column =$sortOptions[$sort]; -} -$order_column=$order_column?$order_column:'topic.topic'; - -if($_REQUEST['order'] && $orderWays[strtoupper($_REQUEST['order'])]) { - $order=$orderWays[strtoupper($_REQUEST['order'])]; -} -$order=$order?$order:'ASC'; - -if($order_column && strpos($order_column,',')){ - $order_column=str_replace(','," $order,",$order_column); -} -$x=$sort.'_sort'; -$$x=' class="'.strtolower($order).'" '; -$order_by="$order_column $order "; +$order_by = ($cfg->getTopicSortMode() == 'm' ? '`sort`' : '`name`'); $total=db_count('SELECT count(*) FROM '.TOPIC_TABLE.' topic '); $page=($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1; $pageNav=new Pagenate($total, $page, PAGE_LIMIT); -$pageNav->setURL('helptopics.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&order='.urlencode($_REQUEST['order'])); +$pageNav->setURL('helptopics.php'); //Ok..lets roll...create the actual query -$qstr.='&order='.($order=='DESC'?'ASC':'DESC'); $query="$sql GROUP BY topic.topic_id ORDER BY $order_by LIMIT ".$pageNav->getStart().",".$pageNav->getLimit(); $res=db_query($query); if($res && ($num=db_num_rows($res))) @@ -53,31 +31,43 @@ else <div style="float:right;text-align:right;padding-top:5px;padding-right:5px;"> <b><a href="helptopics.php?a=add" class="Icon newHelpTopic">Add New Help Topic</a></b></div> <div class="clear"></div> -<form action="helptopics.php" method="POST" name="topics"> +<form id="save" action="helptopics.php" method="POST" name="topics"> <?php csrf_token(); ?> <input type="hidden" name="do" value="mass_process" > -<input type="hidden" id="action" name="a" value="" > +<input type="hidden" id="action" name="a" value="sort" > <table class="list" border="0" cellspacing="1" cellpadding="0" width="940"> - <caption><?php echo $showing; ?></caption> + <caption><span style="display:inline-block;vertical-align:middle"><?php + echo $showing; ?></span> + <div class="pull-right">Sorting Mode: + <select name="help_topic_sort_mode"> +<?php foreach (OsticketConfig::allTopicSortModes() as $i=>$m) + echo sprintf('<option value="%s"%s>%s</option>', + $i, $i == $cfg->getTopicSortMode() ? ' selected="selected"' : '', $m); ?> + </select> + </div> + </caption> <thead> <tr> - <th width="7"> </th> - <th width="320"><a <?php echo $name_sort; ?> href="helptopics.php?<?php echo $qstr; ?>&sort=name">Help Topic</a></th> - <th width="80"><a <?php echo $status_sort; ?> href="helptopics.php?<?php echo $qstr; ?>&sort=status">Status</a></th> - <th width="100"><a <?php echo $type_sort; ?> href="helptopics.php?<?php echo $qstr; ?>&sort=type">Type</a></th> - <th width="100"><a <?php echo $priority_sort; ?> href="helptopics.php?<?php echo $qstr; ?>&sort=priority">Priority</a></th> - <th width="200"><a <?php echo $dept_sort; ?> href="helptopics.php?<?php echo $qstr; ?>&sort=dept">Department</a></th> - <th width="150" nowrap><a <?php echo $updated_sort; ?>href="helptopics.php?<?php echo $qstr; ?>&sort=updated">Last Updated</a></th> + <th width="7" style="height:20px;"> </th> + <th style="padding-left:4px;vertical-align:middle" width="320">Help Topic</th> + <th style="padding-left:4px;vertical-align:middle" width="80">Status</th> + <th style="padding-left:4px;vertical-align:middle" width="100">Type</th> + <th style="padding-left:4px;vertical-align:middle" width="100">Priority</th> + <th style="padding-left:4px;vertical-align:middle" width="200">Department</th> + <th style="padding-left:4px;vertical-align:middle" width="150" nowrap>Last Updated</th> </tr> </thead> - <tbody> + <tbody class="<?php if ($cfg->getTopicSortMode() == 'm') echo 'sortable-rows'; ?>" + data-sort="sort-"> <?php $total=0; $ids=($errors && is_array($_POST['ids']))?$_POST['ids']:null; if($res && db_num_rows($res)): $defaultDept = $cfg->getDefaultDept(); $defaultPriority = $cfg->getDefaultPriority(); + $sort = 0; while ($row = db_fetch_array($res)) { + $sort++; // Track initial order for transition $sel=false; if($ids && in_array($row['topic_id'],$ids)) $sel=true; @@ -93,6 +83,8 @@ else ?> <tr id="<?php echo $row['topic_id']; ?>"> <td width=7px> + <input type="hidden" name="sort-<?php echo $row['topic_id']; ?>" value="<?php + echo $row['sort'] ?: $sort; ?>"/> <input type="checkbox" class="ckb" name="ids[]" value="<?php echo $row['topic_id']; ?>" <?php echo $sel?'checked="checked"':''; ?>> </td> @@ -126,6 +118,7 @@ if($res && $num): //Show options.. echo '<div> Page:'.$pageNav->getPageLinks().' </div>'; ?> <p class="centered" id="actions"> + <input type="submit" name="submit" value="Save"> <input class="button" type="submit" name="enable" value="Enable" > <input class="button" type="submit" name="disable" value="Disable"> <input class="button" type="submit" name="delete" value="Delete"> diff --git a/include/staff/settings-tickets.inc.php b/include/staff/settings-tickets.inc.php index 37bc2af8561a8e12252dca25e9ef10f1167e3c7e..3be8dd7d6f1b5afb3a6ac2b8fa3c3cf14dffe516 100644 --- a/include/staff/settings-tickets.inc.php +++ b/include/staff/settings-tickets.inc.php @@ -63,6 +63,19 @@ if(!($maxfileuploads=ini_get('max_file_uploads'))) <span class="error">* <?php echo $errors['default_priority_id']; ?></span> <i class="help-tip icon-question-sign" href="#default_priority"></i> </td> </tr> + <tr> + <td width="180">Default Help Topic:</td> + <td> + <select name="default_help_topic"> + <option value="0">— None —</option><?php + $topics = Topic::getHelpTopics(); + while (list($id,$topic) = each($topics)) { ?> + <option value="<?php echo $id; ?>"<?php echo ($config['default_help_topic']==$id)?'selected':''; ?>><?php echo $topic; ?></option> + <?php + } ?> + </select> + </td> + </tr> <tr> <td>Maximum <b>Open</b> Tickets:</td> <td> @@ -88,7 +101,7 @@ if(!($maxfileuploads=ini_get('max_file_uploads'))) <td>Claim on Response:</td> <td> <input type="checkbox" name="auto_claim_tickets" <?php echo $config['auto_claim_tickets']?'checked="checked"':''; ?>> - Enable <i class="help-tip icon-question-sign" href="#claim_tickets"></i> + Enable <i class="help-tip icon-question-sign" href="#claim_tickets"></i> </td> </tr> <tr> diff --git a/include/staff/ticket-open.inc.php b/include/staff/ticket-open.inc.php index d14f7e98e393e6ed10d5a03c9ce5523e8fdbe6a8..f9a3ad3c161ab14730b4814ae1ae93433e9150bb 100644 --- a/include/staff/ticket-open.inc.php +++ b/include/staff/ticket-open.inc.php @@ -3,6 +3,9 @@ if(!defined('OSTSCPINC') || !$thisstaff || !$thisstaff->canCreateTickets()) die( $info=array(); $info=Format::htmlchars(($errors && $_POST)?$_POST:$info); +if (!$info['topicId']) + $info['topicId'] = $cfg->getDefaultTopicId(); + $form = null; if ($info['topicId'] && ($topic=Topic::lookup($info['topicId']))) { $form = $topic->getForm(); diff --git a/scp/helptopics.php b/scp/helptopics.php index 0847257cfc0d3da5c7d95a79773f0d34062c0b33..1b4eff07e2e7075e4585b76a8b83161a7da319c3 100644 --- a/scp/helptopics.php +++ b/scp/helptopics.php @@ -41,9 +41,15 @@ if($_POST){ } break; case 'mass_process': - if(!$_POST['ids'] || !is_array($_POST['ids']) || !count($_POST['ids'])) { - $errors['err'] = 'You must select at least one help topic'; - } else { + switch(strtolower($_POST['a'])) { + case 'sort': + // Pass + break; + default: + if(!$_POST['ids'] || !is_array($_POST['ids']) || !count($_POST['ids'])) + $errors['err'] = 'You must select at least one help topic'; + } + if (!$errors) { $count=count($_POST['ids']); switch(strtolower($_POST['a'])) { @@ -86,6 +92,23 @@ if($_POST){ elseif(!$errors['err']) $errors['err'] = 'Unable to delete selected help topics'; + break; + case 'sort': + try { + $cfg->setTopicSortMode($_POST['help_topic_sort_mode']); + if ($cfg->getTopicSortMode() == 'm') { + foreach ($_POST as $k=>$v) { + if (strpos($k, 'sort-') === 0 + && is_numeric($v) + && $t = Topic::lookup(substr($k, 5))) + $t->setSortOrder($v); + } + } + $msg = 'Successfully set sorting configuration'; + } + catch (Exception $ex) { + $errors['err'] = 'Unable to set sorting mode'; + } break; default: $errors['err']='Unknown action - get technical help.'; diff --git a/scp/js/scp.js b/scp/js/scp.js index b2e0ba77b9a9a1d95555194884d08441b86f3d1a..8559f909e587a05c443a7cf300636cc1a93aeb9e 100644 --- a/scp/js/scp.js +++ b/scp/js/scp.js @@ -137,7 +137,7 @@ var scp_prep = function() { var fObj = el.closest('form'); if(!fObj.data('changed')){ fObj.data('changed', true); - $('input[type=submit]', fObj).css('color', 'red'); + $('input[type=submit][name="submit"]', fObj).css('color', 'red'); $(window).bind('beforeunload', function(e) { return 'Are you sure you want to leave? Any changes or info you\'ve entered will be discarded!'; }); @@ -437,6 +437,7 @@ var scp_prep = function() { // Sortable tables for dynamic forms objects $('.sortable-rows').sortable({ 'helper': fixHelper, + 'cursor': 'move', 'stop': function(e, ui) { var attr = ui.item.parent('tbody').data('sort'); warnOnLeave(ui.item);