/** * This function is the start point for configuration of permissions within SimpleDesk. * * @since 2.0 */ function shd_admin_permissions() { global $context, $scripturl, $sourcedir, $settings, $txt, $modSettings; shd_load_all_permission_sets(); loadTemplate('sd_template/SimpleDesk-AdminPermissions'); shd_load_language('sd_language/SimpleDeskPermissions'); $subactions = array('main' => 'shd_admin_role_list', 'createrole' => 'shd_admin_create_role', 'editrole' => 'shd_admin_edit_role', 'saverole' => 'shd_admin_save_role', 'copyrole' => 'shd_admin_copy_role'); $_REQUEST['sa'] = isset($_REQUEST['sa']) && isset($subactions[$_REQUEST['sa']]) ? $_REQUEST['sa'] : 'main'; $subactions[$_REQUEST['sa']](); }
/** * Sets up the profile menu additions. * * @param array $profile_areas Current profile_areas. * * @since 2.0 */ function shd_profile_areas(&$profile_areas) { global $sourcedir, $modSettings, $context, $txt; static $called = false; if ($called) { return; } if (empty($called)) { $called = true; } // SimpleDesk sections. Added here after the initial cleaning is done, so that we can do our own permission checks without arguing with SMF's system (so much) if (empty($modSettings['helpdesk_active'])) { return; } shd_load_language('sd_language/SimpleDeskProfile'); // Put it here so we can reuse it for the left menu a bit $context['helpdesk_menu'] = array('title' => $txt['shd_profile_area'], 'areas' => array('hd_profile' => array('label' => $txt['shd_profile_main'], 'file' => 'sd_source/SimpleDesk-Profile.php', 'function' => 'shd_profile_main', 'enabled' => shd_allowed_to('shd_view_profile_any') || $context['user']['is_owner'] && shd_allowed_to('shd_view_profile_own'), 'permission' => array('own' => array('is_not_guest'), 'any' => array('is_not_guest'))), 'hd_prefs' => array('label' => $txt['shd_profile_preferences'], 'file' => 'sd_source/SimpleDesk-Profile.php', 'function' => 'shd_profile_main', 'enabled' => shd_allowed_to('shd_view_preferences_any') || $context['user']['is_owner'] && shd_allowed_to('shd_view_preferences_own'), 'permission' => array('own' => array('shd_view_preferences_own'), 'any' => array('shd_view_preferences_any'))), 'hd_showtickets' => array('label' => $txt['shd_profile_show_tickets'], 'file' => 'sd_source/SimpleDesk-Profile.php', 'function' => 'shd_profile_main', 'enabled' => $context['user']['is_owner'] && shd_allowed_to('shd_view_ticket_own') || shd_allowed_to('shd_view_ticket_any'), 'permission' => array('own' => array('shd_view_ticket_own'), 'any' => array('shd_view_ticket_any'))), 'hd_permissions' => array('label' => $txt['shd_profile_permissions'], 'file' => 'sd_source/SimpleDesk-Profile.php', 'function' => 'shd_profile_main', 'enabled' => shd_allowed_to('admin_helpdesk'), 'permission' => array('own' => array('admin_helpdesk'), 'any' => array('admin_helpdesk'))), 'hd_actionlog' => array('label' => $txt['shd_profile_actionlog'], 'file' => 'sd_source/SimpleDesk-Profile.php', 'function' => 'shd_profile_main', 'enabled' => empty($modSettings['shd_disable_action_log']) && (shd_allowed_to('shd_view_profile_log_any') || $context['user']['is_owner'] && shd_allowed_to('shd_view_profile_log_own')), 'permission' => array('own' => array('shd_view_profile_log_own'), 'any' => array('shd_view_profile_log_any'))))); // Kill the existing profile menu but save it in a temporary place first. $old_profile_areas = $profile_areas; $profile_areas = array(); // Now, where we add this depends very much on what mode we're in. In HD only mode, we want our menu first before anything else. if (!empty($modSettings['shd_helpdesk_only'])) { require_once $sourcedir . '/Profile-Modify.php'; // Move some stuff around. $context['helpdesk_menu']['areas']['permissions'] = array('label' => $txt['shd_show_forum_permissions'], 'file' => 'Profile-View.php', 'function' => 'showPermissions', 'enabled' => allowedTo('manage_permissions')); $context['helpdesk_menu']['areas']['tracking'] = array('label' => $txt['trackUser'], 'file' => 'Profile-View.php', 'function' => 'tracking', 'subsections' => array('activity' => array($txt['trackActivity'], 'moderate_forum'), 'ip' => array($txt['trackIP'], 'moderate_forum'), 'edits' => array($txt['trackEdits'], 'moderate_forum')), 'enabled' => allowedTo('moderate_forum')); $profile_areas['helpdesk'] = $context['helpdesk_menu']; $profile_areas += $old_profile_areas; unset($profile_areas['info']['areas']['permissions'], $profile_areas['info']['areas']['tracking']); $remove = array('info' => array('summary', 'statistics', 'showposts', 'viewwarning'), 'edit_profile' => array('forumprofile', 'ignoreboards', 'lists', 'notification'), 'profile_action' => array('issuewarning')); if (!empty($modSettings['shd_disable_pm'])) { $remove['profile_action'][] = 'sendpm'; $remove['edit_profile'][] = 'pmprefs'; } foreach ($remove as $area => $items) { foreach ($items as $item) { if (!empty($profile_areas[$area]['areas'][$item])) { $profile_areas[$area]['areas'][$item]['enabled'] = false; } } } $profile_areas['edit_profile']['areas']['theme']['file'] = 'sd_source/SimpleDesk-Profile.php'; $profile_areas['edit_profile']['areas']['theme']['function'] = 'shd_profile_theme_wrapper'; } else { foreach ($old_profile_areas as $area => $details) { if ($area == 'edit_profile') { $profile_areas['helpdesk'] = $context['helpdesk_menu']; } $profile_areas[$area] = $details; } } // Now engage any hooks. call_integration_hook('shd_hook_profilemenu', array(&$profile_areas)); }
/** * The start point for all interaction with the SimpleDesk plugins. * * Directed here from the main administration centre, after permission checks and a few dependencies loaded, this deals solely with managing custom fields. * * @since 2.0 */ function shd_admin_plugins() { global $context, $scripturl, $sourcedir, $settings, $txt, $modSettings; loadTemplate('sd_template/SimpleDesk-AdminPlugins'); shd_load_language('ManageSettings'); loadTemplate(false, array('admin', 'helpdesk_admin')); $context['shd_enabled_plugins'] = !empty($modSettings['shd_enabled_plugins']) ? explode(',', $modSettings['shd_enabled_plugins']) : array(); // 1. Look at the plugin directory and figure out whether or not there are some plugins. $plugins = array(); $plugindir = $sourcedir . '/sd_plugins_source'; $handle = @opendir($plugindir); while ($dir_entry = readdir($handle)) { if (is_dir($plugindir . '/' . $dir_entry) && $dir_entry != '.' && $dir_entry != '..' && file_exists($plugindir . '/' . $dir_entry . '/index.php')) { include_once $plugindir . '/' . $dir_entry . '/index.php'; $function = 'shdplugin_' . $dir_entry; if (function_exists($function)) { $plugins[$dir_entry] = $function(); } } } @closedir($handle); // 2. Figure out what language stuff is going on $master_langlist = array('albanian', 'arabic', 'bangla', 'bulgarian', 'catalan', 'chinese_simplified', 'chinese_traditional', 'croatian', 'czech', 'danish', 'dutch', 'english', 'english_british', 'finnish', 'french', 'galician', 'german', 'hebrew', 'hindi', 'hungarian', 'indonesian', 'italian', 'japanese', 'kurdish_kurmanji', 'kurdish_sorani', 'macedonian', 'malay', 'norwegian', 'persian', 'polish', 'portuguese_brazilian', 'portuguese_pt', 'romanian', 'russian', 'serbian_cyrillic', 'serbian_latin', 'slovak', 'spanish_es', 'spanish_latin', 'swedish', 'thai', 'turkish', 'ukrainian', 'urdu', 'uzbek_latin', 'vietnamese'); $langtemplates = array(); $langfilelist = @opendir($settings['default_theme_dir'] . '/languages/sd_plugins_lang/'); while ($langfile_entry = readdir($langfilelist)) { if (preg_match('~([a-z0-9]+)\\.([a-z\\-\\_]+)(-utf8)?\\.php$~i', $langfile_entry, $matches)) { $langtemplates[$matches[1]][$matches[2]] = true; } } @closedir($langfilelist); // 3. Figure out what shape the plugins are in foreach ($plugins as $id => $plugin) { // 3.1 Is installable? if (empty($plugins[$id]['details']['compatibility'])) { $plugins[$id]['details']['compatibility'] = array($txt['unknown']); } $plugins[$id]['installable'] = in_array(SHD_VERSION, $plugin['details']['compatibility']); // 3.2 Admin language files? (That also means, let's get a list of known languages for this mod) $plugins[$id]['languages'] = array(); if (!empty($plugin['includes']['language']['hdadmin'])) { $include = is_array($plugin['includes']['language']['hdadmin']) ? $plugin['includes']['language']['hdadmin'] : array($plugin['includes']['language']['hdadmin']); if (!empty($include[0])) { $plugins[$id]['languages'] = array_keys($langtemplates[$include[0]]); } foreach ($include as $langfile) { shd_load_language('sd_plugins_lang/' . $langfile); } } // 3.3 Sort out some strings - now we've loaded the lang file if (!empty($txt[$plugin['details']['title']])) { $plugins[$id]['details']['title'] = $txt[$plugin['details']['title']]; } if (!empty($plugin['details']['description']) && !empty($txt[$plugin['details']['description']])) { $plugins[$id]['details']['description'] = $txt[$plugin['details']['description']]; } if (empty($plugin['details']['author'])) { $plugins[$id]['details']['author'] = $txt['unknown']; } // 3.4 Is it enabled? $plugins[$id]['enabled'] = in_array($id, $context['shd_enabled_plugins']); $plugins[$id]['details']['acp_url'] = !empty($plugin['details']['acp_url']) && $plugins[$id]['enabled'] ? strpos($plugin['details']['acp_url'], 'http') === false ? $scripturl . '?' . $plugin['details']['acp_url'] . ';' . $context['session_var'] . '=' . $context['session_id'] : $plugin['details']['acp_url'] : false; } // 3. Throw it at the template. $context['sub_template'] = 'shd_plugin_listing'; $context['plugins'] = $plugins; $context['page_title'] = $txt['shd_admin_plugins']; // 4. Are we saving any changes? if (isset($_POST['save'])) { checkSession(); $list_of_settings = shd_list_hooks(); $setting_changes = array(); foreach ($list_of_settings as $item) { $setting_changes[$item] = array(); } $post_var_prefix = empty($_POST['js_worked']) ? 'feature_plain_' : 'feature_'; foreach ($plugins as $id => $plugin) { if (empty($plugin['installable'])) { continue; } // GET OUT YE WRONGLY VERSIONED SHI--STUFF // Is it enabled, if so, go do the voodoo that you do so well!!!! if (!empty($_POST[$post_var_prefix . $id])) { $setting_changes['shd_enabled_plugins'][] = $id; foreach ($plugin['includes']['source'] as $include_point => $include_file) { if (isset($setting_changes['shd_include_' . $include_point]) && file_exists($sourcedir . '/sd_plugins_source/' . $id . '/' . $include_file)) { $setting_changes['shd_include_' . $include_point][] = $id . '/' . $include_file; } } foreach ($plugin['includes']['language'] as $include_point => $include_file) { if (isset($setting_changes['shd_includelang_' . $include_point])) { $setting_changes['shd_includelang_' . $include_point][] = $include_file; } } foreach ($plugin['hooks'] as $include_point => $function) { if (isset($setting_changes['shd_hook_' . $include_point])) { $setting_changes['shd_hook_' . $include_point][] = $function; } } } // Is there a call back for settings? if (isset($plugin['setting_callback'])) { $returned_settings = $plugin['setting_callback'](!empty($_POST[$post_var_prefix . $id])); if (!empty($returned_settings)) { $setting_changes = array_merge($setting_changes, $returned_settings); } } // Standard save callback? if (isset($plugin['on_save'])) { $plugin['on_save'](); } } // OK, so whatever we have at this point, we know we're going to be implode'ing and saving. foreach ($setting_changes as $setting => $array) { $setting_changes[$setting] = implode(',', $array); } updateSettings($setting_changes); // Any post save things? foreach ($plugins as $id => $plugin) { // Standard save callback? if (isset($plugin['save_callback'])) { $plugin['save_callback'](!empty($_POST[$post_var_prefix . $id])); } } redirectexit('action=admin;area=helpdesk_plugins;' . $context['session_var'] . '=' . $context['session_id']); } }
/** * Adds the SimpleDesk action to the action list, and also handles most of the shutting down of forum items in helpdesk-only mode. * * @param string &$actionArray The master list of actions from index.php * * @since 2.0 */ function shd_init_actions(&$actionArray) { global $modSettings, $context; if (empty($modSettings['helpdesk_active'])) { return; } // Deal with SimpleDesk. If we're enabling HD only mode, rebuild everything, otherwise just add it to the array. $actionArray['helpdesk'] = array('sd_source/SimpleDesk.php', 'shd_main'); // Rewrite the array for unread purposes. $context['shd_unread_actions'] = array('unread' => $actionArray['unread'], 'unreadreplies' => $actionArray['unreadreplies']); $actionArray['unread'] = array('sd_source/SimpleDesk-Unread.php', 'shd_unread_posts'); $actionArray['unreadreplies'] = array('sd_source/SimpleDesk-Unread.php', 'shd_unread_posts'); // If we're going to a help page (for admin), make sure to load the relevant text. if (isset($_REQUEST['action']) && $_REQUEST['action'] == 'helpadmin') { shd_load_language('sd_language/SimpleDeskAdmin'); } if (!empty($modSettings['shd_helpdesk_only'])) { // Firstly, remove all the standard actions we neither want nor need. // Note we did this to prevent breakage of other mods that may be installed, e.g. gallery or portal or something. $unwanted_actions = array('announce', 'attachapprove', 'buddy', 'calendar', 'clock', 'collapse', 'deletemsg', 'display', 'editpoll', 'editpoll2', 'emailuser', 'lock', 'lockvoting', 'markasread', 'mergetopics', 'moderate', 'modifycat', 'modifykarma', 'movetopic', 'movetopic2', 'notify', 'notifyboard', 'post', 'post2', 'printpage', 'quotefast', 'quickmod', 'quickmod2', 'recent', 'removepoll', 'removetopic2', 'reporttm', 'restoretopic', 'search', 'search2', 'sendtopic', 'smstats', 'splittopics', 'stats', 'sticky', 'about:mozilla', 'about:unknown', 'unread', 'unreadreplies', 'vote', 'viewquery', 'who', '.xml', 'xmlhttp'); // that's the generic stuff, now for specific options if (!empty($modSettings['shd_disable_pm'])) { $unwanted_actions[] = 'pm'; } if (!empty($modSettings['shd_disable_mlist'])) { $unwanted_actions[] = 'mlist'; } foreach ($unwanted_actions as $unwanted) { if (isset($actionArray[$unwanted])) { unset($actionArray[$unwanted]); } } // Secondly, rewrite the defaults to point to helpdesk, for unknown actions. I'm doing this rather than munging the main code - easier to unbreak stuff if (empty($actionArray[$_GET['action']])) { $_GET['action'] = 'helpdesk'; } } // Now engage any SD specific hooks. call_integration_hook('shd_hook_actions', array(&$actionArray)); // Lastly, any other-action-specific hooks? if (!empty($_GET['action']) && !empty($actionArray[$_GET['action']])) { shd_load_plugin_files('action_' . $_GET['action']); shd_load_plugin_langfiles('action_' . $_GET['action']); call_integration_hook('shd_hook_action' . $_GET['action'], array(&$actionArray)); } $context['master_action_list'] = array_keys($actionArray); }
function shd_profile_actionlog($memID) { global $context, $txt, $scripturl, $sourcedir, $user_info, $settings; loadTemplate('sd_template/SimpleDesk-Profile'); shd_load_language('sd_language/SimpleDeskProfile'); require_once $sourcedir . '/sd_source/Subs-SimpleDeskAdmin.php'; $context['action_log'] = shd_load_action_log_entries(-1, 10, '', '', 'la.id_member = ' . $memID); $context['action_log_count'] = shd_count_action_log_entries('la.id_member = ' . $memID); $context['action_full_log'] = allowedTo('admin_forum') || shd_allowed_to('admin_helpdesk', 0); $context['page_title'] = $txt['shd_profile_area'] . ' - ' . $txt['shd_profile_actionlog']; $context['sub_template'] = 'shd_profile_actionlog'; }
/** * Load the form up for asking users what board they want to go to. * * Validates the user permission and session, then displays a list of boards the user can create new topics in. * * Accessed through action=helpdesk;sa=tickettotopic;ticket=x;sessvar=sessid * * @see shd_tickettotopic2() * @since 1.0 */ function shd_tickettotopic() { global $smcFunc, $context, $user_info, $sourcedir, $txt, $modSettings, $scripturl; checkSession('get'); if (empty($context['ticket_id'])) { fatal_lang_error('shd_no_ticket'); } // Get ticket details - and kick it out if they shouldn't be able to see it. $query = shd_db_query('', ' SELECT id_member_started, id_member_assigned, private, subject, deleted_replies, hdt.id_dept, hdd.dept_name FROM {db_prefix}helpdesk_tickets AS hdt INNER JOIN {db_prefix}helpdesk_depts AS hdd ON (hdt.id_dept = hdd.id_dept) WHERE {query_see_ticket} AND id_ticket = {int:ticket}', array('ticket' => $context['ticket_id'])); if ($row = $smcFunc['db_fetch_row']($query)) { list($ticket_starter, $ticket_owner, $private, $subject, $deleted_replies, $dept, $dept_name) = $row; $smcFunc['db_free_result']($query); } else { $smcFunc['db_free_result']($query); fatal_lang_error('shd_no_ticket'); } if (!shd_allowed_to('shd_ticket_to_topic', $dept) || !empty($modSettings['shd_helpdesk_only']) || !empty($modSettings['shd_disable_tickettotopic'])) { fatal_lang_error('shd_cannot_move_ticket', false); } // Hang on... are there any deleted replies? if ($deleted_replies > 0) { if (shd_allowed_to('shd_access_recyclebin', $dept)) { $context['deleted_prompt'] = true; } else { fatal_lang_error('shd_cannot_move_ticket_with_deleted'); } } // In a department, for the linktree? if ($context['shd_multi_dept']) { $context['linktree'][] = array('url' => $scripturl . '?' . $context['shd_home'] . ';dept=' . $dept, 'name' => $dept_name); } // Build the linktree $context['linktree'][] = array('url' => $scripturl . '?' . $context['shd_home'] . ($context['shd_multi_dept'] ? ';dept=' . $dept : ''), 'name' => $txt['shd_linktree_move_ticket']); $context['linktree'][] = array('url' => $scripturl . '?action=helpdesk;sa=ticket;ticket=' . $context['ticket_id'], 'name' => $subject); // They should only be able to move it to boards they are allowed to post in. $allowedboards = boardsAllowedTo('post_new'); if ($allowedboards[0] == 0) { $allowedboards = ''; } // They can access everything. // All good, now figure out what board(s) they can move it to. (MoveTopic.php style 0-:D) $request = shd_db_query('order_by_board_order', ' SELECT b.id_board, b.name, b.child_level, c.name AS cat_name, c.id_cat FROM {db_prefix}boards AS b LEFT JOIN {db_prefix}categories AS c ON (c.id_cat = b.id_cat) WHERE {query_see_board} AND b.redirect = {string:blank_redirect} ' . (!empty($allowedboards) ? 'AND id_board IN({array_int:allowed_boards})' : ''), array('blank_redirect' => '', 'allowed_boards' => $allowedboards)); $context['boards'] = array(); while ($row = $smcFunc['db_fetch_assoc']($request)) { if (!isset($context['categories'][$row['id_cat']])) { $context['categories'][$row['id_cat']] = array('name' => strip_tags($row['cat_name']), 'boards' => array()); } $context['categories'][$row['id_cat']]['boards'][] = array('id' => $row['id_board'], 'name' => strip_tags($row['name']), 'category' => strip_tags($row['cat_name']), 'child_level' => $row['child_level']); } $smcFunc['db_free_result']($request); if (empty($context['categories'])) { fatal_lang_error('shd_moveticket_noboards', false); } // OK, now we got to check for custom fields. In any case, we need to fetch the list of fields that might be applicable to this ticket. shd_load_language('sd_language/SimpleDeskAdmin'); $context['field_types'] = array(CFIELD_TYPE_TEXT => array($txt['shd_admin_custom_fields_ui_text'], 'text'), CFIELD_TYPE_LARGETEXT => array($txt['shd_admin_custom_fields_ui_largetext'], 'largetext'), CFIELD_TYPE_INT => array($txt['shd_admin_custom_fields_ui_int'], 'int'), CFIELD_TYPE_FLOAT => array($txt['shd_admin_custom_fields_ui_float'], 'float'), CFIELD_TYPE_SELECT => array($txt['shd_admin_custom_fields_ui_select'], 'select'), CFIELD_TYPE_CHECKBOX => array($txt['shd_admin_custom_fields_ui_checkbox'], 'checkbox'), CFIELD_TYPE_RADIO => array($txt['shd_admin_custom_fields_ui_radio'], 'radio'), CFIELD_TYPE_MULTI => array($txt['shd_admin_custom_fields_ui_multi'], 'multi')); $query = $smcFunc['db_query']('', ' SELECT hdcf.id_field, hdcf.field_name, hdcf.field_order, hdcf.field_type, hdcf.can_see FROM {db_prefix}helpdesk_custom_fields_depts AS hdd INNER JOIN {db_prefix}helpdesk_custom_fields AS hdcf ON (hdd.id_field = hdcf.id_field) WHERE hdd.id_dept = {int:dept} AND hdcf.active = {int:active} ORDER BY hdcf.field_order', array('dept' => $dept, 'active' => 1)); $context['custom_fields'] = array(); $is_staff = shd_allowed_to('shd_staff', $dept); $is_admin = shd_allowed_to('admin_helpdesk', $dept); while ($row = $smcFunc['db_fetch_assoc']($query)) { list($user_see, $staff_see) = explode(',', $row['can_see']); $context['custom_fields'][$row['id_field']] = array('id_field' => $row['id_field'], 'name' => $row['field_name'], 'type' => $row['field_type'], 'visible' => array('user' => $user_see, 'staff' => $staff_see, 'admin' => true), 'values' => array()); } $smcFunc['db_free_result']($query); // Having got all the possible fields for this ticket, let's fetch the values for it. That way if we don't have any values for a field, we don't have to care about showing the user. // But first, we need all the message ids. $context['ticket_messages'] = array(); $query = $smcFunc['db_query']('', ' SELECT id_msg FROM {db_prefix}helpdesk_ticket_replies AS hdtr WHERE id_ticket = {int:ticket}', array('ticket' => $context['ticket_id'])); while ($row = $smcFunc['db_fetch_row']($query)) { $context['ticket_messages'][] = $row[0]; } $smcFunc['db_free_result']($query); // Now get a reference for the field values. $query = shd_db_query('', ' SELECT cfv.id_post, cfv.id_field, cfv.post_type FROM {db_prefix}helpdesk_custom_fields_values AS cfv WHERE (cfv.id_post = {int:ticket} AND cfv.post_type = 1)' . (!empty($context['ticket_messages']) ? ' OR (cfv.id_post IN ({array_int:msgs}) AND cfv.post_type = 2)' : ''), array('ticket' => $context['ticket_id'], 'msgs' => $context['ticket_messages'])); while ($row = $smcFunc['db_fetch_assoc']($query)) { if (isset($context['custom_fields'][$row['id_field']])) { $context['custom_fields'][$row['id_field']]['values'][$row['post_type']][$row['id_post']] = true; } } $smcFunc['db_free_result']($query); // Having now established what fields we do actually have values for, let's proceed to deal with them. foreach ($context['custom_fields'] as $field_id => $field) { // Didn't we have any values? If not, prune it, not interested. if (empty($field['values'])) { unset($context['custom_fields'][$field_id]); } // If the user is an administrator, they can always see the fields. if ($is_admin) { // But users might not be able to, in which case warn the user. if (!$field['visible']['user'] || !$field['visible']['staff']) { $context['custom_fields'][$field_id]['visible_warn'] = true; $context['custom_fields_warning'] = true; } } elseif ($is_staff) { // So they're staff. But the field might not be visible to them; they can't deal with it. if (!$field['visible']['staff']) { fatal_lang_error('cannot_shd_move_ticket_topic_hidden_cfs', false); } elseif (!$field['visible']['user']) { // Normal mortals can't see it even if this person can, so warn them. $context['custom_fields'][$field_id]['visible_warn'] = true; $context['custom_fields_warning'] = true; } } else { // Non staff aren't special. They should not be able to make this decision. If someone can't see it, they don't get to make the choice. if (!$field['visible']['user'] || !$field['visible']['staff']) { fatal_lang_error('cannot_shd_move_ticket_topic_hidden_cfs', false); } } } // Store the ticket subject for the template $context['ticket_subject'] = $subject; loadTemplate('sd_template/SimpleDesk-TicketTopicMove'); $context['sub_template'] = 'shd_tickettotopic'; $context['page_title'] = $txt['shd_move_ticket_to_topic']; checkSubmitOnce('register'); }
/** * Provide the list of possible notification recipients. * * @since 2.0 */ function shd_ajax_notify() { global $txt, $context, $smcFunc, $user_profile, $modSettings, $sourcedir; $session_check = checkSession('get', '', false); // check the session but don't die fatally. if (!empty($session_check)) { return $context['ajax_return'] = array('error' => $txt[$session_check]); } shd_load_language('sd_language/SimpleDeskNotifications'); require_once $sourcedir . '/sd_source/SimpleDesk-Notifications.php'; if (!empty($context['ticket_id'])) { $query = shd_db_query('', ' SELECT hdt.private, hdt.id_member_started, id_member_assigned, id_dept, status FROM {db_prefix}helpdesk_tickets AS hdt WHERE {query_see_ticket} AND hdt.id_ticket = {int:ticket}', array('ticket' => $context['ticket_id'])); if ($smcFunc['db_num_rows']($query) != 0) { $ticket = $smcFunc['db_fetch_assoc']($query); } $smcFunc['db_free_result']($query); } if (empty($ticket) || !shd_allowed_to('shd_singleton_email', $ticket['id_dept']) || $ticket['status'] == TICKET_STATUS_CLOSED || $ticket['status'] == TICKET_STATUS_DELETED) { return $context['ajax_return'] = array('error' => $txt['shd_no_ticket']); } // So, we need to start figuring out who's going to be notified, who won't be and who we might be interested in notifying. $notify_list = array('being_notified' => array(), 'optional' => array(), 'optional_butoff' => array()); // Let's get all the possible actual people. The possible people who can be notified... well, they're staff. $staff = shd_get_visible_list($ticket['id_dept'], $ticket['private'], $ticket['id_member_started'], empty($modSettings['shd_admins_not_assignable']), false); // Let's start figuring it out then! First, get the big ol' lists. $query = $smcFunc['db_query']('', ' SELECT id_member, notify_state FROM {db_prefix}helpdesk_notify_override WHERE id_ticket = {int:ticket}', array('ticket' => $context['ticket_id'])); while ($row = $smcFunc['db_fetch_assoc']($query)) { $notify_list[$row['notify_state'] == NOTIFY_NEVER ? 'optional_butoff' : 'being_notified'][$row['id_member']] = true; } // Did we exclude admins? If we did, we would have scooped the list of admins. If they're in the 'not being notified but you can...' list, remove them. if (!empty($context['list_admin_exclude'])) { foreach ($context['list_admin_exclude'] as $user_id) { if (isset($notify_list['optional_butoff'][$user_id])) { unset($notify_list['optional_butoff'][$user_id]); } } } // Now we get the list by preferences. This is where it starts to get complicated. $possible_members = array(); // People who want replies to their own ticket, without including the ticket starter because they'd know about it... if (!empty($modSettings['shd_notify_new_reply_own']) && $context['user']['id'] != $ticket['id_member_started']) { $possible_members[$ticket['id_member_started']]['new_reply_own'] = true; } // The ticket is assigned to someone and they want to be notified if it changes. if (!empty($modSettings['shd_notify_new_reply_assigned']) && !empty($ticket['id_member_assigned']) && $context['user']['id'] != $ticket['id_member_assigned']) { $possible_members[$ticket['id_member_assigned']]['new_reply_assigned'] = true; } // So, if you're staff, and you've replied to this ticket before, do you want to be notified this time? if (!empty($modSettings['shd_notify_new_reply_previous'])) { $query = $smcFunc['db_query']('', ' SELECT id_member FROM {db_prefix}helpdesk_ticket_replies WHERE id_ticket = {int:ticket} GROUP BY id_member', array('ticket' => $context['ticket_id'])); $responders = array(); while ($row = $smcFunc['db_fetch_row']($query)) { $responders[] = $row[0]; } // this shouldn't be nil, ever, because we're replying, so the topic already exists so there's at least one name in there... $smcFunc['db_free_result']($query); $responders = array_intersect($responders, $staff); foreach ($responders as $id) { $possible_members[$id]['new_reply_previous'] = true; } } // If you're staff, did you have 'spam my inbox every single time' selected? if (!empty($modSettings['shd_notify_new_reply_any'])) { foreach ($staff as $id) { $possible_members[$id]['new_reply_any'] = true; } } // Now we have the list of possibles, exclude everyone who is either set to on, or off, since we don't need to query those for preferences. foreach ($possible_members as $id => $type_list) { if (isset($notify_list['being_notified'][$id]) || isset($notify_list['optional_butoff'][$id])) { unset($possible_members[$id]); } } if (!empty($possible_members)) { // Get the default preferences $prefs = shd_load_user_prefs(false); $pref_groups = $prefs['groups']; $base_prefs = $prefs['prefs']; // Build a list of users -> default prefs. We know this is for the list of possible contenders only. $member_prefs = array(); $pref_list = array(); foreach ($possible_members as $id => $type_list) { foreach ($type_list as $type => $value) { $member_prefs[$id][$type] = $base_prefs['notify_' . $type]['default']; $pref_list['notify_' . $type] = true; } } // Grab pref list from DB for these users and update $query = $smcFunc['db_query']('', ' SELECT id_member, variable, value FROM {db_prefix}helpdesk_preferences WHERE id_member IN ({array_int:members}) AND variable IN ({array_string:variables})', array('members' => array_keys($possible_members), 'variables' => array_keys($pref_list))); while ($row = $smcFunc['db_fetch_assoc']($query)) { $row['id_member'] = (int) $row['id_member']; $variable = substr($row['variable'], 7); if (isset($member_prefs[$row['id_member']][$variable])) { $member_prefs[$row['id_member']][$variable] = $row['value']; } } $smcFunc['db_free_result']($query); // unset $members where member pref doesn't indicate they want it on. foreach ($member_prefs as $id => $value) { foreach ($value as $pref_id => $pref_item) { if (empty($pref_item)) { unset($possible_members[$id][$pref_id]); } } } // Now, it's possible that we have a ticket that the starter can't see, but that their preferences would indicate they'd like a reply. // What should be done here is to remove them from the automatic list, and make them part of the ping list instead. if (!empty($ticket['id_member_started']) && !in_array($ticket['id_member_started'], $staff)) { $possible_members[$ticket['id_member_started']] = array(); } // Now the clever bit, we've taken everyone who wasn't on the normal notify list, and figured out what their preferences are. // We now traverse $possible_members by id, if the array is empty, we know none of their preferences accounted for emails - so they're possible. // Otherwise we add them to the list of being notified. foreach ($possible_members as $id => $list) { if (empty($list)) { $notify_list['optional'][$id] = true; } else { $notify_list['being_notified'][$id] = true; } } } // By now we have three lists that include people who will be notified, people who could be notified, and people who don't really want to be. // Let's translate that into a list of people that we can make use of. $members = array_merge(array_keys($notify_list['being_notified']), array_keys($notify_list['optional']), array_keys($notify_list['optional_butoff'])); if (!empty($members)) { // Get everyone's name. $loaded = loadMemberData($members); foreach ($loaded as $user) { if (!empty($user_profile[$user]) && $user_profile[$user]['is_activated'] > 0 && $user_profile[$user]['is_activated'] < 10) { // active & not banned $people[$user] = array('id' => $user, 'name' => $user_profile[$user]['real_name']); } } // Right, now let's step through and tidy up the three lists foreach ($notify_list as $list_type => $list_members) { foreach ($list_members as $id_member => $data) { if (isset($people[$id_member]) && $id_member != $context['user']['id']) { // We really shouldn't be in this list. $list_members[$id_member] = $people[$id_member]['name']; } else { unset($list_members[$id_member]); } } if (!empty($list_members)) { asort($list_members); array_walk($list_members, 'shd_format_notify_name', $ticket['id_member_started']); $notify_list[$list_type] = $list_members; } else { unset($notify_list[$list_type]); } } } if (empty($notify_list) || empty($members)) { return $context['ajax_raw'] = '<notify><![C' . 'DATA[' . cleanXml($txt['shd_ping_none']) . ']' . ']></notify>'; } else { ob_start(); echo '<notify><![C', 'DATA['; $selected = array(); if (!empty($_GET['list'])) { $_GET['list'] = explode(',', $_GET['list']); foreach ($_GET['list'] as $id) { if ((int) $id > 0) { $selected[] = (int) $id; } } } if (!empty($notify_list['being_notified'])) { echo '<span class="shd_ajax_head">', $txt['shd_ping_already_' . (count($notify_list['being_notified']) == 1 ? '1' : 'n')], '</span><br />', implode(', ', $notify_list['being_notified']); } if (!empty($notify_list['optional'])) { if (!empty($notify_list['being_notified'])) { echo '<br /><br />'; } echo '<span class="shd_ajax_head">', $txt['shd_ping_' . (count($notify_list['optional']) == 1 ? '1' : 'n')], '</span><br />'; foreach ($notify_list['optional'] as $id => $member) { echo '<div class="shd_ajaxnotify"><input type="checkbox" name="notify[', $id, ']" value="', $id, '"', in_array($id, $selected) ? ' checked="checked"' : '', ' class="input_check" /> ', $member, '</div>'; } } if (!empty($notify_list['optional_butoff'])) { if (!empty($notify_list['being_notified']) || !empty($notify_list['optional_butoff'])) { echo '<br /><br />'; } echo '<span class="shd_ajax_head">', $txt['shd_ping_none_' . (count($notify_list['optional_butoff']) == 1 ? '1' : 'n')], '</span><br />'; foreach ($notify_list['optional_butoff'] as $id => $member) { echo '<div class="shd_ajaxnotify"><input type="checkbox" name="notify[', $id, ']" value="', $id, '"', in_array($id, $selected) ? ' checked="checked"' : '', ' class="input_check" /> ', $member, '</div>'; } } echo ']', ']></notify>'; $content = ob_get_clean(); return $context['ajax_raw'] = cleanXml($content); } }
/** * Add the SimpleDesk option into the Core Features page inside the admin panel. * * @param array &$core_features The array of Core Features as provided by ManageSettings.php */ function shd_admin_core_features(&$core_features) { $temp = $core_features; $core_features = array(); shd_load_language('sd_language/SimpleDeskAdmin'); foreach ($temp as $k => $v) { // Insert it before the moderation log if ($k == 'ml') { $core_features['shd'] = array('url' => 'action=admin;area=helpdesk_info'); } $core_features[$k] = $v; } }
/** * Intergrates into SMF's admin search. * * @since 2.0 * @param array &$language_files language files to include. * @param array &$include_files Files to load. * @param array &$settings_search Settings to search. */ function shd_admin_search(&$language_files, &$include_files, &$settings_search) { // Add in language files. shd_load_language('sd_language/SimpleDeskAdmin'); $include_files = array_merge($include_files, array('sd_source/SimpleDesk-Admin')); // Add SimpleDesk functions $settings_search = array_merge($settings_search, array(array('shd_modify_display_options', 'area=helpdesk_options;sa=display'), array('shd_modify_posting_options', 'area=helpdesk_options;sa=posting'), array('shd_modify_admin_options', 'area=helpdesk_options;sa=admin'), array('shd_modify_standalone_options', 'area=helpdesk_options;sa=standalone'), array('shd_modify_actionlog_options', 'area=helpdesk_options;sa=actionlog'), array('shd_modify_notifications_options', 'area=helpdesk_options;sa=notifications'))); // Our plugins may still use the old SHD hook. call_integration_hook('shd_hook_hdadminoptssrch', array(&$settings_search)); }
/** * Display the notice of email. * * @todo Finish documenting * @since 2.0 */ function shd_notify_popup() { global $txt, $context, $settings, $modSettings, $smcFunc, $user_profile, $user_info, $scripturl; // First, verify we got a log entry, that the log entry is right, and it points to a ticket we can actually see. $_GET['log'] = isset($_GET['log']) ? (int) $_GET['log'] : 0; $email_type = isset($_GET['template']) ? preg_replace('~[^a-z_]~', '', $_GET['template']) : ''; if (empty($modSettings['shd_display_ticket_logs']) || empty($_GET['log']) || empty($email_type)) { fatal_lang_error('no_access', false); } $query = $smcFunc['db_query']('', ' SELECT hdla.id_member, hdla.id_ticket, hdla.id_msg, hdla.extra, IFNULL(hdtr.body, {string:empty}) AS body, IFNULL(mem.real_name, hdtr.poster_name) AS poster_name FROM {db_prefix}helpdesk_log_action AS hdla LEFT JOIN {db_prefix}helpdesk_ticket_replies AS hdtr ON (hdla.id_msg = hdtr.id_msg) LEFT JOIN {db_prefix}members AS mem ON (hdtr.id_member = mem.id_member) WHERE id_action = {int:log} AND action = {string:notify}', array('log' => $_GET['log'], 'notify' => 'notify', 'empty' => '')); if ($smcFunc['db_num_rows']($query) == 0) { $smcFunc['db_free_result']($query); fatal_lang_error('no_access'); } $row = $smcFunc['db_fetch_assoc']($query); $smcFunc['db_free_result']($query); $row['extra'] = unserialize($row['extra']); // Just check we did actually log an email of that type. if (empty($row['extra']['emails'][$_GET['template']])) { fatal_lang_error('no_access', false); } $ticketinfo = shd_load_ticket($row['id_ticket']); // OK, if we're here, we can see the ticket. Can we actually see the email log at this point? if (!shd_allowed_to('shd_view_ticket_logs_any', $ticketinfo['dept']) && (!shd_allowed_to('shd_view_ticket_logs_own', $ticketinfo['dept']) || !$ticketinfo['is_own'])) { fatal_lang_error('no_access', false); } // We're reusing the Help template, need its language file. loadLanguage('Help'); shd_load_language('sd_language/SimpleDeskAdmin'); shd_load_language('sd_language/SimpleDeskLogAction'); shd_load_language('sd_language/SimpleDeskNotifications'); // Set the page up loadTemplate('Help'); $context['page_title'] = $context['forum_name'] . ' - ' . $txt['shd_log_notifications']; $context['template_layers'] = array(); $context['sub_template'] = 'popup'; $users = array(); // First, get the list of users, and load their username etc if we haven't already attempted it before. if (isset($row['extra']['emails'][$email_type]['u'])) { $users = array_merge($users, explode(',', $row['extra']['emails'][$email_type]['u'])); } if (!empty($users)) { $users = array_unique($users); if (!empty($users)) { loadMemberData($users, false, 'minimal'); } } // Now we have all the usernames for this instance, let's go and build this entry. $context['help_text'] = $txt['shd_log_notify_to'] . '<br />'; $new_content = ''; if (!empty($users)) { $first = true; foreach ($users as $user) { if (empty($user_profile[$user])) { continue; } $new_content .= ($first ? '<img src="' . shd_image_url('user.png') . '" alt="" /> ' : ', ') . shd_profile_link($user_profile[$user]['real_name'], $user); $first = false; } } if (!empty($row['extra']['emails'][$email_type]['e'])) { $emails = explode(',', $row['extra']['emails'][$email_type]['e']); // Admins can see the actual emails. if (shd_allowed_to('admin_helpdesk', 0) || $user_info['is_admin']) { foreach ($emails as $key => $value) { $emails[$key] = '<a href="mailto:' . $value . '">' . $value . '</a>'; } $new_content .= '<img src="' . shd_image_url('log_notify.png') . '" alt="" /> ' . implode(', ', $emails); } else { $new_content .= '<img src="' . shd_image_url('log_notify.png') . '" alt="" /> ' . (count($emails) == 1 ? $txt['shd_log_notify_hiddenemail_1'] : sprintf($txt['shd_log_notify_hiddenemail'], count($emails))); } } if (!empty($new_content)) { $context['help_text'] .= $new_content; } $context['help_text'] .= '<hr />'; // So the general prep is done. Now let's rebuild the email contents. if (empty($row['extra']['withbody']) || empty($row['body'])) { $body = ''; } else { $body = trim(un_htmlspecialchars(strip_tags(strtr(shd_format_text($row['body'], false), array('<br />' => "\n", '</div>' => "\n", '</li>' => "\n", '[' => '[', ']' => ']'))))); } $replacements = array("\n" => '<br />', '{ticket_id}' => str_pad($row['id_ticket'], $modSettings['shd_zerofill'], '0', STR_PAD_LEFT), '{subject}' => empty($row['extra']['subject']) ? $txt['no_subject'] : $row['extra']['subject'], '{ticketlink}' => $scripturl . '?action=helpdesk;sa=ticket;ticket=' . $row['id_ticket'] . (empty($row['id_msg']) ? '.0' : '.msg' . $row['id_msg'] . '#msg' . $row['id_msg']), '{body}' => $body, '{poster_name}' => $row['poster_name']); $email_subject = str_replace(array_keys($replacements), array_values($replacements), $txt['template_subject_notify_' . $email_type]); $email_body = str_replace(array_keys($replacements), array_values($replacements), $txt['template_' . (empty($row['extra']['withbody']) || empty($row['body']) ? 'body' : 'bodyfull') . '_notify_' . $email_type]); $context['help_text'] .= '<strong>' . $txt['subject'] . ':</strong> ' . $email_subject . '<br /><br />' . $email_body; }
function shd_admin_edit_dept() { global $context, $txt, $smcFunc, $scripturl; shd_load_language('sd_language/SimpleDeskPermissions'); $_REQUEST['dept'] = isset($_REQUEST['dept']) ? (int) $_REQUEST['dept'] : 0; // Get the current department $query = $smcFunc['db_query']('', ' SELECT id_dept, dept_name, description, board_cat, before_after, dept_theme, autoclose_days FROM {db_prefix}helpdesk_depts WHERE id_dept = {int:dept}', array('dept' => $_REQUEST['dept'])); if ($smcFunc['db_num_rows']($query) == 0) { $smcFunc['db_free_result']($query); fatal_lang_error('shd_unknown_dept', false); } $context['shd_dept'] = $smcFunc['db_fetch_assoc']($query); $context['shd_dept']['description'] = htmlspecialchars($context['shd_dept']['description']); $smcFunc['db_free_result']($query); // Get the category list $context['shd_cat_list'] = array(0 => $txt['shd_boardindex_cat_none']); $request = $smcFunc['db_query']('', ' SELECT id_cat, name FROM {db_prefix}categories ORDER BY cat_order'); while ($row = $smcFunc['db_fetch_assoc']($request)) { $context['shd_cat_list'][$row['id_cat']] = $row['name']; } $smcFunc['db_free_result']($request); // Now the role list $query = $smcFunc['db_query']('', ' SELECT id_role, template, role_name FROM {db_prefix}helpdesk_roles ORDER BY id_role'); while ($row = $smcFunc['db_fetch_assoc']($query)) { $context['shd_roles'][$row['id_role']] = $row; } $smcFunc['db_free_result']($query); $query = $smcFunc['db_query']('', ' SELECT id_role FROM {db_prefix}helpdesk_dept_roles WHERE id_dept = {int:dept}', array('dept' => $_REQUEST['dept'])); while ($row = $smcFunc['db_fetch_assoc']($query)) { $context['shd_roles'][$row['id_role']]['in_dept'] = true; } $smcFunc['db_free_result']($query); // And the theme list shd_get_dept_theme_list(); $context['page_title'] = $txt['shd_edit_dept']; $context['sub_template'] = 'shd_edit_dept'; }
/** * Initialises the helpdesk action log. * * This function loads the language strings, and hands off to {@link shd_load_action_log_entries()} to perform the actual log * generation. * * Before doing so, however, this function will also prepare for deletion of old entries, as well as sorting out the columns and * ordering rules before handing control to the other function. * * @since 1.0 */ function shd_admin_action_log() { global $context, $settings, $scripturl, $txt, $sourcedir, $smcFunc, $sort_types; shd_load_language('sd_language/SimpleDeskLogAction'); $context['can_delete'] = allowedTo('admin_forum'); $context['displaypage'] = 30; $context['hoursdisable'] = 24; $context['waittime'] = time() - $context['hoursdisable'] * 3600; // Handle deletion... if (isset($_REQUEST['removeall']) && $context['can_delete']) { shd_db_query('', ' DELETE FROM {db_prefix}helpdesk_log_action WHERE log_time < {int:twenty_four_hours_wait}', array('twenty_four_hours_wait' => $context['waittime'])); } elseif (!empty($_REQUEST['remove']) && $context['can_delete']) { shd_db_query('', ' DELETE FROM {db_prefix}helpdesk_log_action WHERE id_action = {int:gtfo} AND log_time < {int:twenty_four_hours_wait}', array('twenty_four_hours_wait' => $context['waittime'], 'gtfo' => (int) $_REQUEST['remove'])); } // Do the column stuff! $sort_types = array('action' => 'la.action', 'time' => 'la.log_time', 'member' => 'mem.real_name', 'position' => 'mg.group_name', 'ip' => 'la.ip'); // Setup the direction stuff... $context['sort'] = isset($_REQUEST['sort']) && isset($sort_types[$_REQUEST['sort']]) ? $sort_types[$_REQUEST['sort']] : $sort_types['time']; $context['start'] = isset($_REQUEST['start']) ? $_REQUEST['start'] : 0; $context['order'] = isset($_REQUEST['asc']) ? 'ASC' : 'DESC'; $context['url_sort'] = isset($_REQUEST['sort']) ? ';sort=' . $_REQUEST['sort'] : ''; $context['url_order'] = isset($_REQUEST['asc']) ? ';asc' : ''; // Get all action log entries $context['actions'] = shd_load_action_log_entries($context['start'], $context['displaypage'], $context['sort'], $context['order']); $context['page_index'] = shd_no_expand_pageindex($scripturl . '?action=admin;area=helpdesk_info;sa=actionlog' . $context['url_sort'] . $context['url_order'], $context['start'], shd_count_action_log_entries(), $context['displaypage']); $context['sub_template'] = 'shd_action_log'; }