<?php /*

 Composr
 Copyright (c) Christopher Graham, 2004-2024

 See docs/LICENSE.md for full licensing information.


 NOTE TO PROGRAMMERS:
   Do not edit this file. If you need to make changes, save your changed file to the appropriate *_custom folder
   **** If you ignore this advice, then your website upgrades (e.g. for bug fixes) will likely kill your changes ****

*/

/**
 * @license    http://opensource.org/licenses/cpal_1.0 Common Public Attribution License
 * @copyright  Christopher Graham
 * @package    tickets
 */

/**
 * Module page class.
 */
class Module_admin_tickets
{
    /**
     * Find details of the module.
     *
     * @return ?array Map of module info (null: module is disabled)
     */
    public function info() : ?array
    {
        $info = [];
        $info['author'] = 'Chris Graham';
        $info['organisation'] = 'Composr';
        $info['hacked_by'] = null;
        $info['hack_version'] = null;
        $info['version'] = 2;
        $info['locked'] = false;
        $info['min_cms_version'] = 11.0;
        $info['addon'] = 'tickets';
        return $info;
    }

    /**
     * Find entry-points available within this module.
     *
     * @param  boolean $check_perms Whether to check permissions
     * @param  ?MEMBER $member_id The member to check permissions as (null: current user)
     * @param  boolean $support_crosslinks Whether to allow cross links to other modules (identifiable via a full-page-link rather than a screen-name)
     * @param  boolean $be_deferential Whether to avoid any entry-point (or even return null to disable the page in the Sitemap) if we know another module, or page_group, is going to link to that entry-point. Note that "!" and "browse" entry points are automatically merged with container page nodes (likely called by page-groupings) as appropriate.
     * @return ?array A map of entry points (screen-name=>language-code/string or screen-name=>[language-code/string, icon-theme-image]) (null: disabled)
     */
    public function get_entry_points(bool $check_perms = true, ?int $member_id = null, bool $support_crosslinks = true, bool $be_deferential = false) : ?array
    {
        if (!addon_installed('tickets')) {
            return null;
        }

        if (get_forum_type() == 'none') {
            return null;
        }

        return [
            'browse' => ['MANAGE_TICKET_TYPES', 'menu/site_meta/tickets'],
            'email' => ['ADD_TICKET_EMAIL', 'buttons/add_ticket'],
        ];
    }

    public $title;

    /**
     * Module pre-run function. Allows us to know metadata for <head> before we start streaming output.
     *
     * @return ?Tempcode Tempcode indicating some kind of exceptional output (null: none)
     */
    public function pre_run() : ?object
    {
        $error_msg = new Tempcode();
        if (!addon_installed__messaged('tickets', $error_msg)) {
            return $error_msg;
        }

        $type = get_param_string('type', 'browse');

        require_lang('tickets');

        set_helper_panel_tutorial('tut_support_desk');

        if ($type != 'browse') {
            breadcrumb_set_parents([['_SELF:_SELF:browse', do_lang_tempcode('MANAGE_TICKET_TYPES')]]);
        }

        if ($type == 'browse') {
            $this->title = get_screen_title('MANAGE_TICKET_TYPES');
        }

        if ($type == 'add') {
            $this->title = get_screen_title('ADD_TICKET_TYPE');
        }

        if ($type == 'edit') {
            $this->title = get_screen_title('EDIT_TICKET_TYPE');
        }

        if ($type == '_edit') {
            if (post_param_integer('delete', 0) == 1) {
                $this->title = get_screen_title('DELETE_TICKET_TYPE');
            } else {
                $this->title = get_screen_title('EDIT_TICKET_TYPE');
            }
        }

        if (($type == 'email') || ($type == '_email')) {
            $this->title = get_screen_title('ADD_TICKET_EMAIL');
        }

        return null;
    }

    /**
     * Execute the module.
     *
     * @return Tempcode The result of execution
     */
    public function run() : object
    {
        require_css('tickets');

        require_code('tickets');
        require_code('tickets2');

        $type = get_param_string('type', 'browse');

        if ($type == 'browse') {
            return $this->ticket_type_interface();
        }
        if ($type == 'add') {
            return $this->add_ticket_type();
        }
        if ($type == 'edit') {
            return $this->edit_ticket_type();
        }
        if ($type == '_edit') {
            return $this->_edit_ticket_type();
        }
        if ($type == 'email') {
            return $this->send_email_as_ticket();
        }
        if ($type == '_email') {
            return $this->_send_email_as_ticket();
        }

        return new Tempcode();
    }

    /**
     * The UI to choose a ticket type to edit, or to add a ticket.
     *
     * @return Tempcode The UI
     */
    public function ticket_type_interface() : object
    {
        require_lang('permissions');

        $list = new Tempcode();
        require_code('form_templates');
        $ticket_types = collapse_2d_complexity('id', 'ticket_type_name', $GLOBALS['SITE_DB']->query_select('ticket_types', ['*'], [], 'ORDER BY ' . $GLOBALS['SITE_DB']->translate_field_ref('ticket_type_name')));
        foreach ($ticket_types as $ticket_type_id => $ticket_type_name) {
            $list->attach(form_input_list_entry(strval($ticket_type_id), false, get_translated_text($ticket_type_name)));
        }
        if (!$list->is_empty()) {
            $edit_url = build_url(['page' => '_SELF', 'type' => 'edit'], '_SELF', [], false, true);
            $submit_name = do_lang_tempcode('EDIT');
            $fields = form_input_huge_list(do_lang_tempcode('TITLE'), do_lang_tempcode('DESCRIPTION_TICKET_TYPE'), 'ticket_type_id', $list);

            $tpl = do_template('FORM', [
                '_GUID' => '2d2e76f5cfc397a78688db72170918d4',
                'TABINDEX' => strval(get_form_field_tabindex()),
                'GET' => true,
                'HIDDEN' => '',
                'TEXT' => '',
                'FIELDS' => $fields,
                'URL' => $edit_url,
                'SUBMIT_ICON' => 'admin/edit_this_category',
                'SUBMIT_NAME' => $submit_name,
            ]);
        } else {
            $tpl = new Tempcode();
        }

        // Do a form so people can add...

        $post_url = build_url(['page' => '_SELF', 'type' => 'add'], '_SELF');

        $submit_name = do_lang_tempcode('ADD');

        $fields = form_input_line(do_lang_tempcode('TITLE'), do_lang_tempcode('DESCRIPTION_TICKET_TYPE'), 'ticket_type_name_2', '', false);
        $fields->attach(form_input_tick(do_lang_tempcode('TICKET_GUEST_EMAILS_MANDATORY'), do_lang_tempcode('DESCRIPTION_TICKET_GUEST_EMAILS_MANDATORY'), 'guest_emails_mandatory', false));
        $fields->attach(form_input_tick(do_lang_tempcode('TICKET_SEARCH_FAQ'), do_lang_tempcode('DESCRIPTION_TICKET_SEARCH_FAQ'), 'search_faq', false));

        // Permissions
        $fields->attach(do_template('FORM_SCREEN_FIELD_SPACER', ['_GUID' => '87ef39b0a5c3c45c1c1319c7f85d0e2a', 'TITLE' => do_lang_tempcode('PERMISSIONS'), 'SECTION_HIDDEN' => true]));
        $admin_groups = $GLOBALS['FORUM_DRIVER']->get_super_admin_groups();
        $groups = $GLOBALS['FORUM_DRIVER']->get_usergroup_list(false, true);
        foreach ($groups as $id => $group_name) {
            if (in_array($id, $admin_groups)) {
                continue;
            }
            $fields->attach(form_input_tick(do_lang_tempcode('ACCESS_FOR', escape_html($group_name)), do_lang_tempcode('DESCRIPTION_ACCESS_FOR', escape_html($group_name)), 'access_' . strval($id), true));
        }
        if (addon_installed('ecommerce')) {
            require_code('ecommerce_permission_products');
            $fields->attach(permission_product_form('ticket_type'));
        }

        $add_form = do_template('FORM', [
            '_GUID' => '382f6fab6c563d81303ecb26495e76ec',
            'TABINDEX' => strval(get_form_field_tabindex()),
            'SECONDARY_FORM' => true,
            'HIDDEN' => '',
            'TEXT' => '',
            'FIELDS' => $fields,
            'SUBMIT_ICON' => 'admin/add_one_category',
            'SUBMIT_NAME' => $submit_name,
            'URL' => $post_url,
            'SUPPORT_AUTOSAVE' => true,
        ]);

        return do_template('SUPPORT_TICKET_TYPE_SCREEN', ['_GUID' => '28645dc4a86086fa865ec7e166b84bb6', 'TITLE' => $this->title, 'TPL' => $tpl, 'ADD_FORM' => $add_form]);
    }

    /**
     * The actualiser to add a ticket type.
     *
     * @return Tempcode The UI
     */
    public function add_ticket_type() : object
    {
        $ticket_type_name = post_param_string('ticket_type_name', post_param_string('ticket_type_name_2'));
        $ticket_type_id = add_ticket_type($ticket_type_name, post_param_integer('guest_emails_mandatory', 0), post_param_integer('search_faq', 0));

        // Permissions
        require_code('permissions2');
        set_category_permissions_from_environment('tickets', strval($ticket_type_id));
        if (addon_installed('ecommerce')) {
            require_code('ecommerce_permission_products');
            permission_product_save('ticket_type', strval($ticket_type_id));
        }

        // Show it worked / Refresh
        $url = build_url(['page' => '_SELF', 'type' => 'browse'], '_SELF');
        return redirect_screen($this->title, $url, do_lang_tempcode('SUCCESS'));
    }

    /**
     * The UI to edit a ticket.
     *
     * @return Tempcode The UI
     */
    public function edit_ticket_type() : object
    {
        require_code('form_templates');
        require_code('permissions2');

        $ticket_type_id = get_param_integer('ticket_type_id');
        $details = get_ticket_type($ticket_type_id);
        $ticket_type_name = get_translated_text($details['ticket_type_name']);

        $post_url = build_url(['page' => '_SELF', 'type' => '_edit', 'ticket_type_id' => $ticket_type_id], '_SELF');

        $submit_name = do_lang_tempcode('SAVE');

        $fields = new Tempcode();

        $fields->attach(form_input_line(do_lang_tempcode('TYPE'), do_lang_tempcode('DESCRIPTION_TICKET_TYPE'), 'ticket_type_name', $ticket_type_name, false));
        $fields->attach(form_input_tick(do_lang_tempcode('TICKET_GUEST_EMAILS_MANDATORY'), do_lang_tempcode('DESCRIPTION_TICKET_GUEST_EMAILS_MANDATORY'), 'guest_emails_mandatory', $details['guest_emails_mandatory'] == 1));
        $fields->attach(form_input_tick(do_lang_tempcode('TICKET_SEARCH_FAQ'), do_lang_tempcode('DESCRIPTION_TICKET_SEARCH_FAQ'), 'search_faq', $details['search_faq'] == 1));

        // Permissions
        $fields->attach(get_category_permissions_for_environment('tickets', strval($ticket_type_id)));
        if (addon_installed('ecommerce')) {
            require_code('ecommerce_permission_products');
            $fields->attach(permission_product_form('ticket_type', ($ticket_type_id === null) ? null : strval($ticket_type_id)));
        }

        $fields->attach(do_template('FORM_SCREEN_FIELD_SPACER', ['_GUID' => '09e6f1d2276ee679f280b33a79bff089', 'TITLE' => do_lang_tempcode('ACTIONS')]));
        $fields->attach(form_input_tick(do_lang_tempcode('DELETE'), do_lang_tempcode('DESCRIPTION_DELETE'), 'delete', false));

        return do_template('FORM_SCREEN', [
            '_GUID' => '0a505a779c1639fd2d3ee10c24a7905a',
            'SKIP_WEBSTANDARDS' => true,
            'TITLE' => $this->title,
            'HIDDEN' => '',
            'TEXT' => '',
            'FIELDS' => $fields,
            'SUBMIT_ICON' => 'admin/edit_this',
            'SUBMIT_NAME' => $submit_name,
            'URL' => $post_url,
            'SUPPORT_AUTOSAVE' => true,
        ]);
    }

    /**
     * The actualiser to edit/delete a ticket type.
     *
     * @return Tempcode The UI
     */
    public function _edit_ticket_type() : object
    {
        $ticket_type_id = get_param_integer('ticket_type_id');

        if (post_param_integer('delete', 0) == 1) {
            delete_ticket_type($ticket_type_id);
        } else {
            edit_ticket_type($ticket_type_id, post_param_string('ticket_type_name'), post_param_integer('guest_emails_mandatory', 0), post_param_integer('search_faq', 0));

            $GLOBALS['SITE_DB']->query_delete('group_category_access', ['module_the_name' => 'tickets', 'category_name' => strval($ticket_type_id)], '', 1);
            require_code('permissions2');
            set_category_permissions_from_environment('tickets', strval($ticket_type_id));
            if (addon_installed('ecommerce')) {
                require_code('ecommerce_permission_products');
                permission_product_save('ticket_type', strval($ticket_type_id));
            }
        }

        // Show it worked / Refresh
        $url = build_url(['page' => '_SELF', 'type' => 'browse'], '_SELF');
        return redirect_screen($this->title, $url, do_lang_tempcode('SUCCESS'));
    }

    /**
     * The UI for sending an e-mail to any address as a Support Ticket.
     *
     * @return Tempcode The UI
     */
    public function send_email_as_ticket() : object
    {
        require_code('form_templates');
        require_lang('email_log');

        $fields = new Tempcode();
        $hidden = new Tempcode();

        $fields->attach(form_input_email(do_lang_tempcode('TO_EMAIL'), do_lang_tempcode('DESCRIPTION_TO_EMAIL_TICKET'), 'email', null, true));
        $fields->attach(form_input_line(do_lang_tempcode('SUBJECT'), do_lang_tempcode('DESCRIPTION_SUBJECT_EMAIL_TICKET'), 'title', post_param_string('title', null), true));
        $fields->attach(form_input_huge_comcode(do_lang_tempcode('MESSAGE'), do_lang_tempcode('DESCRIPTION_MESSAGE_EMAIL_TICKET'), 'message', post_param_string('message', ''), true));
        $fields->attach(form_input_mail_template(do_lang_tempcode('EMAIL_TEMPLATE'), do_lang_tempcode('DESCRIPTION_EMAIL_TEMPLATE_EMAIL_TICKET'), 'template', post_param_string('template', null), false, true));

        if (get_option('ticket_mail_on') == '1') {
            $reply_to = get_option('ticket_mail_email_address');
        } else {
            $reply_to = get_option('website_email');
        }
        $fields->attach(form_input_email(do_lang_tempcode('REPLY_TO'), do_lang_tempcode('DESCRIPTION_REPLY_TO_EMAIL_TICKET'), 'reply_to', post_param_string('reply_to', $reply_to), true));

        $ticket_type_id = $this->get_ticket_type_id();
        $types = build_types_list($ticket_type_id);
        $entries = new Tempcode();
        foreach ($types as $id => $type) {
            $entries->attach(form_input_list_entry($type['TICKET_TYPE_ID'], $type['SELECTED'], $type['NAME']));
        }
        $fields->attach(form_input_list(do_lang_tempcode('TICKET_TYPE'), do_lang_tempcode('DESCRIPTION_TICKET_TYPE_EMAIL_TICKET'), 'ticket_type_id', $entries));

        $fields->attach(form_input_tick(do_lang_tempcode('SKIP_TICKET_CREATION'), do_lang_tempcode('DESCRIPTION_SKIP_TICKET_CREATION'), 'skip_ticket', post_param_integer('skip_ticket', 0) == 1));

        $url = build_url(['page' => '_SELF', 'type' => '_email'], '_SELF');

        return do_template('FORM_SCREEN', [
            'HIDDEN' => $hidden,
            'TITLE' => $this->title,
            'FIELDS' => $fields,
            'TEXT' => do_lang_tempcode('DESCRIPTION_ADD_TICKET_EMAIL'),
            'SUBMIT_ICON' => 'buttons/proceed',
            'SUBMIT_NAME' => do_lang_tempcode('PROCEED'),
            'URL' => $url,
        ]);
    }

    /**
     * The actualiser for sending an e-mail as a support ticket.
     *
     * @return Tempcode The UI for sending e-mail as ticket to another recipient
     */
    public function _send_email_as_ticket() : object
    {
        // Gather details
        $to_email = post_param_string('email', false, INPUT_FILTER_EMAIL_ADDRESS);
        $title = post_param_string('title');
        $message = post_param_string('message');
        $template = post_param_string('template');
        $reply_to = post_param_string('reply_to', false, INPUT_FILTER_EMAIL_ADDRESS);
        $ticket_type_id = $this->get_ticket_type_id();
        $skip_ticket = post_param_integer('skip_ticket', 0);

        if ($skip_ticket == 0) { // create a support ticket
            @ignore_user_abort(true);
            $ticket_id = ticket_generate_new_id($GLOBALS['FORUM_DRIVER']->get_guest_id());

            // Check ticket type access
            if (!has_category_access(get_member(), 'tickets', strval($ticket_type_id))) {
                access_denied('I_ERROR');
            }

            // Wrap around e-mail address
            $message = ticket_wrap_with_email_address($message, $to_email, false);

            // Add post to ticket...
            $ticket_url = ticket_add_post($ticket_id, $ticket_type_id, $title, $message, false);

            // Auto-monitor...
            if ((has_privilege(get_member(), 'support_operator')) && (get_option('ticket_auto_assign') == '1')) {
                require_code('notifications');
                set_notifications('ticket_assigned_staff', $ticket_id);
            }

            // Update subject with the real ticket title
            list($title) = get_ticket_meta_details($ticket_id);
        }

        require_code('mail');
        $dispatcher = dispatch_mail($title, $message, [$to_email], [$to_email], $reply_to, '', ['mail_template' => $template]);

        // Attach status
        if ($dispatcher->worked) {
            attach_message(do_lang_tempcode('SUCCESS'), 'inform');
        } elseif ($dispatcher->error !== false) {
            attach_message($dispatcher->error, 'warn', false, true);
        } else {
            attach_message(do_lang_tempcode('INTERNAL_ERROR'), 'warn');
        }

        // Return the UI for sending the e-mail to another person
        return $this->send_email_as_ticket();
    }

    /**
     * Find the selected ticket type ID.
     *
     * @return ?AUTO_LINK The ticket type ID (null: none specified)
     */
    protected function get_ticket_type_id() : ?int
    {
        $default_ticket_type_id = either_param_integer('ticket_type_id', null);
        if ($default_ticket_type_id === null) {
            $_default_ticket_type = either_param_string('ticket_type', null);
            if ($_default_ticket_type !== null) {
                $default_ticket_type_id = $GLOBALS['SITE_DB']->query_select_value_if_there('ticket_types', 'id', [$GLOBALS['SITE_DB']->translate_field_ref('ticket_type_name') => $_default_ticket_type]);
                if ($default_ticket_type_id === null) {
                    warn_exit(do_lang_tempcode('CAT_NOT_FOUND', escape_html($_default_ticket_type), 'ticket_type'));
                }
            }
        }
        return $default_ticket_type_id;
    }
}
