diff --git a/include/class.dept.php b/include/class.dept.php index 9687f1977a14ae8a9b2c4c7279de619fdc557666..9c0b9564b55c499fba0399ac65b2f75295939171 100644 --- a/include/class.dept.php +++ b/include/class.dept.php @@ -62,11 +62,14 @@ implements TemplateVariable, Searchable { var $autorespEmail; const ALERTS_DISABLED = 2; + const DISPLAY_DISABLED = 2; const ALERTS_DEPT_AND_EXTENDED = 1; const ALERTS_DEPT_ONLY = 0; const FLAG_ASSIGN_MEMBERS_ONLY = 0x0001; const FLAG_DISABLE_AUTO_CLAIM = 0x0002; + const FLAG_ACTIVE = 0x0004; + const FLAG_ARCHIVED = 0x0008; function asVar() { return $this->getName(); @@ -144,6 +147,45 @@ implements TemplateVariable, Searchable { return self::getNameById($this->getId()); } + function getStatus() { + if($this->flags & self::FLAG_ACTIVE) + return __('Active'); + elseif($this->flags & self::FLAG_ARCHIVED) + return __('Archived'); + else + return __('Disabled'); + } + + function allowsReopen() { + return !($this->flags & self::FLAG_ARCHIVED); + } + + function isActive() { + return !!($this->flags & self::FLAG_ACTIVE); + } + + function clearInactiveDept($dept_id) { + global $cfg; + + $topics = Topic::objects()->filter(array('dept_id'=>$dept_id))->values_flat('topic_id'); + if ($topics) { + foreach ($topics as $topic_id) { + $topic = Topic::lookup($topic_id[0]); + $topic->dept_id = $cfg->getDefaultDeptId(); + $topic->save(); + } + } + + $emails = Email::objects()->filter(array('dept_id'=>$dept_id))->values_flat('email_id'); + if ($emails) { + foreach ($emails as $email_id) { + $email = Email::lookup($email_id[0]); + $email->dept_id = $cfg->getDefaultDeptId(); + $email->save(); + } + } + } + function getEmailId() { return $this->email_id; } @@ -377,6 +419,7 @@ implements TemplateVariable, Searchable { $ht['assign_members_only'] = $this->assignMembersOnly(); $ht['disable_auto_claim'] = $this->disableAutoClaim(); + $ht['status'] = $this->getStatus(); return $ht; } @@ -481,7 +524,7 @@ implements TemplateVariable, Searchable { * */ - private function setFlag($flag, $val) { + public function setFlag($flag, $val) { if ($val) $this->flags |= $flag; @@ -511,7 +554,7 @@ implements TemplateVariable, Searchable { } function getNameById($id) { - $names = static::getDepartments(); + $names = Dept::getDepartments(); return $names[$id]; } @@ -525,8 +568,8 @@ implements TemplateVariable, Searchable { : null; } - static function getDepartments( $criteria=null, $localize=true) { - static $depts = null; + static function getDepartments($criteria=null, $localize=true, $disabled=true) { + $depts = null; if (!isset($depts) || $criteria) { // XXX: This will upset the static $depts array @@ -534,7 +577,7 @@ implements TemplateVariable, Searchable { $query = self::objects(); if (isset($criteria['publiconly'])) $query->filter(array( - 'ispublic' => ($criteria['publiconly'] ? 1 : 0))); + 'flags__hasbit' => Dept::FLAG_ACTIVE)); if ($manager=$criteria['manager']) $query->filter(array( @@ -549,10 +592,14 @@ implements TemplateVariable, Searchable { } $query->order_by('name') - ->values('id', 'pid', 'name', 'parent'); + ->values('id', 'pid', 'flags', 'name', 'parent'); + + foreach ($query as $row) { + $display = ($row['flags'] & self::FLAG_ACTIVE); - foreach ($query as $row) - $depts[$row['id']] = $row; + $depts[$row['id']] = array('id' => $row['id'], 'pid'=>$row['pid'], 'name'=>$row['name'], + 'parent'=>$row['parent'], 'disabled' => !$display); + } $localize_this = function($id, $default) use ($localize) { if (!$localize) @@ -579,21 +626,32 @@ implements TemplateVariable, Searchable { // Fetch local names $names[$id] = $localize_this($id, $name); } - asort($names); - // TODO: Use locale-aware sorting mechanism + // Apply requested filters + $requested_names = array(); + foreach ($names as $id=>$n) { + $info = $depts[$id]; + if (!$disabled && $info['disabled']) + continue; + if ($disabled === self::DISPLAY_DISABLED && $info['disabled']) + $n .= " - ".__("(disabled)"); + + $requested_names[$id] = $n; + } + asort($requested_names); + // TODO: Use locale-aware sorting mechanism if ($criteria) - return $names; + return $requested_names; - $depts = $names; + $depts = $requested_names; } - return $depts; + return $requested_names; } static function getPublicDepartments() { - static $depts =null; + $depts =null; if (!$depts) $depts = self::getDepartments(array('publiconly'=>true)); @@ -645,6 +703,10 @@ implements TemplateVariable, Searchable { if ($vars['pid'] && !($p = static::lookup($vars['pid']))) $errors['pid'] = __('Department selection is required'); + $dept = Dept::lookup($vars['pid']); + if($dept && !$dept->isActive()) + $errors['dept_id'] = sprintf(__('%s selected must be active'), __('Parent Department')); + // Format access update as [array(dept_id, role_id, alerts?)] $access = array(); if (isset($vars['members'])) { @@ -670,10 +732,33 @@ implements TemplateVariable, Searchable { $this->group_membership = $vars['group_membership']; $this->ticket_auto_response = isset($vars['ticket_auto_response'])?$vars['ticket_auto_response']:1; $this->message_auto_response = isset($vars['message_auto_response'])?$vars['message_auto_response']:1; - $this->flags = 0; $this->setFlag(self::FLAG_ASSIGN_MEMBERS_ONLY, isset($vars['assign_members_only'])); $this->setFlag(self::FLAG_DISABLE_AUTO_CLAIM, isset($vars['disable_auto_claim'])); + $filter_actions = FilterAction::objects()->filter(array('type' => 'dept', 'configuration' => '{"dept_id":'. $this->getId().'}')); + if ($filter_actions && $vars['status'] == __('Active')) + FilterAction::setFilterFlag($filter_actions, 'dept', false); + else + FilterAction::setFilterFlag($filter_actions, 'dept', true); + + switch ($vars['status']) + { + case __('Active'): + $this->setFlag(self::FLAG_ACTIVE, true); + $this->setFlag(self::FLAG_ARCHIVED, false); + break; + + case __('Disabled'): + $this->setFlag(self::FLAG_ACTIVE, false); + $this->setFlag(self::FLAG_ARCHIVED, false); + break; + + case __('Archived'): + $this->setFlag(self::FLAG_ACTIVE, false); + $this->setFlag(self::FLAG_ARCHIVED, true); + break; + } + $this->path = $this->getFullPath(); $wasnew = $this->__new__; @@ -761,7 +846,7 @@ extends Form { 'default' => 0, 'choices' => array(0 => '— '.__('Top-Level Department').' —') - + Dept::getDepartments() + + Dept::getPublicDepartments() )), 'name' => new TextboxField(array( 'required' => true, diff --git a/include/class.email.php b/include/class.email.php index a91bebde566cf9709736ffec2b1cfaf4fc579e85..b0dce8bbce91312575695a6b0fcdf070b580d735 100644 --- a/include/class.email.php +++ b/include/class.email.php @@ -264,6 +264,14 @@ class Email extends VerySimpleModel { if(!$vars['name']) $errors['name']=__('Email name required'); + $dept = Dept::lookup($vars['dept_id']); + if($dept && !$dept->isActive()) + $errors['dept_id'] = ''; + + $topic = Topic::lookup($vars['topic_id']); + if($topic && !$topic->isActive()) + $errors['topic_id'] = ''; + if($vars['mail_active'] || ($vars['smtp_active'] && $vars['smtp_auth'])) { if(!$vars['userid']) $errors['userid']=__('Username missing'); diff --git a/include/class.filter.php b/include/class.filter.php index 29f49d904949b2318dbd4da9d16c6ebed7f1f299..0ea5c4ab4036e4ad4b8ea21e0c0b4a8fe9ecf029 100644 --- a/include/class.filter.php +++ b/include/class.filter.php @@ -21,6 +21,9 @@ class Filter { var $id; var $ht; + const FLAG_INACTIVE_HT = 0x0001; + const FLAG_INACTIVE_DEPT = 0x0002; + static $match_types = array( /* @trans */ 'User Information' => array( array('name' => /* @trans */ 'Name', @@ -138,6 +141,15 @@ class Filter { return $this->ht['topic_id']; } + public function setFlag($flag, $val) { + if ($val) + $this->ht['flags'] |= $flag; + else + $this->ht['flags'] &= ~$flag; + $vars['rules']= $this->getRules(); + $this->update($this->ht, $errors); + } + function stopOnMatch() { return ($this->ht['stop_onmatch']); } @@ -340,7 +352,7 @@ class Filter { } function update($vars,&$errors) { - + $vars['flags'] = $this->ht['flags']; if(!Filter::save($this->getId(),$vars,$errors)) return false; @@ -457,6 +469,21 @@ class Filter { } function save($id,$vars,&$errors) { + if ($this) { + foreach ($this->getActions() as $A) { + if ($A->type == 'dept') + $dept = Dept::lookup($A->parseConfiguration($vars)['dept_id']); + + if ($A->type == 'topic') + $topic = Topic::lookup($A->parseConfiguration($vars)['topic_id']); + } + } + + if($dept && !$dept->isActive()) + $errors['err'] = sprintf(__('%s selected for %s must be active'), __('Department'), __('Filter Action')); + + if($topic && !$topic->isActive()) + $errors['err'] = sprintf(__('%s selected for %s must be active'), __('Help Topic'), __('Filter Action')); if(!$vars['execorder']) $errors['execorder'] = __('Order required'); @@ -487,6 +514,7 @@ class Filter { $sql=' updated=NOW() ' .',isactive='.db_input($vars['isactive']) + .',flags='.db_input($vars['flags']) .',target='.db_input($vars['target']) .',name='.db_input($vars['name']) .',execorder='.db_input($vars['execorder']) @@ -518,6 +546,29 @@ class Filter { return count($errors) == 0; } + function validate_actions($action) { + + $config = json_decode($action->ht['configuration'], true); + if ($action->ht['type'] == 'dept') { + $dept = Dept::lookup($config['dept_id']); + if (!$dept || !$dept->isActive()) { + $errors['err'] = sprintf(__('Unable to save: Please choose an active %s'), 'Department'); + return $errors; + } + } + + if ($action->ht['type'] == 'topic') { + $topic = Topic::lookup($config['topic_id']); + if (!$topic || !$topic->isActive()) { + $errors['err'] = sprintf(__('Unable to save: Please choose an active %s'), 'Help Topic'); + return $errors; + } + } + + return false; + + } + function save_actions($id, $vars, &$errors) { if (!is_array(@$vars['actions'])) return; @@ -540,11 +591,28 @@ class Filter { 'sort' => (int) $sort, )); $I->setConfiguration($errors, $vars); + $config = json_decode($I->ht['configuration'], true); + + $invalid = self::validate_actions($I); + if ($invalid) { + $errors['err'] = sprintf($invalid['err']); + return; + } + $I->save(); break; - case 'I': # exiting filter action + case 'I': # existing filter action if ($I = FilterAction::lookup($info)) { $I->setConfiguration($errors, $vars); + + $config = json_decode($I->ht['configuration'], true); + + $invalid = self::validate_actions($I); + if ($invalid) { + $errors['err'] = sprintf($invalid['err']); + return; + } + $I->sort = (int) $sort; $I->save(); } diff --git a/include/class.filter_action.php b/include/class.filter_action.php index f5dc14abbc77740d58a368e434603568b6f64fca..081e6d251e30901b3920ec053061483cd4e9aaae 100644 --- a/include/class.filter_action.php +++ b/include/class.filter_action.php @@ -41,15 +41,28 @@ class FilterAction extends VerySimpleModel { return $this->_config; } - function setConfiguration(&$errors=array(), $source=false) { - $config = array(); - foreach ($this->getImpl()->getConfigurationForm($source ?: $_POST) - ->getFields() as $name=>$field) { - if (!$field->hasData()) - continue; + function parseConfiguration($source, &$errors=array()) + { + if (!$source) + return $this->getConfiguration(); + + $config = array(); + foreach ($this->getImpl()->getConfigurationForm($source) + ->getFields() as $name=>$field) { + if (!$field->hasData()) + continue; + if($field->to_php($field->getClean())) $config[$name] = $field->to_php($field->getClean()); - $errors = array_merge($errors, $field->errors()); - } + else + $config[$name] = $field->getClean(); + + $errors = array_merge($errors, $field->errors()); + } + return $config; + } + + function setConfiguration(&$errors=array(), $source=false) { + $config = $this->parseConfiguration($source ?: $_POST, $errors); if (count($errors) === 0) $this->set('configuration', JsonDataEncoder::encode($config)); return count($errors) === 0; @@ -65,6 +78,15 @@ class FilterAction extends VerySimpleModel { return $this->_impl; } + function setFilterFlag($actions, $flag, $bool) { + $errors = array(); + foreach ($actions as $action) { + $filter = Filter::lookup($action->filter_id); + if ($flag == 'dept') $filter->setFlag(Filter::FLAG_INACTIVE_DEPT, $bool); + if ($flag == 'topic') $filter->setFlag(Filter::FLAG_INACTIVE_HT, $bool); + } + } + function apply(&$ticket, array $info) { return $this->getImpl()->apply($ticket, $info); } @@ -273,19 +295,32 @@ class FA_RouteDepartment extends TriggerAction { function apply(&$ticket, array $info) { $config = $this->getConfiguration(); - if ($config['dept_id']) + if ($config['dept_id']) { + $dept = Dept::lookup($config['dept_id']); + + if ($dept->isActive()) $ticket['deptId'] = $config['dept_id']; + } } function getConfigurationOptions() { + $depts = Dept::getDepartments(null, true, false); + + if ($this->action->type == 'dept') { + $dept_id = json_decode($this->action->configuration, true); + $dept = Dept::lookup($dept_id['dept_id']); + if ($dept && !$dept->isActive()) + $depts[$dept->getId()] = $dept->getName(); + } + return array( - 'dept_id' => new ChoiceField(array( + 'dept_id' => new ChoiceField(array( 'configuration' => array( 'prompt' => __('Unchanged'), 'data' => array('quick-add' => 'department'), ), 'choices' => - Dept::getDepartments() + + $depts + array(':new:' => '— '.__('Add New').' —'), 'validators' => function($self, $clean) { if ($clean === ':new:') @@ -406,12 +441,24 @@ class FA_AssignTopic extends TriggerAction { function apply(&$ticket, array $info) { $config = $this->getConfiguration(); - if ($config['topic_id']) + if ($config['topic_id']) { + $topic = Topic::lookup($config['topic_id']); + + if ($topic->isActive()) $ticket['topicId'] = $config['topic_id']; + } } function getConfigurationOptions() { - $choices = Topic::getHelpTopics(false, Topic::DISPLAY_DISABLED); + $choices = Topic::getHelpTopics(false, false); + + if ($this->action->type == 'topic') { + $topic_id = json_decode($this->action->configuration, true); + $topic = Topic::lookup($topic_id['topic_id']); + if ($topic && !$topic->isActive()) + $choices[$topic->getId()] = $topic->getName(); + } + return array( 'topic_id' => new ChoiceField(array( 'configuration' => array('prompt' => __('Unchanged')), diff --git a/include/class.forms.php b/include/class.forms.php index 39d17ebd3f2f9b03b8fd423b0ac42a8b6b137034..c7e20d3627a45a4ff8551d2aaf20d8c3e67ef27b 100644 --- a/include/class.forms.php +++ b/include/class.forms.php @@ -2645,10 +2645,47 @@ class DepartmentField extends ChoiceField { function getChoices($verbose=false) { global $cfg; + $selected = self::getWidget(); + if($selected && $selected->value) { + if(is_array($selected->value)) { + foreach ($selected->value as $k => $v) { + $current_id = $k; + $current_name = $v; + } + } + else { + $current_id = $selected->value; + $current_name = Dept::getNameById($current_id); + $addNew = true; + } + } + + $active_depts = array(); + if($current_id) + $active_depts = Dept::objects() + ->filter(array('flags__hasbit' => Dept::FLAG_ACTIVE)) + ->values('id', 'name'); + $choices = array(); - if (($depts = Dept::getDepartments())) - foreach ($depts as $id => $name) - $choices[$id] = $name; + if ($depts = Dept::getDepartments(null, true, Dept::DISPLAY_DISABLED)) { + //create array w/queryset + $active = array(); + foreach ($active_depts as $dept) + $active[$dept['id']] = $dept['name']; + + //add selected dept to list + $active[$current_id] = $current_name; + + + foreach ($depts as $id => $name) { + $choices[$id] = $name; + if(!array_key_exists($id, $active) && $current_id) + unset($choices[$id]); + } + + } + if($addNew) + $choices[':new:'] = '— '.__('Add New').' —'; return $choices; } diff --git a/include/class.report.php b/include/class.report.php index 179dd8e13fcaf35b2c0d2ed928ee4ba9e8135f26..999ae22fe0ac6c6e12a70edbb1bf6fc340f2611c 100644 --- a/include/class.report.php +++ b/include/class.report.php @@ -202,7 +202,7 @@ class OverviewReport { $pk = 'dept__id'; $stats = $stats ->filter(array('dept_id__in' => $thisstaff->getDepts())) - ->values('dept__id', 'dept__name'); + ->values('dept__id', 'dept__name', 'dept__flags'); $times = $times ->filter(array('dept_id__in' => $thisstaff->getDepts())) ->values('dept__id'); @@ -212,7 +212,7 @@ class OverviewReport { $header = function($row) { return Topic::getLocalNameById($row['topic_id'], $row['topic__topic']); }; $pk = 'topic_id'; $stats = $stats - ->values('topic_id', 'topic__topic') + ->values('topic_id', 'topic__topic', 'topic__flags') ->filter(array('dept_id__in' => $thisstaff->getDepts(), 'topic_id__gt' => 0)); $times = $times ->values('topic_id') @@ -246,8 +246,25 @@ class OverviewReport { } $rows = array(); foreach ($stats as $R) { + if (isset($R['dept__flags'])) { + if ($R['dept__flags'] & Dept::FLAG_ARCHIVED) + $status = ' - '.__('Archived'); + elseif ($R['dept__flags'] & Dept::FLAG_ACTIVE) + $status = ''; + else + $status = ' - '.__('Disabled'); + } + if (isset($R['topic__flags'])) { + if ($R['topic__flags'] & Topic::FLAG_ARCHIVED) + $status = ' - '.__('Archived'); + elseif ($R['topic__flags'] & Topic::FLAG_ACTIVE) + $status = ''; + else + $status = ' - '.__('Disabled'); + } + $T = $timings[$R[$pk]]; - $rows[] = array($header($R), $R['Opened'], $R['Assigned'], + $rows[] = array($header($R) . $status, $R['Opened'], $R['Assigned'], $R['Overdue'], $R['Closed'], $R['Reopened'], $R['Deleted'], number_format($T['ServiceTime'], 1), number_format($T['ResponseTime'], 1)); diff --git a/include/class.staff.php b/include/class.staff.php index 9d4df38cc19ccdba8dc0095236881e4d4f7e2482..05260871121adb619a70f23a6e86668061751ea7 100644 --- a/include/class.staff.php +++ b/include/class.staff.php @@ -1047,6 +1047,10 @@ implements AuthenticatedUser, EmailContact, TemplateVariable, Searchable { if(!$vars['role_id']) $errors['role_id']=__('Role for primary department is required'); + $dept = Dept::lookup($vars['dept_id']); + if($dept && !$dept->isActive()) + $errors['dept_id'] = sprintf(__('%s selected must be active'), __('Department')); + // Ensure we will still have an administrator with access if ($vars['isadmin'] !== '1' || $vars['islocked'] === '1') { $sql = 'select count(*), max(staff_id) from '.STAFF_TABLE diff --git a/include/class.thread.php b/include/class.thread.php index c6643ccbbb9bf96bfaf43538ac057ef245060256..e9f079f2359b4468a93becb01fb99776adaf12ad 100644 --- a/include/class.thread.php +++ b/include/class.thread.php @@ -2083,8 +2083,6 @@ class ThreadEvents extends InstrumentedList { $event = ThreadEvent::forTicket($object, $state, $user); elseif ($object instanceof Task) $event = ThreadEvent::forTask($object, $state, $user); - // else - // $event = ThreadEvent::create(false, $user); # Annul previous entries if requested (for instance, reopening a # ticket will annul an 'closed' entry). This will be useful to diff --git a/include/class.ticket.php b/include/class.ticket.php index 5b3f765a9033effb7df7577b2e8bbc444e80c7f9..aa57299fb09951b10ae106d5382548e50b8c532a 100644 --- a/include/class.ticket.php +++ b/include/class.ticket.php @@ -207,7 +207,9 @@ implements RestrictedAccess, Threadable, Searchable { } function isReopenable() { - return $this->getStatus()->isReopenable(); + return ($this->getStatus()->isReopenable() + && $this->getDept()->allowsReopen() + && $this->getTopic()->allowsReopen()); } function isClosed() { @@ -3158,6 +3160,10 @@ implements RestrictedAccess, Threadable, Searchable { $errors['source'] = sprintf( __('Invalid source given - %s'), Format::htmlchars($vars['source'])); + $topic = Topic::lookup($vars['topicId']); + if($topic && !$topic->isActive()) + $errors['topicId']= sprintf(__('%s selected must be active'), __('Help Topic')); + // Validate dynamic meta-data $forms = DynamicFormEntry::forTicket($this->getId()); foreach ($forms as $form) { diff --git a/include/class.topic.php b/include/class.topic.php index 0ac168c10c93ead1aa74adfcbe68687bfb27cfbf..ffff7049b6e70603d27228f0b65646f5cccac2ab 100644 --- a/include/class.topic.php +++ b/include/class.topic.php @@ -67,6 +67,8 @@ implements TemplateVariable, Searchable { const FORM_USE_PARENT = 4294967295; const FLAG_CUSTOM_NUMBERS = 0x0001; + const FLAG_ACTIVE = 0x0002; + const FLAG_ARCHIVED = 0x0004; const SORT_ALPHA = 'a'; const SORT_MANUAL = 'm'; @@ -136,6 +138,11 @@ implements TemplateVariable, Searchable { return $this->dept_id; } + function getDept() { + + return $this->getDeptId() ? Dept::lookup($this->getDeptId()) : null; + } + function getSLAId() { return $this->sla_id; } @@ -184,30 +191,35 @@ implements TemplateVariable, Searchable { return $this->isActive(); } - /** - * Determine if the help topic is currently enabled. The ancestry of - * this topic will be considered to see if any of the parents are - * disabled. If any are disabled, then this topic will be considered - * disabled. - * - * Parameters: - * $chain - array<id:bool> recusion chain used to detect loops. The - * chain should be maintained and passed to a parent's ::isActive() - * method. When consulting a parent, if the local topic ID is a key - * in the chain, then this topic has already been considered, and - * there is a loop in the ancestry - */ - function isActive(array $chain=array()) { - if (!$this->isactive) - return false; + function isActive() + { + return !!($this->flags & self::FLAG_ACTIVE); + } - if (!isset($chain[$this->getId()]) && ($p = $this->getParent())) { - $chain[$this->getId()] = true; - return $p->isActive($chain); - } - else { - return $this->isactive; + function clearInactiveTopic($topic_id) { + global $cfg; + + $emails = Email::objects()->filter(array('topic_id'=>$topic_id))->values_flat('email_id'); + if ($emails) { + foreach ($emails as $email_id) { + $email = Email::lookup($email_id[0]); + $email->topic_id = $cfg->getDefaultTopicId(); + $email->save(); } + } + } + + function getStatus() { + if($this->flags & self::FLAG_ACTIVE) + return 'Active'; + elseif($this->flags & self::FLAG_ARCHIVED) + return 'Archived'; + else + return 'Disabled'; + } + + function allowsReopen() { + return !($this->flags & self::FLAG_ARCHIVED); } function isPublic() { @@ -221,6 +233,7 @@ implements TemplateVariable, Searchable { function getInfo() { $base = $this->getHashtable(); $base['custom-numbers'] = $this->hasFlag(self::FLAG_CUSTOM_NUMBERS); + $base['status'] = $this->getStatus(); return $base; } @@ -303,75 +316,91 @@ implements TemplateVariable, Searchable { return $topic; } - static function getHelpTopics($publicOnly=false, $disabled=false, $localize=true) { - global $cfg; - static $topics, $names = array(); - - // If localization is specifically requested, then rebuild the list. - if (!$names || $localize) { - $objects = self::objects()->values_flat( - 'topic_id', 'topic_pid', 'ispublic', 'isactive', 'topic' - ) - ->order_by('sort'); - - // Fetch information for all topics, in declared sort order - $topics = array(); - foreach ($objects as $T) { - list($id, $pid, $pub, $act, $topic) = $T; - $topics[$id] = array('pid'=>$pid, 'public'=>$pub, - 'disabled'=>!$act, 'topic'=>$topic); - } - - $localize_this = function($id, $default) use ($localize) { - if (!$localize) - return $default; - - $tag = _H("topic.name.{$id}"); - $T = CustomDataTranslation::translate($tag); - return $T != $tag ? $T : $default; - }; - - // Resolve parent names - foreach ($topics as $id=>$info) { - $name = $localize_this($id, $info['topic']); - $loop = array($id=>true); - $parent = false; - while (($pid = $info['pid']) && ($info = $topics[$info['pid']])) { - $name = sprintf('%s / %s', $localize_this($pid, $info['topic']), - $name); - if ($parent && $parent['disabled']) - // Cascade disabled flag - $topics[$id]['disabled'] = true; - if (isset($loop[$info['pid']])) - break; - $loop[$info['pid']] = true; - $parent = $info; - } - $names[$id] = $name; - } - } - - // Apply requested filters - $requested_names = array(); - foreach ($names as $id=>$n) { - $info = $topics[$id]; - if ($publicOnly && !$info['public']) - continue; - if (!$disabled && $info['disabled']) - continue; - if ($disabled === self::DISPLAY_DISABLED && $info['disabled']) - $n .= " - ".__("(disabled)"); - $requested_names[$id] = $n; - } + /** + * setFlag + * + * Utility method to set/unset flag bits + * + */ + public function setFlag($flag, $val) { - // If localization requested and the current locale is not the - // primary, the list may need to be sorted. Caching is ok here, - // because the locale is not going to be changed within a single - // request. - if ($localize && $cfg->getTopicSortMode() == self::SORT_ALPHA) - return Internationalization::sortKeyedList($requested_names); + if ($val) + $this->flags |= $flag; + else + $this->flags &= ~$flag; + } - return $requested_names; + static function getHelpTopics($publicOnly=false, $disabled=false, $localize=true) { + global $cfg; + static $topics, $names = array(); + + // If localization is specifically requested, then rebuild the list. + if (!$names || $localize) { + $objects = self::objects()->values_flat( + 'topic_id', 'topic_pid', 'ispublic', 'flags', 'topic' + ) + ->order_by('sort'); + + // Fetch information for all topics, in declared sort order + $topics = array(); + foreach ($objects as $T) { + list($id, $pid, $pub, $flags, $topic) = $T; + + $display = ($flags & self::FLAG_ACTIVE); + $topics[$id] = array('pid'=>$pid, 'public'=>$pub, + 'disabled'=>!$display, 'topic'=>$topic); + } + + $localize_this = function($id, $default) use ($localize) { + if (!$localize) + return $default; + + $tag = _H("topic.name.{$id}"); + $T = CustomDataTranslation::translate($tag); + return $T != $tag ? $T : $default; + }; + + // Resolve parent names + foreach ($topics as $id=>$info) { + $name = $localize_this($id, $info['topic']); + $loop = array($id=>true); + $parent = false; + while (($pid = $info['pid']) && ($info = $topics[$info['pid']])) { + $name = sprintf('%s / %s', $localize_this($pid, $info['topic']), + $name); + if ($parent && $parent['disabled']) + // Cascade disabled flag + $topics[$id]['disabled'] = true; + if (isset($loop[$info['pid']])) + break; + $loop[$info['pid']] = true; + $parent = $info; + } + $names[$id] = $name; + } + } + + // Apply requested filters + $requested_names = array(); + foreach ($names as $id=>$n) { + $info = $topics[$id]; + if ($publicOnly && !$info['public']) + continue; + if (!$disabled && $info['disabled']) + continue; + if ($disabled === self::DISPLAY_DISABLED && $info['disabled']) + $n .= " - ".__("(disabled)"); + $requested_names[$id] = $n; + } + + // If localization requested and the current locale is not the + // primary, the list may need to be sorted. Caching is ok here, + // because the locale is not going to be changed within a single + // request. + if ($localize && $cfg->getTopicSortMode() == self::SORT_ALPHA) + return Internationalization::sortKeyedList($requested_names); + + return $requested_names; } static function getPublicHelpTopics() { @@ -413,6 +442,10 @@ implements TemplateVariable, Searchable { && (!isset($this->topic_id) || $tid!=$this->getId())) $errors['topic']=__('Topic already exists'); + $dept = Dept::lookup($vars['dept_id']); + if($dept && !$dept->isActive()) + $errors['dept_id'] = sprintf(__('%s selected must be active'), __('Department')); + if (!is_numeric($vars['dept_id'])) $errors['dept_id']=__('Department selection is required'); @@ -434,10 +467,34 @@ implements TemplateVariable, Searchable { $this->ispublic = $vars['ispublic']; $this->sequence_id = $vars['custom-numbers'] ? $vars['sequence_id'] : 0; $this->number_format = $vars['custom-numbers'] ? $vars['number_format'] : ''; - $this->flags = $vars['custom-numbers'] ? self::FLAG_CUSTOM_NUMBERS : 0; + $this->flags = $vars['custom-numbers'] ? self::FLAG_CUSTOM_NUMBERS : $this->flags; $this->noautoresp = !!$vars['noautoresp']; $this->notes = Format::sanitize($vars['notes']); + $filter_actions = FilterAction::objects()->filter(array('type' => 'topic', 'configuration' => '{"topic_id":'. $this->getId().'}')); + if ($filter_actions && $vars['status'] == __('Active')) + FilterAction::setFilterFlag($filter_actions, 'topic', false); + else + FilterAction::setFilterFlag($filter_actions, 'topic', true); + + switch ($vars['status']) + { + case __('Active'): + $this->setFlag(self::FLAG_ACTIVE, true); + $this->setFlag(self::FLAG_ARCHIVED, false); + break; + + case __('Disabled'): + $this->setFlag(self::FLAG_ACTIVE, false); + $this->setFlag(self::FLAG_ARCHIVED, false); + break; + + case __('Archived'): + $this->setFlag(self::FLAG_ACTIVE, false); + $this->setFlag(self::FLAG_ARCHIVED, true); + break; + } + //Auto assign ID is overloaded... if ($vars['assign'] && $vars['assign'][0] == 's') { $this->team_id = 0; diff --git a/include/client/view.inc.php b/include/client/view.inc.php index b368ae25dfce5a70a421237b6bf863bf75550f99..42ef768311eb746dff3f52c229fd1dbf401cabce 100644 --- a/include/client/view.inc.php +++ b/include/client/view.inc.php @@ -185,7 +185,8 @@ echo $attrs; ?>><?php echo $draft ?: $info['message']; print $attachments->render(array('client'=>true)); } ?> </div> -<?php if ($ticket->isClosed()) { ?> +<?php + if ($ticket->isClosed() && $ticket->isReopenable()) { ?> <div class="warning-banner"> <?php echo __('Ticket will be reopened on message post'); ?> </div> diff --git a/include/i18n/en_US/help/tips/manage.helptopic.yaml b/include/i18n/en_US/help/tips/manage.helptopic.yaml index 0297f1ceeb93f418b112cdfecbc4213f1ae2cbeb..e13ae5eafbde807b69adbb95af3be74b95b587d2 100644 --- a/include/i18n/en_US/help/tips/manage.helptopic.yaml +++ b/include/i18n/en_US/help/tips/manage.helptopic.yaml @@ -27,7 +27,7 @@ topic: status: title: Status content: > - If disabled, this <span class="doc-desc-title">Help Topic</span> + If disabled or archived, this <span class="doc-desc-title">Help Topic</span> will not be available. type: diff --git a/include/i18n/en_US/help/tips/staff.department.yaml b/include/i18n/en_US/help/tips/staff.department.yaml index 32e65ea60ddba610ac130623161c3e5f287d8f4f..aee25f97df04081c04a2639d49d08fb54f9d2ccf 100644 --- a/include/i18n/en_US/help/tips/staff.department.yaml +++ b/include/i18n/en_US/help/tips/staff.department.yaml @@ -13,6 +13,11 @@ # must match the HTML #ids put into the page template. # --- +status: + title: Status + content: > + If disabled or archived, this <span class="doc-desc-title">Department</span> + will not be available. type: title: Type content: > diff --git a/include/staff/cannedresponse.inc.php b/include/staff/cannedresponse.inc.php index 20818d994242254f10fe2c85e5747742e9a944ef..981eef289ab2f340940ba58651efa73338615c89 100644 --- a/include/staff/cannedresponse.inc.php +++ b/include/staff/cannedresponse.inc.php @@ -57,7 +57,7 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info); <select name="dept_id"> <option value="0">— <?php echo __('All Departments');?> —</option> <?php - if (($depts=Dept::getDepartments())) { + if (($depts=Dept::getDepartments(array('publiconly' => true)))) { foreach($depts as $id => $name) { $selected=($info['dept_id'] && $id==$info['dept_id'])?'selected="selected"':''; echo sprintf('<option value="%d" %s>%s</option>',$id,$selected,$name); diff --git a/include/staff/department.inc.php b/include/staff/department.inc.php index b8bd103003aad8ff155e111d051e255c73729c21..4352badf30eb6e2dc3647712795d335a65c874f5 100644 --- a/include/staff/department.inc.php +++ b/include/staff/department.inc.php @@ -59,14 +59,27 @@ $info = Format::htmlchars(($errors && $_POST) ? $_POST : $info); <td> <select name="pid"> <option value="">— <?php echo __('Top-Level Department'); ?> —</option> -<?php foreach (Dept::getDepartments() as $id=>$name) { - if ($info['id'] && $id == $info['id']) - continue; ?> - <option value="<?php echo $id; ?>" <?php - if ($info['pid'] == $id) echo 'selected="selected"'; - ?>><?php echo $name; ?></option> -<?php } ?> - </select> + <?php + if($info['pid']) + $current_name = Dept::getNameById($info['pid']); + if ($depts=Dept::getPublicDepartments()) + { + if(!array_key_exists($info['pid'], $depts) && $info['pid']) + { + $depts[$info['pid']] = $current_name; + $warn = sprintf(__('%s selected must be active'), __('Parent Department')); + } + foreach ($depts as $id=>$name) { + $selected=($info['pid'] && $id==$info['pid'])?'selected="selected"':''; + echo sprintf('<option value="%d" %s>%s</option>',$id,$selected,$name); + } + } + ?> + </select> + <?php + if($warn) { ?> + <span class="error">* <?php echo $warn; ?></span> + <?php } ?> </td> </tr> <tr> @@ -80,6 +93,19 @@ $info = Format::htmlchars(($errors && $_POST) ? $_POST : $info); <span class="error">* <?php echo $errors['name']; ?></span> </td> </tr> + <tr> + <td width="180" class="required"> + <?php echo __('Status');?>: + </td> + <td> + <select name="status"> + <option value="Active"<?php echo ($info['status'] == __('Active'))?'selected="selected"':'';?>><?php echo __('Active'); ?></option> + <option value="Disabled"<?php echo ($info['status'] == __('Disabled'))?'selected="selected"':'';?>><?php echo __('Disabled'); ?></option> + <option value="Archived"<?php echo ($info['status'] == __('Archived'))?'selected="selected"':'';?>><?php echo __('Archived'); ?></option> + </select> + <span class="error"> </span> <i class="help-tip icon-question-sign" href="#status"></i> + </td> + </tr> <tr> <td width="180" class="required"> <?php echo __('Type');?>: diff --git a/include/staff/departments.inc.php b/include/staff/departments.inc.php index 2924eea68f11acb94209187472eef9b1892c03e6..4fd4a34c9fe0870e6c006886bd5a23d88e68d5ec 100644 --- a/include/staff/departments.inc.php +++ b/include/staff/departments.inc.php @@ -5,6 +5,7 @@ if (!defined('OSTADMININC') || !$thisstaff->isAdmin()) $qs = array(); $sortOptions=array( 'name' => 'name', + 'status' => 'flags', 'type' => 'ispublic', 'members'=> 'members_count', 'email'=> 'email__name', @@ -53,9 +54,28 @@ $showing = $pageNav->showing().' '._N('department', 'departments', $count); </span> <div id="action-dropdown-more" class="action-dropdown anchor-right"> <ul id="actions"> + <li> + <a class="confirm" data-name="enable" href="departments.php?a=enable"> + <i class="icon-ok-sign icon-fixed-width"></i> + <?php echo __( 'Enable'); ?> + </a> + </li> + <li> + <a class="confirm" data-name="disable" href="departments.php?a=disable"> + <i class="icon-ban-circle icon-fixed-width"></i> + <?php echo __( 'Disable'); ?> + </a> + </li> + <li> + <a class="confirm" data-name="archive" href="departments.php?a=archive"> + <i class="icon-folder-close icon-fixed-width"></i> + <?php echo __( 'Archive'); ?> + </a> + </li> <li class="danger"><a class="confirm" data-name="delete" href="departments.php?a=delete"> <i class="icon-trash icon-fixed-width"></i> - <?php echo __('Delete'); ?></a></li> + <?php echo __('Delete'); ?></a> + </li> </ul> </div> </div> @@ -70,8 +90,11 @@ $showing = $pageNav->showing().' '._N('department', 'departments', $count); <tr> <th width="4%"> </th> <th width="28%"><a <?php echo $name_sort; ?> href="departments.php?<?php echo $qstr; ?>&sort=name"><?php echo __('Name');?></a></th> + <th width="8%"><a <?php echo $status_sort; ?> href="departments.php?<?php echo $qstr;?>&sort=status"><?php echo __('Status');?></a></th> + <!-- <th style="padding-left:4px;vertical-align:middle" width="8%"><?php echo __('Status'); ?></th> --> <th width="8%"><a <?php echo $type_sort; ?> href="departments.php?<?php echo $qstr; ?>&sort=type"><?php echo __('Type');?></a></th> - <th width="8%"><a <?php echo $users_sort; ?>href="departments.php?<?php echo $qstr; ?>&sort=users"><?php echo __('Agents');?></a></th> + <!-- <th width="8%"><a <?php echo $users_sort; ?>href="departments.php?<?php echo $qstr; ?>&sort=users"><?php echo __('Agents');?></a></th> --> + <th width="8%"><a <?php echo $users_sort; ?>href="departments.php?<?php echo $qstr; ?>&sort=members"><?php echo __('Agents');?></a></th> <th width="30%"><a <?php echo $email_sort; ?> href="departments.php?<?php echo $qstr; ?>&sort=email"><?php echo __('Email Address');?></a></th> <th width="22%"><a <?php echo $manager_sort; ?> href="departments.php?<?php echo $qstr; ?>&sort=manager"><?php echo __('Manager');?></a></th> </tr> @@ -115,8 +138,17 @@ $showing = $pageNav->showing().' '._N('department', 'departments', $count); <?php echo $sel? 'checked="checked"' : ''; ?> <?php echo $default? 'disabled="disabled"' : ''; ?> > </td> - <td><a href="departments.php?id=<?php echo $id; ?>"><?php - echo Dept::getNameById($id); ?></a> <?php echo $default; ?></td> + <td> + <a href="departments.php?id=<?php echo $id; ?>"><?php + echo Dept::getNameById($id); ?></a> <?php echo $default; ?> + </td> + <td><?php + if($dept->getStatus() == __('Active')) + echo $dept->getStatus(); + else + echo '<b>'.$dept->getStatus(); + ?> + </td> <td><?php echo $dept->isPublic() ? __('Public') :'<b>'.__('Private').'</b>'; ?></td> <td> <b> @@ -136,7 +168,7 @@ $showing = $pageNav->showing().' '._N('department', 'departments', $count); } ?> <tfoot> <tr> - <td colspan="6"> + <td colspan="7"> <?php if ($count) { ?> <?php echo __('Select');?>: @@ -170,6 +202,18 @@ endif; <?php echo sprintf(__('Are you sure you want to make %s <b>private</b> (internal)?'), _N('selected department', 'selected departments', 2));?> </p> + <p class="confirm-action" style="display:none;" id="enable-confirm"> + <?php echo sprintf(__('Are you sure you want to <b>enable</b> %s?'), + _N('selected department', 'selected departments', 2));?> + </p> + <p class="confirm-action" style="display:none;" id="disable-confirm"> + <?php echo sprintf(__('Are you sure you want to <b>disable</b> %s?'), + _N('selected department', 'selected departments', 2));?> + </p> + <p class="confirm-action" style="display:none;" id="archive-confirm"> + <?php echo sprintf(__('Are you sure you want to <b>archive</b> %s?'), + _N('selected department', 'selected departments', 2));?> + </p> <p class="confirm-action" style="display:none;" id="delete-confirm"> <font color="red"><strong><?php echo sprintf(__('Are you sure you want to DELETE %s?'), _N('selected department', 'selected departments', 2));?></strong></font> diff --git a/include/staff/email.inc.php b/include/staff/email.inc.php index 3653f06a7949bacc7d92d1b32a911c075abe07c0..9633acff690ca42c5aa378ea589e69460017f861 100644 --- a/include/staff/email.inc.php +++ b/include/staff/email.inc.php @@ -87,7 +87,13 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info); <option value="0" selected="selected">— <?php echo __('System Default'); ?> —</option> <?php - if (($depts=Dept::getDepartments())) { + if ($depts=Dept::getPublicDepartments()) { + if($info['dept_id'] && !array_key_exists($info['dept_id'], $depts)) + { + $depts[$info['dept_id']] = $email->dept; + $warn = sprintf(__('%s selected must be active'), __('Department')); + } + foreach ($depts as $id => $name) { $selected=($info['dept_id'] && $id==$info['dept_id'])?'selected="selected"':''; echo sprintf('<option value="%d" %s>%s</option>',$id,$selected,$name); @@ -95,9 +101,12 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info); } ?> </select> + <?php + if($warn) { ?> + <span class="error">* <?php echo $warn; ?></span> + <?php } ?> <i class="help-tip icon-question-sign" href="#new_ticket_department"></i> </span> - <span class="error"><?php echo $errors['dept_id']; ?></span> </td> </tr> <tr> @@ -133,12 +142,21 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info); <select name="topic_id"> <option value="0" selected="selected">— <?php echo __('System Default'); ?> —</option> <?php + $warn = ''; $topics = Topic::getHelpTopics(); + if($info['topic_id'] && !array_key_exists($info['topic_id'], $topics)) { + $topics[$info['topic_id']] = $email->topic; + $warn = sprintf(__('%s selected must be active'), __('Help Topic')); + } while (list($id,$topic) = each($topics)) { ?> <option value="<?php echo $id; ?>"<?php echo ($info['topic_id']==$id)?'selected':''; ?>><?php echo $topic; ?></option> <?php } ?> </select> + <?php + if($warn) { ?> + <span class="error">* <?php echo $warn; ?></span> + <?php } ?> <i class="help-tip icon-question-sign" href="#new_ticket_help_topic"></i> </span> <span class="error"> diff --git a/include/staff/filter.inc.php b/include/staff/filter.inc.php index 2330fc47dc4ebeece8aa04e8365c71bb30bfb186..ba0c06ce58ccdd35b8dadcdc9001362477da7b83 100644 --- a/include/staff/filter.inc.php +++ b/include/staff/filter.inc.php @@ -238,7 +238,23 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info); <?php $existing = array(); if ($filter) { foreach ($filter->getActions() as $A) { + $_warn = ''; $existing[] = $A->type; + if($A->type == 'dept') { + $errors['topic_id'] = ''; + // $info=Format::htmlchars(($errors && $_POST)?$_POST:$info); + $dept_config = $A->parseConfiguration($_POST); + $dept = Dept::lookup($dept_config['dept_id']); + if($dept && !$dept->isActive()) + $_warn = sprintf(__('%s must be active'), __('Department')); + } + elseif($A->type == 'topic') { + $errors['dept_id'] = ''; + $topic_config = $A->parseConfiguration($_POST); + $topic = Topic::lookup($topic_config['topic_id']); + if($topic && !$topic->isActive()) + $_warn = sprintf(__('%s must be active'), __('Help Topic')); + } ?> <tr style="background-color:white"><td><i class="icon-sort icon-large icon-muted"></i> <?php echo $A->getImpl()->getName(); ?>:</td> @@ -248,7 +264,9 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info); // XXX: Drop this when the ORM supports proper caching $form->isValid(); include STAFFINC_DIR . 'templates/dynamic-form-simple.tmpl.php'; - ?> + if($_warn) { + ?> <span class="error">* <?php echo $_warn; ?></span> + <?php } ?> <input type="hidden" name="actions[]" value="I<?php echo $A->getId(); ?>"/> <div class="pull-right" style="position:absolute;top:2px;right:2px;"> <a href="#" title="<?php echo __('clear'); ?>" onclick="javascript: diff --git a/include/staff/filters.inc.php b/include/staff/filters.inc.php index 6eb7f32310c965fbcb3f013a1666c6fbb99c3d43..7da5b73d318a285120c2f951300af495f19eaf1d 100644 --- a/include/staff/filters.inc.php +++ b/include/staff/filters.inc.php @@ -2,9 +2,11 @@ if(!defined('OSTADMININC') || !$thisstaff->isAdmin()) die('Access Denied'); $targets = Filter::getTargets(); $qs = array(); -$sql='SELECT filter.*,count(rule.id) as rules '. +$sql='SELECT filter.*,count(rule.id) as rules, topic.configuration AS topic, dept.configuration AS dept '. 'FROM '.FILTER_TABLE.' filter '. 'LEFT JOIN '.FILTER_RULE_TABLE.' rule ON(rule.filter_id=filter.id) '. + 'LEFT JOIN '.FILTER_ACTION_TABLE.' topic ON (topic.filter_id = filter.id AND topic.type = \'topic\') '. + 'LEFT JOIN '.FILTER_ACTION_TABLE.' dept ON (dept.filter_id = filter.id AND dept.type = \'dept\') '. "WHERE filter.`name` <> 'SYSTEM BAN LIST' ". 'GROUP BY filter.id'; $sortOptions=array('name'=>'filter.name','status'=>'filter.isactive','order'=>'filter.execorder','rules'=>'rules', @@ -113,7 +115,17 @@ else <input type="checkbox" class="ckb" name="ids[]" value="<?php echo $row['id']; ?>" <?php echo $sel?'checked="checked"':''; ?>> </td> - <td> <a href="filters.php?id=<?php echo $row['id']; ?>"><?php echo Format::htmlchars($row['name']); ?></a></td> + <td> <a href="filters.php?id=<?php echo $row['id']; ?>"><?php echo Format::htmlchars($row['name']); ?></a> + <?php + if ($row['flags'] & Filter::FLAG_INACTIVE_DEPT) + echo '<a data-placement="bottom" data-toggle="tooltip" title="Inactive Department Selected" + <i class="pull-right icon-warning-sign"></a>'; + + if ($row['flags'] & Filter::FLAG_INACTIVE_HT) + echo '<a data-placement="bottom" data-toggle="tooltip" title="Inactive Help Topic Selected" + <i class="pull-right icon-warning-sign"></a>'; + ?> + </td> <td><?php echo $row['isactive']?__('Active'):'<b>'.__('Disabled').'</b>'; ?></td> <td style="text-align:right;padding-right:25px;"><?php echo $row['execorder']; ?> </td> <td style="text-align:right;padding-right:25px;"><?php echo $row['rules']; ?> </td> diff --git a/include/staff/helptopic.inc.php b/include/staff/helptopic.inc.php index 8cb90850d546d9080495833ea95de0d1f5376f1a..b6783666998c52af37d30c4e3ed401c272ff65f0 100644 --- a/include/staff/helptopic.inc.php +++ b/include/staff/helptopic.inc.php @@ -15,7 +15,7 @@ if($topic && $_REQUEST['a']!='add') { $title=__('Add New Help Topic'); $action='create'; $submit_text=__('Add Topic'); - $info['isactive']=isset($info['isactive'])?$info['isactive']:1; + // $info['isactive']=isset($info['isactive'])?$info['isactive']:1; $info['ispublic']=isset($info['ispublic'])?$info['ispublic']:1; $qs += array('a' => $_REQUEST['a']); $forms = TicketForm::objects(); @@ -60,8 +60,11 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info); <?php echo __('Status');?>: </td> <td> - <input type="radio" name="isactive" value="1" <?php echo $info['isactive']?'checked="checked"':''; ?>> <?php echo __('Active'); ?> - <input type="radio" name="isactive" value="0" <?php echo !$info['isactive']?'checked="checked"':''; ?>> <?php echo __('Disabled'); ?> + <select name="status"> + <option value="Active"<?php echo ($info['status'] == __('Active'))?'selected="selected"':'';?>><?php echo __('Active'); ?></option> + <option value="Disabled"<?php echo ($info['status'] == __('Disabled'))?'selected="selected"':'';?>><?php echo __('Disabled'); ?></option> + <option value="Archived"<?php echo ($info['status'] == __('Archived'))?'selected="selected"':'';?>><?php echo __('Archived'); ?></option> + </select> <span class="error">* </span> <i class="help-tip icon-question-sign" href="#status"></i> </td> </tr> @@ -82,7 +85,7 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info); <td> <select name="topic_pid"> <option value="">— <?php echo __('Top-Level Topic'); ?> —</option><?php - $topics = Topic::getAllHelpTopics(); + $topics = Topic::getHelpTopics(); while (list($id,$topic) = each($topics)) { if ($id == $info['topic_id']) continue; ?> @@ -122,13 +125,26 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info); <select name="dept_id" data-quick-add="department"> <option value="0">— <?php echo __('System Default'); ?> —</option> <?php - foreach (Dept::getDepartments() as $id=>$name) { + if($info['dept_id']) + $current_name = Dept::getNameById($info['dept_id']); + if ($depts=Dept::getPublicDepartments()) { + if(!array_key_exists($info['dept_id'], $depts) && $info['dept_id']) + { + $depts[$info['dept_id']] = $current_name; + $warn = sprintf(__('%s selected must be active'), __('Department')); + } + foreach ($depts as $id=>$name) { $selected=($info['dept_id'] && $id==$info['dept_id'])?'selected="selected"':''; echo sprintf('<option value="%d" %s>%s</option>',$id,$selected,$name); - } ?> + } + } + ?> <option value="0" data-quick-add>— <?php echo __('Add New');?> —</option> </select> - <span class="error"> <?php echo $errors['dept_id']; ?></span> + <?php + if($warn) { ?> + <span class="error">* <?php echo $warn; ?></span> + <?php } ?> <i class="help-tip icon-question-sign" href="#department"></i> </td> </tr> diff --git a/include/staff/helptopics.inc.php b/include/staff/helptopics.inc.php index 0b5c58580c22ffdb3c7774db0ac170a904accf57..8978b97e36c1b94b678d006dade0a26310992949 100644 --- a/include/staff/helptopics.inc.php +++ b/include/staff/helptopics.inc.php @@ -41,6 +41,12 @@ $order_by = 'sort'; <?php echo __( 'Disable'); ?> </a> </li> + <li> + <a class="confirm" data-name="archive" href="helptopics.php?a=archive"> + <i class="icon-folder-close icon-fixed-width"></i> + <?php echo __( 'Archive'); ?> + </a> + </li> <li class="danger"> <a class="confirm" data-name="delete" href="helptopics.php?a=delete"> <i class="icon-trash icon-fixed-width"></i> @@ -142,7 +148,13 @@ $order_by = 'sort'; <a href="helptopics.php?id=<?php echo $id; ?>"><?php echo Topic::getTopicName($id); ?></a> </td> - <td><?php echo $topic->isactive ? __('Active') : '<b>'.__('Disabled').'</b>'; ?></td> + <td><?php + if($topic->getStatus() == __('Active')) + echo $topic->getStatus(); + else + echo '<b>'.$topic->getStatus(); + ?> + </td> <td><?php echo $topic->ispublic ? __('Public') : '<b>'.__('Private').'</b>'; ?></td> <td><?php echo $priority; ?></td> <td><a href="departments.php?id=<?php echo $deptId; @@ -189,6 +201,10 @@ endif; <?php echo sprintf(__('Are you sure you want to <b>disable</b> %s?'), _N('selected help topic', 'selected help topics', 2));?> </p> + <p class="confirm-action" style="display:none;" id="archive-confirm"> + <?php echo sprintf(__('Are you sure you want to <b>archive</b> %s?'), + _N('selected help topic', 'selected help topics', 2));?> + </p> <p class="confirm-action" style="display:none;" id="delete-confirm"> <font color="red"><strong><?php echo sprintf(__('Are you sure you want to DELETE %s?'), _N('selected help topic', 'selected help topics', 2));?></strong></font> diff --git a/include/staff/staff.inc.php b/include/staff/staff.inc.php index 4fce85b4f64ad7908964ca0614c6d34b7f73ab17..217daa065de2b514b2b11aac7b2cd246be4fde1f 100644 --- a/include/staff/staff.inc.php +++ b/include/staff/staff.inc.php @@ -228,15 +228,25 @@ if (count($bks) > 1) { <select name="dept_id" id="dept_id" data-quick-add="department"> <option value="0">— <?php echo __('Select Department');?> —</option> <?php - foreach (Dept::getDepartments() as $id=>$name) { - $sel=($staff->dept_id==$id)?'selected="selected"':''; - echo sprintf('<option value="%d" %s>%s</option>',$id,$sel,$name); + if($depts = Dept::getPublicDepartments()) { + if($staff->dept_id && !array_key_exists($staff->dept_id, $depts)) + { + $depts[$staff->dept_id] = $staff->dept; + $warn = sprintf(__('%s selected must be active'), __('Department')); + } + foreach($depts as $id =>$name) { + $sel=($staff->dept_id==$id)?'selected="selected"':''; + echo sprintf('<option value="%d" %s>%s</option>',$id,$sel,$name); + } } ?> <option value="0" data-quick-add>— <?php echo __('Add New');?> —</option> </select> <i class="offset help-tip icon-question-sign" href="#primary_department"></i> - <div class="error"><?php echo $errors['dept_id']; ?></div> + <?php + if($warn) { ?> + <span class="error">* <?php echo $warn; ?></span> + <?php } ?> </td> <td style="vertical-align:top"> <select name="role_id" data-quick-add="role"> diff --git a/include/staff/ticket-edit.inc.php b/include/staff/ticket-edit.inc.php index ecc295a59701eb0df5b0b5c1961f51b0749bad49..f77e02b8715cf9ce690b56777163b743c39551f7 100644 --- a/include/staff/ticket-edit.inc.php +++ b/include/staff/ticket-edit.inc.php @@ -94,6 +94,11 @@ if ($_POST) <option value="" selected >— <?php echo __('Select Help Topic');?> —</option> <?php if($topics=Topic::getHelpTopics()) { + if(!array_key_exists($ticket->topic_id, $topics)) + { + $topics[$ticket->topic_id] = $ticket->topic; + $warn = sprintf(__('%s selected must be active'), __('Help Topic')); + } foreach($topics as $id =>$name) { echo sprintf('<option value="%d" %s>%s</option>', $id, ($info['topicId']==$id)?'selected="selected"':'',$name); @@ -101,7 +106,10 @@ if ($_POST) } ?> </select> - <font class="error"><b>*</b> <?php echo $errors['topicId']; ?></font> + <?php + if($warn) { ?> + <font class="error"><b>*</b> <?php echo $warn; ?></font> + <?php } ?> </td> </tr> <tr> diff --git a/include/staff/ticket-open.inc.php b/include/staff/ticket-open.inc.php index 79b66318d038c87470b7d0defc90f6cd58517e2d..aa396305a70f7b99c0a12e4bad6ed4cbe04e6257 100644 --- a/include/staff/ticket-open.inc.php +++ b/include/staff/ticket-open.inc.php @@ -248,7 +248,7 @@ if ($_POST) <select name="deptId"> <option value="" selected >— <?php echo __('Select Department'); ?>—</option> <?php - if($depts=Dept::getDepartments(array('dept_id' => $thisstaff->getDepts()))) { + if($depts=Dept::getPublicDepartments()) { foreach($depts as $id =>$name) { if (!($role = $thisstaff->getRole($id)) || !$role->hasPerm(Ticket::PERM_CREATE) diff --git a/include/upgrader/streams/core.sig b/include/upgrader/streams/core.sig index e791d7b4a64d84a4f7c28ead42d9b5e37d04fc9c..c9ff3a1a56d55b539015b2db0bd2463c280af839 100644 --- a/include/upgrader/streams/core.sig +++ b/include/upgrader/streams/core.sig @@ -1 +1 @@ -526c601bc1748febb192f854699f170a +cce1ba439ea7e50fcb845fd067779088 diff --git a/include/upgrader/streams/core/526c601b-cce1ba43.patch.sql b/include/upgrader/streams/core/526c601b-cce1ba43.patch.sql new file mode 100644 index 0000000000000000000000000000000000000000..a624a52493c4f57dc74f4ee1f3bbd05397f406e1 --- /dev/null +++ b/include/upgrader/streams/core/526c601b-cce1ba43.patch.sql @@ -0,0 +1,32 @@ +/** +* @signature cce1ba439ea7e50fcb845fd067779088 +* @version v1.11.0 +* @title Archive Departments and Help Topics +* +* This patch replaces the isactive field on Help Topics with using the flags field to add a new status called 'archived'. +* It also adds a status field to Departments, allowing Agents to activate, disable, and archive Departments +* through using the flags field +* +* Finally, a flag field is added to the filter table +*/ +Help Topics +UPDATE `%TABLE_PREFIX%help_topic` + SET `flags` = `flags` + 2 + WHERE `isactive` = 1; + +ALTER TABLE `%TABLE_PREFIX%help_topic` + DROP COLUMN `isactive`; + +-- Departments +UPDATE `%TABLE_PREFIX%department` + SET `flags` = `flags` + 4 + WHERE `ispublic` = 1; + +-- Ticket Filters +ALTER TABLE `%TABLE_PREFIX%filter` + ADD `flags` int(10) unsigned DEFAULT '0' AFTER `isactive`; + + -- Finished with patch +UPDATE `%TABLE_PREFIX%config` + SET `value` = 'cce1ba439ea7e50fcb845fd067779088' + WHERE `key` = 'schema_signature' AND `namespace` = 'core'; diff --git a/scp/departments.php b/scp/departments.php index 6e0742199b98550f4c94c9969f526559a437f757..9c34f7f94af4b2857646d7d40a3ee6c3b78711df 100644 --- a/scp/departments.php +++ b/scp/departments.php @@ -19,114 +19,194 @@ $dept=null; if($_REQUEST['id'] && !($dept=Dept::lookup($_REQUEST['id']))) $errors['err']=sprintf(__('%s: Unknown or invalid ID.'), __('department')); -if($_POST){ - switch(strtolower($_POST['do'])){ - case 'update': - if(!$dept){ - $errors['err']=sprintf(__('%s: Unknown or invalid'), __('department')); - }elseif($dept->update($_POST,$errors)){ - $msg=sprintf(__('Successfully updated %s.'), - __('this department')); - }elseif(!$errors['err']){ - $errors['err'] = sprintf('%s %s', - sprintf(__('Unable to update %s.'), __('this department')), - __('Correct any errors below and try again.')); - } - break; - case 'create': - $_dept = Dept::create(); - if(($_dept->update($_POST,$errors))){ - $msg=sprintf(__('Successfully added %s.'),Format::htmlchars($_POST['name'])); - $_REQUEST['a']=null; - }elseif(!$errors['err']){ - $errors['err']=sprintf('%s %s', - sprintf(__('Unable to add %s.'), __('this department')), - __('Correct any errors below and try again.')); - } - break; - case 'mass_process': - if(!$_POST['ids'] || !is_array($_POST['ids']) || !count($_POST['ids'])) { - $errors['err'] = sprintf(__('You must select at least %s.'), - __('one department')); - }elseif(in_array($cfg->getDefaultDeptId(),$_POST['ids'])) { - $errors['err'] = __('You cannot disable/delete a default department. Select a new default department and try again.'); - }else{ - $count=count($_POST['ids']); - switch(strtolower($_POST['a'])) { - case 'make_public': - $sql='UPDATE '.DEPT_TABLE.' SET ispublic=1 ' - .' WHERE dept_id IN ('.implode(',', db_input($_POST['ids'])).')'; - if(db_query($sql) && ($num=db_affected_rows())){ - if($num==$count) - $msg=sprintf(__('Successfully made %s PUBLIC'), - _N('selected department', 'selected departments', $count)); - else - $warn=sprintf(__( - /* Phrase will read: - <a> of <b> <selected objects> made PUBLIC */ - '%1$d of %2$d %3$s made PUBLIC'), $num, $count, - _N('selected department', 'selected departments', $count)); - } else { - $errors['err']=sprintf(__('Unable to make %s PUBLIC.'), - _N('selected department', 'selected departments', $count)); - } - break; - case 'make_private': - $sql='UPDATE '.DEPT_TABLE.' SET ispublic=0 ' - .' WHERE dept_id IN ('.implode(',', db_input($_POST['ids'])).') ' - .' AND dept_id!='.db_input($cfg->getDefaultDeptId()); - if(db_query($sql) && ($num=db_affected_rows())) { - if($num==$count) - $msg = sprintf(__('Successfully made %s PRIVATE'), - _N('selected department', 'selected epartments', $count)); - else - $warn = sprintf(__( - /* Phrase will read: - <a> of <b> <selected objects> made PRIVATE */ - '%1$d of %2$d %3$s made PRIVATE'), $num, $count, + if($_POST){ + switch(strtolower($_POST['do'])){ + case 'update': + if(!$dept){ + $errors['err']=sprintf(__('%s: Unknown or invalid'), __('department')); + }elseif($dept->update($_POST,$errors)){ + if ($_POST["status"] != __('Active')) + Dept::clearInactiveDept($dept->getId()); + + $msg=sprintf(__('Successfully updated %s.'), + __('this department')); + }elseif(!$errors['err']){ + $errors['err'] = sprintf('%s %s', + sprintf(__('Unable to update %s.'), __('this department')), + __('Correct any errors below and try again.')); + } + break; + case 'create': + $_dept = Dept::create(); + if(($_dept->update($_POST,$errors))){ + $msg=sprintf(__('Successfully added %s.'),Format::htmlchars($_POST['name'])); + $_REQUEST['a']=null; + }elseif(!$errors['err']){ + $errors['err']=sprintf('%s %s', + sprintf(__('Unable to add %s.'), __('this department')), + __('Correct any errors below and try again.')); + } + break; + case 'mass_process': + if(!$_POST['ids'] || !is_array($_POST['ids']) || !count($_POST['ids'])) { + $errors['err'] = sprintf(__('You must select at least %s.'), + __('one department')); + }elseif(in_array($cfg->getDefaultDeptId(),$_POST['ids'])) { + $errors['err'] = __('You cannot disable/delete a default department. Select a new default department and try again.'); + }else{ + $count=count($_POST['ids']); + switch(strtolower($_POST['a'])) { + case 'make_public': + $sql='UPDATE '.DEPT_TABLE.' SET ispublic=1 ' + .' WHERE dept_id IN ('.implode(',', db_input($_POST['ids'])).')'; + if(db_query($sql) && ($num=db_affected_rows())){ + if($num==$count) + $msg=sprintf(__('Successfully made %s PUBLIC'), + _N('selected department', 'selected departments', $count)); + else + $warn=sprintf(__( + /* Phrase will read: + <a> of <b> <selected objects> made PUBLIC */ + '%1$d of %2$d %3$s made PUBLIC'), $num, $count, + _N('selected department', 'selected departments', $count)); + } else { + $errors['err']=sprintf(__('Unable to make %s PUBLIC.'), _N('selected department', 'selected departments', $count)); - } else { - $errors['err'] = sprintf(__('Unable to make %s private. Possibly already private!'), - _N('selected department', 'selected departments', $count)); - } - break; - case 'delete': - //Deny all deletes if one of the selections has members in it. - $sql='SELECT count(staff_id) FROM '.STAFF_TABLE - .' WHERE dept_id IN ('.implode(',', db_input($_POST['ids'])).')'; - list($members)=db_fetch_row(db_query($sql)); - if($members) - $errors['err']=__('Departments with agents can not be deleted. Move the agents first.'); - else { - $i=0; - foreach($_POST['ids'] as $k=>$v) { - if($v!=$cfg->getDefaultDeptId() && ($d=Dept::lookup($v)) && $d->delete()) - $i++; } - if($i && $i==$count) - $msg = sprintf(__('Successfully deleted %s.'), + break; + case 'make_private': + $sql='UPDATE '.DEPT_TABLE.' SET ispublic=0 ' + .' WHERE dept_id IN ('.implode(',', db_input($_POST['ids'])).') ' + .' AND dept_id!='.db_input($cfg->getDefaultDeptId()); + if(db_query($sql) && ($num=db_affected_rows())) { + if($num==$count) + $msg = sprintf(__('Successfully made %s PRIVATE'), + _N('selected department', 'selected epartments', $count)); + else + $warn = sprintf(__( + /* Phrase will read: + <a> of <b> <selected objects> made PRIVATE */ + '%1$d of %2$d %3$s made PRIVATE'), $num, $count, + _N('selected department', 'selected departments', $count)); + } else { + $errors['err'] = sprintf(__('Unable to make %s private. Possibly already private!'), _N('selected department', 'selected departments', $count)); - elseif($i>0) - $warn = sprintf(__( - /* Phrase will read: - <a> of <b> <selected objects> deleted */ - '%1$d of %2$d %3$s deleted'), $i, $count, + } + break; + case 'enable': + $depts = Dept::objects()->filter(array( + 'id__in'=>$_POST['ids'], + ))->exclude(array( + 'id'=>$cfg->getDefaultDeptId() + )); + foreach ($depts as $d) { + $d->setFlag(Dept::FLAG_ARCHIVED, false); + $d->setFlag(Dept::FLAG_ACTIVE, true); + if($d->save()) + $num++; + } + + if ($num > 0) { + if($num==$count) + $msg = sprintf(__('Successfully enabled %s'), + _N('selected department', 'selected departments', $count)); + else + $warn = sprintf(__('%1$d of %2$d %3$s enabled'), $num, $count, + _N('selected department', 'selected departments', $count)); + } else { + $errors['err'] = sprintf(__('Unable to enable %s'), _N('selected department', 'selected departments', $count)); - elseif(!$errors['err']) - $errors['err'] = sprintf(__('Unable to delete %s.'), + } + break; + case 'disable': + $depts = Dept::objects()->filter(array( + 'id__in'=>$_POST['ids'], + ))->exclude(array( + 'id'=>$cfg->getDefaultDeptId() + )); + foreach ($depts as $d) { + $d->setFlag(Dept::FLAG_ARCHIVED, false); + $d->setFlag(Dept::FLAG_ACTIVE, false); + if($d->save()) { + $num++; + //set dept_id to default for topics/emails using disabled dept + Dept::clearInactiveDept($d->getId()); + } + } + if ($num > 0) { + if($num==$count) + $msg = sprintf(__('Successfully disabled %s'), + _N('selected department', 'selected departments', $count)); + else + $warn = sprintf(__('%1$d of %2$d %3$s disabled'), $num, $count, + _N('selected department', 'selected departments', $count)); + } else { + $errors['err'] = sprintf(__('Unable to disable %s'), _N('selected department', 'selected departments', $count)); - } - break; - default: - $errors['err']=sprintf('%s - %s', __('Unknown action'), __('Get technical help!')); + } + break; + case 'archive': + $depts = Dept::objects()->filter(array( + 'id__in'=>$_POST['ids'], + ))->exclude(array( + 'id'=>$cfg->getDefaultDeptId() + )); + foreach ($depts as $d) { + $d->setFlag(Dept::FLAG_ARCHIVED, true); + $d->setFlag(Dept::FLAG_ACTIVE, false); + if($d->save()) { + $num++; + //set dept_id to default for topics/emails using archived dept + Dept::clearInactiveDept($d->getId()); + } + } + if ($num > 0) { + if($num==$count) + $msg = sprintf(__('Successfully archived %s'), + _N('selected department', 'selected departments', $count)); + else + $warn = sprintf(__('%1$d of %2$d %3$s archived'), $num, $count, + _N('selected department', 'selected departments', $count)); + } else { + $errors['err'] = sprintf(__('Unable to archive %s'), + _N('selected department', 'departments', $count)); + } + break; + case 'delete': + //Deny all deletes if one of the selections has members in it. + $sql='SELECT count(staff_id) FROM '.STAFF_TABLE + .' WHERE dept_id IN ('.implode(',', db_input($_POST['ids'])).')'; + list($members)=db_fetch_row(db_query($sql)); + if($members) + $errors['err']=__('Departments with agents can not be deleted. Move the agents first.'); + else { + $i=0; + foreach($_POST['ids'] as $k=>$v) { + if($v!=$cfg->getDefaultDeptId() && ($d=Dept::lookup($v)) && $d->delete()) + $i++; + } + if($i && $i==$count) + $msg = sprintf(__('Successfully deleted %s.'), + _N('selected department', 'selected departments', $count)); + elseif($i>0) + $warn = sprintf(__( + /* Phrase will read: + <a> of <b> <selected objects> deleted */ + '%1$d of %2$d %3$s deleted'), $i, $count, + _N('selected department', 'selected departments', $count)); + elseif(!$errors['err']) + $errors['err'] = sprintf(__('Unable to delete %s.'), + _N('selected department', 'selected departments', $count)); + } + break; + } } - } - break; - default: - $errors['err']=__('Unknown action'); - break; + break; + default: + $errors['err']=__('Unknown action'); + break; + } } -} $page='departments.inc.php'; $tip_namespace = 'staff.department'; @@ -134,6 +214,9 @@ if ($_REQUEST['a'] && $_REQUEST['a'] == 'export') { if (!Dept::export($dept)) $errors['err'] = sprintf(__('Unable to export %s.'), __('Department')); } elseif ($dept || ($_REQUEST['a'] && !strcasecmp($_REQUEST['a'],'add'))) { + if ($dept && ($pid=$dept->getParent()) && !$pid->isActive()) + $warn = sprintf(__('%s is assigned a %s that is not active.'), __('Department'), __('Parent Department')); + $page='department.inc.php'; } diff --git a/scp/filters.php b/scp/filters.php index 9e4d63193bfa370b53ca3135d5c2b16c5d7e20ae..23bbe23e37ae0721eccbf43288dbfc6a77ab0e75 100644 --- a/scp/filters.php +++ b/scp/filters.php @@ -31,6 +31,8 @@ if($_POST){ if(!$filter){ $errors['err']=sprintf(__('%s: Unknown or invalid'), __('ticket filter')); }elseif($filter->update($_POST,$errors)){ + $filter->setFlag(Filter::FLAG_INACTIVE_DEPT, false); + $filter->setFlag(Filter::FLAG_INACTIVE_HT, false); $msg=sprintf(__('Successfully updated %s.'), __('this ticket filter')); }elseif(!$errors['err']){ $errors['err']=sprintf('%s %s', @@ -116,6 +118,22 @@ if($_POST){ $page='filters.inc.php'; $tip_namespace = 'manage.filter'; if($filter || ($_REQUEST['a'] && !strcasecmp($_REQUEST['a'],'add'))) { + if($filter) { + foreach ($filter->getActions() as $A) { + if($A->type == 'dept') + $dept = Dept::lookup($A->parseConfiguration($_POST)['dept_id']); + + if($A->type == 'topic') + $topic = Topic::lookup($A->parseConfiguration($_POST)['topic_id']); + } + } + + if($dept && !$dept->isActive()) + $warn = sprintf(__('%s is assigned a %s that is not active.'), __('Ticket Filter'), __('Department')); + + if($topic && !$topic->isActive()) + $warn = sprintf(__('%s is assigned a %s that is not active.'), __('Ticket Filter'), __('Help Topic')); + $page='filter.inc.php'; } diff --git a/scp/helptopics.php b/scp/helptopics.php index b00c231d500211a30c4ea30d35a2b8c87a7b38d4..281b1c7f15391288944210d31464e4c8ceafc45b 100644 --- a/scp/helptopics.php +++ b/scp/helptopics.php @@ -28,6 +28,9 @@ if($_POST){ if(!$topic){ $errors['err']=sprintf(__('%s: Unknown or invalid'), __('help topic')); }elseif($topic->update($_POST,$errors)){ + if ($_POST["status"] != __('Active')) + Topic::clearInactiveTopic($topic->getId()); + $msg=sprintf(__('Successfully updated %s.'), __('this help topic')); }elseif(!$errors['err']){ @@ -63,11 +66,15 @@ if($_POST){ switch(strtolower($_POST['a'])) { case 'enable': - $num = Topic::objects()->filter(array( - 'topic_id__in' => $_POST['ids'], - ))->update(array( - 'isactive' => true, + $topics = Topic::objects()->filter(array( + 'topic_id__in'=>$_POST['ids'], )); + foreach ($topics as $t) { + $t->setFlag(Topic::FLAG_ARCHIVED, false); + $t->setFlag(Topic::FLAG_ACTIVE, true); + if($t->save()) + $num++; + } if ($num > 0) { if($num==$count) @@ -82,13 +89,20 @@ if($_POST){ } break; case 'disable': - $num = Topic::objects()->filter(array( - 'topic_id__in'=>$_POST['ids'], + $topics = Topic::objects()->filter(array( + 'topic_id__in'=>$_POST['ids'], ))->exclude(array( - 'topic_id'=>$cfg->getDefaultTopicId(), - ))->update(array( - 'isactive' => false, + 'topic_id'=>$cfg->getDefaultTopicId() )); + foreach ($topics as $t) { + $t->setFlag(Topic::FLAG_ARCHIVED, false); + $t->setFlag(Topic::FLAG_ACTIVE, false); + if($t->save()) { + $num++; + //remove topic_id for emails using disabled topic + Topic::clearInactiveTopic($t->getId()); + } + } if ($num > 0) { if($num==$count) $msg = sprintf(__('Successfully disabled %s'), @@ -101,6 +115,33 @@ if($_POST){ _N('selected help topic', 'selected help topics', $count)); } break; + case 'archive': + $topics = Topic::objects()->filter(array( + 'topic_id__in'=>$_POST['ids'], + ))->exclude(array( + 'topic_id'=>$cfg->getDefaultTopicId() + )); + foreach ($topics as $t) { + $t->setFlag(Topic::FLAG_ARCHIVED, true); + $t->setFlag(Topic::FLAG_ACTIVE, false); + if($t->save()) { + $num++; + //remove topic_id for emails using disabled topic + Topic::clearInactiveTopic($t->getId()); + } + } + if ($num > 0) { + if($num==$count) + $msg = sprintf(__('Successfully archived %s'), + _N('selected help topic', 'selected help topics', $count)); + else + $warn = sprintf(__('%1$d of %2$d %3$s archived'), $num, $count, + _N('selected help topic', 'selected help topics', $count)); + } else { + $errors['err'] = sprintf(__('Unable to archive %s'), + _N('selected help topic', 'selected help topics', $count)); + } + break; case 'delete': $i = Topic::objects()->filter(array( 'topic_id__in'=>$_POST['ids'] @@ -150,7 +191,11 @@ if($_POST){ $page='helptopics.inc.php'; $tip_namespace = 'manage.helptopic'; -if($topic || ($_REQUEST['a'] && !strcasecmp($_REQUEST['a'],'add'))) { +if($topic || ($_REQUEST['a'] && !strcasecmp($_REQUEST['a'],'add'))) +{ + if ($topic && ($dept=$topic->getDept()) && !$dept->isActive()) + $warn = sprintf(__('%s is assigned a %s that is not active.'), __('Help Topic'), __('Department')); + $page='helptopic.inc.php'; } diff --git a/scp/staff.php b/scp/staff.php index c2731b9f2d69b7b0ff96d11f35d4c00782c5dd40..97c72edc2c82336a5adfe083edf63cf69e6e60f2 100644 --- a/scp/staff.php +++ b/scp/staff.php @@ -171,7 +171,11 @@ if($_POST){ $page='staffmembers.inc.php'; $tip_namespace = 'staff.agent'; -if ($staff || ($_REQUEST['a'] && !strcasecmp($_REQUEST['a'],'add'))) { +if($staff || ($_REQUEST['a'] && !strcasecmp($_REQUEST['a'],'add'))) { + + if ($staff && ($pdept=$staff->getDept()) && !$pdept->isActive()) + $warn = sprintf(__('%s is assigned a %s that is not active.'), __('Agent'), __('Primary Department')); + $page='staff.inc.php'; } elseif ($_REQUEST['a'] && !strcasecmp($_REQUEST['a'],'export')) { if (!Staff::export()) diff --git a/setup/inc/install-prereq.inc.php b/setup/inc/install-prereq.inc.php index f4346e3f22b8a7c74f005e4dff530950c1ec8e19..97d7a13c48d6332f542e66486d39ee4d7a7f7cc6 100644 --- a/setup/inc/install-prereq.inc.php +++ b/setup/inc/install-prereq.inc.php @@ -9,7 +9,7 @@ if(!defined('SETUPINC')) die('Kwaheri!'); <p><?php echo __('We are delighted you have chosen osTicket for your customer support ticketing system!');?></p> <p><?php echo __("The installer will guide you every step of the way in the installation process. You're minutes away from your awesome customer support system!");?></p> </div> - <h3><?php echo __('Prerequisites');?>:</h3> + <h2><?php echo __('Prerequisites');?></h3> <p><?php echo __("Before we begin, we'll check your server configuration to make sure you meet the minimum requirements to run the latest version of osTicket.");?></p> <h3><?php echo __('Required');?>: <font color="red"><?php echo $errors['prereq']; ?></font></h3> <?php echo __('These items are necessary in order to install and use osTicket.');?> diff --git a/setup/inc/streams/core/install-mysql.sql b/setup/inc/streams/core/install-mysql.sql index 6d5ef523778ea663f14f6d6d94b54030e89d7e47..0a12b389e9c1c6cd29120131dc67fbbbd3ca8a64 100644 --- a/setup/inc/streams/core/install-mysql.sql +++ b/setup/inc/streams/core/install-mysql.sql @@ -295,6 +295,7 @@ CREATE TABLE `%TABLE_PREFIX%filter` ( `id` int(11) unsigned NOT NULL auto_increment, `execorder` int(10) unsigned NOT NULL default '99', `isactive` tinyint(1) unsigned NOT NULL default '1', + `flags` int(10) unsigned DEFAULT '0', `status` int(11) unsigned NOT NULL DEFAULT '0', `match_all_rules` tinyint(1) unsigned NOT NULL default '0', `stop_onmatch` tinyint(1) unsigned NOT NULL default '0', @@ -420,7 +421,6 @@ DROP TABLE IF EXISTS `%TABLE_PREFIX%help_topic`; CREATE TABLE `%TABLE_PREFIX%help_topic` ( `topic_id` int(11) unsigned NOT NULL auto_increment, `topic_pid` int(10) unsigned NOT NULL default '0', - `isactive` tinyint(1) unsigned NOT NULL default '1', `ispublic` tinyint(1) unsigned NOT NULL default '1', `noautoresp` tinyint(3) unsigned NOT NULL default '0', `flags` int(10) unsigned DEFAULT '0',