<?php /*

 Composr
 Copyright (c) ocProducts, 2004-2016

 See text/EN/licence.txt for full licencing 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  ocProducts Ltd
 * @package    cns_warnings
 */

require_code('crud_module');

/**
 * Module page class.
 */
class Module_warnings extends Standard_crud_module
{
    public $lang_type = 'WARNING';
    public $select_name = 'SUBMITTER';
    public $select_name_description = '';
    public $redirect_type = '!';
    public $menu_label = 'MODULE_TRANS_NAME_warnings';
    public $table = 'f_warnings';
    public $orderer = 'w_time';
    public $title_is_multi_lang = true;

    /**
     * Find icon for this module, specifically to find an icon for the module's main sitemap node. Defined when there is no entry-point for a default page call.
     *
     * @return string Icon.
     */
    public function get_wrapper_icon()
    {
        return 'tabs/member_account/warnings';
    }

    /**
     * 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($check_perms = true, $member_id = null, $support_crosslinks = true, $be_deferential = false)
    {
        if (get_forum_type() != 'cns') {
            return null;
        }

        if ($be_deferential) {
            return null;
        }

        if ($check_perms) {
            cns_require_all_forum_stuff();
            if (!cns_may_warn_members()) {
                return null;
            }
        }

        return (!$check_perms || !is_guest($member_id)) ? (parent::get_entry_points()) : array();
    }

    public $title;

    /**
     * Module pre-run function. Allows us to know metadata for <head> before we start streaming output.
     *
     * @param  boolean $top_level Whether this is running at the top level, prior to having sub-objects called.
     * @param  ?ID_TEXT $type The screen type to consider for metadata purposes (null: read from environment).
     * @return ?Tempcode Tempcode indicating some kind of exceptional output (null: none).
     */
    public function pre_run($top_level = true, $type = null)
    {
        $type = get_param_string('type', 'browse');

        if (get_forum_type() != 'cns') {
            warn_exit(do_lang_tempcode('NO_CNS'));
        } else {
            cns_require_all_forum_stuff();
        }
        require_lang('cns_warnings');
        if (addon_installed('securitylogging')) {
            require_lang('submitban');
        }

        if ($type == 'history') {
            $this->title = get_screen_title('PUNITIVE_HISTORY');
        }

        if ($type == 'undo_charge') {
            $this->title = get_screen_title('UNDO_CHARGE');
        }

        if ($type == 'undo_probation') {
            $this->title = get_screen_title('UNDO_PROBATION');
        }

        if ($type == 'undo_banned_ip') {
            $this->title = get_screen_title('UNBAN_IP');
        }

        if ($type == 'undo_banned_member') {
            $this->title = get_screen_title('UNBAN_MEMBER');
        }

        if ($type == 'undo_silence_from_topic') {
            $this->title = get_screen_title('UNSILENCE_TOPIC');
        }

        if ($type == 'undo_silence_from_forum') {
            $this->title = get_screen_title('UNSILENCE_FORUM');
        }

        return parent::pre_run($top_level);
    }

    /**
     * Standard crud_module run_start.
     *
     * @param  ID_TEXT $type The type of module execution
     * @return Tempcode The output of the run
     */
    public function run_start($type)
    {
        require_code('cns_moderation_action');
        require_code('cns_moderation_action2');

        if (!cns_may_warn_members()) {
            access_denied('PRIVILEGE', 'warn_members');
        }

        if ($type == 'history') {
            return $this->history();
        }
        if ($type == 'undo_charge') {
            return $this->undo_charge();
        }
        if ($type == 'undo_probation') {
            return $this->undo_probation();
        }
        if ($type == 'undo_banned_ip') {
            return $this->undo_banned_ip();
        }
        if ($type == 'undo_banned_member') {
            return $this->undo_banned_member();
        }
        if ($type == 'undo_silence_from_topic') {
            return $this->undo_silence_from_topic();
        }
        if ($type == 'undo_silence_from_forum') {
            return $this->undo_silence_from_forum();
        }

        return new Tempcode();
    }

    /**
     * View the warning/punishment history for a member.
     *
     * @return Tempcode The output of the run
     */
    public function history()
    {
        require_code('templates_results_table');

        $member_id = get_param_integer('id');

        $rows = $GLOBALS['FORUM_DB']->query_select('f_warnings', array('*'), array('w_member_id' => $member_id), 'ORDER BY w_time');
        if (count($rows) == 0) {
            inform_exit(do_lang_tempcode('NO_ENTRIES'));
        }
        $max_rows = count($rows);

        $out = new Tempcode();
        $f = array(do_lang_tempcode('SLASH_OR', do_lang_tempcode('DATE'), do_lang_tempcode('BY')), do_lang('WHETHER_MAKE_WARNING'), do_lang('CHANGED_USERGROUP'), do_lang('PUNISHMENT_UNDOING'));
        $fields_title = results_field_title($f, array());
        foreach ($rows as $row) {
            $date = hyperlink(build_url(array('page' => '_SELF', 'type' => '_edit', 'id' => $row['id'], 'redirect' => get_self_url(true)), '_SELF'), get_timezoned_date($row['w_time']), false, true, $row['w_explanation']);
            $by = $GLOBALS['FORUM_DRIVER']->member_profile_hyperlink($row['w_by']);
            $date_by = new Tempcode();
            $date_by->attach(do_lang_tempcode('SLASH_OR', $date, $by));

            $is_warning = escape_html($row['w_is_warning'] ? do_lang_tempcode('YES') : do_lang_tempcode('NO'));

            $changed_usergroup_from = escape_html((is_null($row['p_changed_usergroup_from']) ? do_lang_tempcode('NO') : do_lang_tempcode('YES')));
            $charged_points = ($row['p_charged_points'] == 0) ? new Tempcode() : div(hyperlink(build_url(array('page' => '_SELF', 'type' => 'undo_charge'), '_SELF'), do_lang_tempcode('RESTORE_POINTS', escape_html(integer_format($row['p_charged_points']))), false, true, '', null, form_input_hidden('id', strval($row['id']))), 'dsgsgdfgddgdf');
            $undoing = new Tempcode();
            if ($row['p_probation'] == 0) {
                $_undoing_link = new Tempcode();
            } else {
                $_undoing_url = build_url(array('page' => '_SELF', 'type' => 'undo_probation'), '_SELF');
                $_undoing_link = div(hyperlink($_undoing_url, do_lang_tempcode('REMOVE_PROBATION_DAYS', escape_html(integer_format($row['p_probation']))), false, false, '', null, form_input_hidden('id', strval($row['id']))), '46t54yhrtghdfhdhdfg');
            }
            $undoing->attach($_undoing_link);
            if (addon_installed('points')) {
                $undoing->attach($charged_points);
            }
            if ($row['p_banned_ip'] != '') {
                $undoing->attach(div(hyperlink(build_url(array('page' => '_SELF', 'type' => 'undo_banned_ip'), '_SELF'), do_lang_tempcode('UNBAN_IP'), false, true, '', null, form_input_hidden('id', strval($row['id']))), '4teryeryrydfhyhrgf'));
            }
            if ($row['p_banned_member'] == 1) {
                $undoing->attach(div(hyperlink(build_url(array('page' => '_SELF', 'type' => 'undo_banned_member'), '_SELF'), do_lang_tempcode('UNBAN_MEMBER'), false, true, '', null, form_input_hidden('id', strval($row['id']))), '56ytryrtyhrtyrt'));
            }
            if (!is_null($row['p_silence_from_topic'])) {
                $undoing->attach(div(hyperlink(build_url(array('page' => '_SELF', 'type' => 'undo_silence_from_topic'), '_SELF'), do_lang_tempcode('UNSILENCE_TOPIC'), false, true, '', null, form_input_hidden('id', strval($row['id']))), 'rgergdfhfhg'));
            }
            if (!is_null($row['p_silence_from_forum'])) {
                $undoing->attach(div(hyperlink(build_url(array('page' => '_SELF', 'type' => 'undo_silence_from_forum'), '_SELF'), do_lang_tempcode('UNSILENCE_FORUM'), false, true, '', null, form_input_hidden('id', strval($row['id']))), 'ghgfhfghggf'));
            }
            if ($undoing->is_empty()) {
                $undoing = do_lang_tempcode('NA_EM');
            }

            $g = array($date_by, $is_warning, $changed_usergroup_from, $undoing);
            $out->attach(results_entry($g, false));
        }
        $results_table = results_table(do_lang_tempcode('PUNITIVE_HISTORY'), 0, 'start', 1000000, 'max', $max_rows, $fields_title, $out, null, null, null, null, paragraph(do_lang_tempcode('PUNITIVE_HISTORY_TEXT'), '4t4ygyerhrth4'));

        $add_warning_url = build_url(array('page' => '_SELF', 'type' => 'add', 'id' => $member_id, 'redirect' => get_self_url(true)), '_SELF');
        $view_profile_url = $GLOBALS['FORUM_DRIVER']->member_profile_url($member_id, false, true);
        $edit_profile_url = build_url(array('page' => 'members', 'type' => 'view', 'id' => $member_id), get_module_zone('members'), null, false, false, false, 'tab__edit');

        $tpl = do_template('CNS_WARNING_HISTORY_SCREEN', array(
            '_GUID' => '4444beed9305f0460a6c00e6c87d4208',
            'TITLE' => $this->title,
            'MEMBER_ID' => strval($member_id),
            'EDIT_PROFILE_URL' => $edit_profile_url,
            'VIEW_PROFILE_URL' => $view_profile_url,
            'ADD_WARNING_URL' => $add_warning_url,
            'RESULTS_TABLE' => $results_table,
        ));

        require_code('templates_internalise_screen');
        return internalise_own_screen($tpl);
    }

    /**
     * Actualiser to undo a certain type of punitive action.
     *
     * @return Tempcode Result (redirect page)
     */
    public function undo_charge()
    {
        $id = post_param_integer('id');
        $member_id = $GLOBALS['FORUM_DB']->query_select_value('f_warnings', 'w_member_id', array('id' => $id));
        $charged_points = $GLOBALS['FORUM_DB']->query_select_value('f_warnings', 'p_charged_points', array('id' => $id));
        require_code('points2');
        charge_member($member_id, -$charged_points, do_lang('UNDO_CHARGE_FOR', strval($id)));
        $GLOBALS['FORUM_DB']->query_update('f_warnings', array('p_charged_points' => 0), array('id' => $id), '', 1);

        log_it('UNDO_CHARGE', strval($id), $GLOBALS['FORUM_DRIVER']->get_username($member_id));

        // Show it worked / Refresh
        $url = build_url(array('page' => '_SELF', 'type' => 'history', 'id' => $member_id), '_SELF');
        return redirect_screen($this->title, $url, do_lang_tempcode('SUCCESS'));
    }

    /**
     * Actualiser to undo a certain type of punitive action.
     *
     * @return Tempcode Result (redirect page)
     */
    public function undo_probation()
    {
        $id = post_param_integer('id');
        $member_id = $GLOBALS['FORUM_DB']->query_select_value('f_warnings', 'w_member_id', array('id' => $id));
        $probation = $GLOBALS['FORUM_DB']->query_select_value('f_warnings', 'p_probation', array('id' => $id));
        $on_probation_until = $GLOBALS['FORUM_DRIVER']->get_member_row_field($member_id, 'm_on_probation_until');
        if (!is_null($on_probation_until)) {
            $GLOBALS['FORUM_DB']->query_update('f_members', array('m_on_probation_until' => $on_probation_until - $probation * 60 * 60 * 24), array('id' => $member_id), '', 1);
        }
        $GLOBALS['FORUM_DB']->query_update('f_warnings', array('p_probation' => 0), array('id' => $id), '', 1);

        log_it('UNDO_PROBATION', strval($id), $GLOBALS['FORUM_DRIVER']->get_username($member_id));

        // Show it worked / Refresh
        $url = build_url(array('page' => '_SELF', 'type' => 'history', 'id' => $member_id), '_SELF');
        return redirect_screen($this->title, $url, do_lang_tempcode('SUCCESS'));
    }

    /**
     * Actualiser to undo a certain type of punitive action.
     *
     * @return Tempcode Result (redirect page)
     */
    public function undo_banned_ip()
    {
        require_code('failure');

        $id = post_param_integer('id');
        $member_id = $GLOBALS['FORUM_DB']->query_select_value('f_warnings', 'w_member_id', array('id' => $id));
        $banned_ip = $GLOBALS['FORUM_DB']->query_select_value('f_warnings', 'p_banned_ip', array('id' => $id));
        remove_ip_ban($banned_ip);
        $GLOBALS['FORUM_DB']->query_update('f_warnings', array('p_banned_ip' => ''), array('id' => $id), '', 1);

        log_it('UNBAN_IP', strval($id), $banned_ip);

        // Show it worked / Refresh
        $url = build_url(array('page' => '_SELF', 'type' => 'history', 'id' => $member_id), '_SELF');
        return redirect_screen($this->title, $url, do_lang_tempcode('SUCCESS'));
    }

    /**
     * Actualiser to undo a certain type of punitive action.
     *
     * @return Tempcode Result (redirect page)
     */
    public function undo_banned_member()
    {
        $id = post_param_integer('id');
        $member_id = $GLOBALS['FORUM_DB']->query_select_value('f_warnings', 'w_member_id', array('id' => $id));
        $banned_member = $GLOBALS['FORUM_DB']->query_select_value('f_warnings', 'p_banned_member', array('id' => $id));
        $GLOBALS['FORUM_DB']->query_update('f_members', array('m_is_perm_banned' => 0), array('id' => $member_id), '', 1);
        $GLOBALS['FORUM_DB']->query_update('f_warnings', array('p_banned_member' => 0), array('id' => $id), '', 1);

        log_it('UNBAN_MEMBER', strval($id), $GLOBALS['FORUM_DRIVER']->get_username($member_id));

        // Show it worked / Refresh
        $url = build_url(array('page' => '_SELF', 'type' => 'history', 'id' => $member_id), '_SELF');
        return redirect_screen($this->title, $url, do_lang_tempcode('SUCCESS'));
    }

    /**
     * Actualiser to undo a certain type of punitive action.
     *
     * @return Tempcode Result (redirect page)
     */
    public function undo_silence_from_topic()
    {
        $id = post_param_integer('id');
        $member_id = $GLOBALS['FORUM_DB']->query_select_value('f_warnings', 'w_member_id', array('id' => $id));
        $silence_from_topic = $GLOBALS['FORUM_DB']->query_select_value('f_warnings', 'p_silence_from_topic', array('id' => $id));
        $GLOBALS['FORUM_DB']->query_delete('member_privileges', array(
            'member_id' => $member_id,
            'privilege' => 'submit_lowrange_content',
            'the_page' => '',
            'module_the_name' => 'topics',
            'category_name' => strval($silence_from_topic),
        ));
        $GLOBALS['FORUM_DB']->query_update('f_warnings', array('p_silence_from_topic' => null), array('id' => $id), '', 1);

        log_it('UNSILENCE_TOPIC', strval($id));

        // Show it worked / Refresh
        $url = build_url(array('page' => '_SELF', 'type' => 'history', 'id' => $member_id), '_SELF');
        return redirect_screen($this->title, $url, do_lang_tempcode('SUCCESS'));
    }

    /**
     * Actualiser to undo a certain type of punitive action.
     *
     * @return Tempcode Result (redirect page)
     */
    public function undo_silence_from_forum()
    {
        $id = post_param_integer('id');
        $member_id = $GLOBALS['FORUM_DB']->query_select_value('f_warnings', 'w_member_id', array('id' => $id));
        $silence_from_forum = $GLOBALS['FORUM_DB']->query_select_value('f_warnings', 'p_silence_from_forum', array('id' => $id));
        $GLOBALS['FORUM_DB']->query_delete('member_privileges', array(
            'member_id' => $member_id,
            'privilege' => 'submit_lowrange_content',
            'the_page' => '',
            'module_the_name' => 'forums',
            'category_name' => strval($silence_from_forum),
        ));
        $GLOBALS['FORUM_DB']->query_update('f_warnings', array('p_silence_from_forum' => null), array('id' => $id), '', 1);

        log_it('UNSILENCE_FORUM', strval($id));

        // Show it worked / Refresh
        $url = build_url(array('page' => '_SELF', 'type' => 'history', 'id' => $member_id), '_SELF');
        return redirect_screen($this->title, $url, do_lang_tempcode('SUCCESS'));
    }

    /**
     * Get Tempcode for a warning adding/editing form.
     *
     * @param  boolean $new Whether it is a new warning/punishment record
     * @param  LONG_TEXT $explanation The explanation for the warning/punishment record
     * @param  BINARY $is_warning Whether to make this a formal warning
     * @param  ?MEMBER $member_id The member the warning is for (null: get from environment)
     * @return array A pair: the Tempcode for the visible fields, and the Tempcode for the hidden fields
     */
    public function get_form_fields($new = true, $explanation = '', $is_warning = 0, $member_id = null)
    {
        $spam_mode = (get_param_integer('spam', 0) == 1);

        if (is_null($member_id)) {
            $member_id = get_param_integer('member_id', get_member());
        }

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

        require_code('form_templates');

        $this->add_text = new Tempcode();

        $post_id = get_param_integer('post_id', null);
        $ip_address = ($post_id === null) ? null : $GLOBALS['FORUM_DB']->query_select_value_if_there('f_posts', 'p_ip_address', array('id' => $post_id));

        // Information about their history, and the rules - to educate the warner/punisher
        if ($new) {
            $hidden->attach(form_input_hidden('member_id', strval($member_id)));

            $username = $GLOBALS['FORUM_DRIVER']->get_username($member_id);
            $num_warnings = $GLOBALS['FORUM_DRIVER']->get_member_row_field($member_id, 'm_cache_warnings');
            $_rules_url = build_url(array('page' => 'rules'), '_SEARCH');
            $rules_url = $_rules_url->evaluate();
            $_history_url = build_url(array('page' => '_SELF', 'type' => 'history', 'id' => $member_id), '_SELF');
            $history_url = $_history_url->evaluate();
            if (((!is_guest($member_id)) || ($ip_address !== null)) && (addon_installed('securitylogging'))) {
                $lookup_url = build_url(array('page' => 'admin_lookup', 'param' => is_guest($member_id) ? $ip_address : $member_id), 'adminzone');
            } else {
                $lookup_url = $GLOBALS['FORUM_DRIVER']->member_profile_url($member_id, false, true);
            }
            if (is_object($lookup_url)) {
                $lookup_url = $lookup_url->evaluate();
            }
            $this->add_text->attach(paragraph(do_lang_tempcode('HAS_ALREADY_X_WARNINGS', escape_html($username), escape_html(integer_format($num_warnings)), array(escape_html(get_site_name()), escape_html($rules_url), escape_html($history_url), escape_html($lookup_url)))));
        }

        $fields->attach(do_template('FORM_SCREEN_FIELD_SPACER', array('_GUID' => 'cb4511a58a4c78eb75346a468e6e6fdf', 'TITLE' => do_lang_tempcode('MODULE_TRANS_NAME_warnings'))));
        $fields->attach(form_input_tick(do_lang_tempcode('WHETHER_MAKE_WARNING'), do_lang_tempcode('DESCRIPTION_WHETHER_MAKE_WARNING'), 'is_warning', $is_warning == 1));

        // Punitive actions
        if ($new) {
            define('POST_STANDALONE_AT_END', 0);
            define('POST_STANDALONE_IN_MIDDLE', 1);
            define('POST_AS_TOPIC_FULL', 2);
            define('POST_AS_TOPIC_STARTER', 3);

            $posts_deletable = array();
            if (has_delete_permission('mid', get_member(), $member_id, 'topics')) {
                $first_post_time = $GLOBALS['FORUM_DB']->query_select_value('f_posts', 'MIN(p_time)', array('p_poster' => $member_id));
                if (
                    (($GLOBALS['DEV_MODE']) || ($first_post_time > time() - 60 * 60 * 24 * 14)) && // i.e. a recent spammer, not a normal member being punished
                    ((!is_guest($member_id)) || ($ip_address !== null))
                ) {
                    $where = array();
                    if (is_guest($member_id)) {
                        $where['p_ip_address'] = $ip_address;
                    } else {
                        $where['p_poster'] = $member_id;
                    }
                    $sup = 'ORDER BY p_time DESC';
                    if (!has_privilege(get_member(), 'view_other_pt')) {
                        $sup = ' AND p_cache_forum_id IS NOT NULL ' . $sup;
                    }
                    $posts_by_member = $GLOBALS['FORUM_DB']->query_select('f_posts p JOIN ' . $GLOBALS['FORUM_DB']->get_table_prefix() . 'f_topics t ON t.id=p.p_topic_id', array('p.*', 't_cache_first_post_id', 't_cache_last_post_id', 't_cache_num_posts', 't_cache_first_title', 'p_cache_forum_id'), $where, $sup, 10);
                    $spam_urls = array();
                    foreach ($posts_by_member as $post) {
                        $just_post_row = db_map_restrict($post, array('id', 'p_post'), array('id' => 'p_id'));
                        $post_text = get_translated_tempcode('f_posts', $just_post_row, 'p_post', $GLOBALS['FORUM_DB']);
                        $matches = array();
                        $num_matches = preg_match_all('#<a\s[^<>]*href=["\']([^"\']*)["\']#', $post_text->evaluate(), $matches);
                        for ($i = 0; $i < $num_matches; $i++) {
                            $spam_url = $matches[1][$i];
                            if (!url_is_local($spam_url)) {
                                $domain = parse_url(normalise_idn_url($spam_url), PHP_URL_HOST);
                                if (($domain != get_domain()) && (!empty($domain))) {
                                    if (!isset($spam_urls[$domain])) {
                                        require_code('mail');
                                        $ip = cms_gethostbyname($domain);
                                        $spam_urls[$domain] = array('DOMAIN' => $domain, 'IP' => $ip, 'URLS' => array(), 'POSTS' => array());
                                    }
                                    if (!isset($spam_urls[$domain]['URLS'][$spam_url])) {
                                        $spam_urls[$domain]['URLS'][$spam_url] = array('I' => strval(count($spam_urls[$domain]['URLS'])), 'URL' => $spam_url);
                                    }
                                    if (!isset($spam_urls[$domain]['POSTS'][$post['id']])) {
                                        $spam_urls[$domain]['POSTS'][$post['id']] = array('I' => strval(count($spam_urls[$domain]['POSTS'])), 'POST_TITLE' => $post['p_title'], 'POST' => strip_html($post_text->evaluate()));
                                    }
                                }
                            }
                        }

                        if ($post['t_cache_first_post_id'] == $post['id']) {
                            if ($post['t_cache_num_posts'] == 1) {
                                $post_context = POST_AS_TOPIC_STARTER;
                            } else {
                                $post_context = POST_AS_TOPIC_FULL;
                            }
                        } else {
                            if ($post['t_cache_last_post_id'] == $post['id']) {
                                $post_context = POST_STANDALONE_AT_END;
                            } else {
                                $post_context = POST_STANDALONE_IN_MIDDLE;
                            }
                        }
                        $posts_deletable[$post['id']] = array($post_context, $post['id'], $post['p_topic_id'], $post['t_cache_first_title'], $post['p_time'], $post['p_cache_forum_id']);
                    }
                    if (count($spam_urls) > 0) {
                        $this->add_text->attach(paragraph(do_template('CNS_WARN_SPAM_URLS', array('USERNAME' => $username, 'SPAM_URLS' => $spam_urls))));
                    }
                }
            }

            $fields->attach(do_template('FORM_SCREEN_FIELD_SPACER', array('_GUID' => '322a026b7a56a3e4e9ac58e4979add35', 'TITLE' => do_lang_tempcode('PUNITIVE_ACTIONS'))));

            if (($post_id !== null) && (!$spam_mode)) {
                $topic_id = $GLOBALS['FORUM_DB']->query_select_value_if_there('f_posts', 'p_topic_id', array('id' => $post_id));
                if (!is_null($topic_id)) {
                    $forum_id = $GLOBALS['FORUM_DB']->query_select_value('f_topics', 't_forum_id', array('id' => $topic_id));
                    $hidden->attach(form_input_hidden('topic_id', strval($topic_id)));
                    $hidden->attach(form_input_hidden('forum_id', strval($forum_id)));
                    $silence_topic_time = null;//time()+60*60*24*7;
                    $silence_forum_time = null;//time()+60*60*24*7;
                    $active_until = $GLOBALS['FORUM_DB']->query_select_value_if_there('member_privileges', 'active_until', array(
                        'member_id' => $member_id,
                        'privilege' => 'submit_lowrange_content',
                        'the_page' => '',
                        'module_the_name' => 'topics',
                        'category_name' => strval($topic_id),
                    ));
                    if (!is_null($active_until)) {
                        $silence_topic_time = $active_until;
                    }
                    $active_until = $GLOBALS['FORUM_DB']->query_select_value_if_there('member_privileges', 'active_until', array(
                        'member_id' => $member_id,
                        'privilege' => 'submit_lowrange_content',
                        'the_page' => '',
                        'module_the_name' => 'forums',
                        'category_name' => strval($forum_id),
                    ));
                    if (!is_null($active_until)) {
                        $silence_forum_time = $active_until;
                    }
                    $fields->attach(form_input_date(do_lang_tempcode('SILENCE_FROM_TOPIC'), do_lang_tempcode('DESCRIPTION_SILENCE_FROM_TOPIC'), 'silence_from_topic', false, true, true, $silence_topic_time, 2));
                    $fields->attach(form_input_date(do_lang_tempcode('SILENCE_FROM_FORUM'), do_lang_tempcode('DESCRIPTION_SILENCE_FROM_FORUM'), 'silence_from_forum', false, true, true, $silence_forum_time, 2));
                }
            }

            if (has_privilege(get_member(), 'probate_members')) {
                $fields->attach(form_input_integer(do_lang_tempcode('EXTEND_PROBATION'), do_lang_tempcode('DESCRIPTION_EXTEND_PROBATION'), 'probation', 0, true));
            }
            if (addon_installed('points')) {
                if (has_actual_page_access(get_member(), 'admin_points')) {
                    require_code('points');
                    $num_points_currently = available_points($member_id);
                    $fields->attach(form_input_integer(do_lang_tempcode('CHARGED_POINTS'), do_lang_tempcode('DESCRIPTION_CHARGED_POINTS', escape_html(integer_format($num_points_currently))), 'charged_points', 0, true));
                }
            }
            if (addon_installed('securitylogging')) {
                if (has_actual_page_access(get_member(), 'admin_ip_ban')) {
                    $already_banned_ip = ip_banned($GLOBALS['FORUM_DRIVER']->get_member_row_field($member_id, 'm_ip_address'));
                    $fields->attach(form_input_tick(do_lang_tempcode('WHETHER_BANNED_IP'), do_lang_tempcode('DESCRIPTION_WHETHER_BANNED_IP'), 'banned_ip', $spam_mode || $already_banned_ip, null, '1', $already_banned_ip));
                }

                $stopforumspam_api_key = get_option('stopforumspam_api_key');
                if (is_null($stopforumspam_api_key)) {
                    $stopforumspam_api_key = '';
                }
                $tornevall_api_username = get_option('tornevall_api_username');
                if (is_null($tornevall_api_username)) {
                    $tornevall_api_username = '';
                }
                if ($stopforumspam_api_key . $tornevall_api_username != '') {
                    $fields->attach(form_input_tick(do_lang_tempcode('SYNDICATE_TO_STOPFORUMSPAM'), do_lang_tempcode('DESCRIPTION_SYNDICATE_TO_STOPFORUMSPAM'), 'stopforumspam', $spam_mode));
                }
            }
            if (has_privilege(get_member(), 'member_maintenance')) {
                $already_banned = ($GLOBALS['FORUM_DRIVER']->get_member_row_field($member_id, 'm_is_perm_banned') == 1);
                $fields->attach(form_input_tick(do_lang_tempcode('BAN_MEMBER'), do_lang_tempcode('DESCRIPTION_BANNED_MEMBER'), 'banned_member', $spam_mode || $already_banned, null, '1', $already_banned));

                $rows = $GLOBALS['FORUM_DB']->query_select('f_groups', array('id', 'g_name'), array('g_is_private_club' => 0));
                $groups = new Tempcode();
                $groups->attach(form_input_list_entry('-1', false, do_lang_tempcode('NA_EM')));
                foreach ($rows as $group) {
                    if ($group['id'] != db_get_first_id()) {
                        $groups->attach(form_input_list_entry(strval($group['id']), false, get_translated_text($group['g_name'], $GLOBALS['FORUM_DB'])));
                    }
                }
                $fields->attach(form_input_list(do_lang_tempcode('CHANGE_USERGROUP_TO'), do_lang_tempcode('DESCRIPTION_CHANGE_USERGROUP_TO'), 'changed_usergroup_from', $groups, null, false, false));
            }
        }

        // Explanatory text
        $keep = symbol_tempcode('KEEP');
        $load_url = find_script('warnings_browse') . '?type=load' . $keep->evaluate();
        $fields->attach(do_template('FORM_SCREEN_FIELD_SPACER', array('_GUID' => 'c7eb70b13be74d8f3bd1f1c5e739d9aa', 'TITLE' => do_lang_tempcode('EXPLANATORY_TEXT'), 'HELP' => do_lang_tempcode('LOAD_SAVED_WARNING', escape_html($load_url)))));
        if (($explanation == '') && ($spam_mode)) {
            $explanation = 'Spam';
        }
        $fields->attach(form_input_line_comcode(do_lang_tempcode('EXPLANATION'), do_lang_tempcode('DESCRIPTION_EXPLANATION'), 'explanation', $explanation, true));
        if ($new) {
            $message = '';
            if (!is_null($post_id)) {
                $_postdetails_text = $GLOBALS['FORUM_DB']->query_select_value_if_there('f_posts', 'p_post', array('id' => $post_id));
                if (!is_null($_postdetails_text)) {
                    $message = '[quote="' . $username . '"]' . "\n" . get_translated_text($_postdetails_text, $GLOBALS['FORUM_DB']) . "\n" . '[/quote]';
                    $message .= "\n\n" . do_lang('MODERATED_AS_SPAM', get_site_name()); // TODO: Change in v11 to mesh with Patrick's changes
                }
            }
            $fields->attach(form_input_text_comcode(do_lang_tempcode('MESSAGE'), do_lang_tempcode('DESCRIPTION_PP_MESSAGE'), 'message', $message, false));

            $fields->attach(do_template('FORM_SCREEN_FIELD_SPACER', array('_GUID' => 'c745535395edf114d20a8a8eafe73b92', 'TITLE' => do_lang_tempcode('ACTIONS'))));
            $fields->attach(form_input_line(do_lang_tempcode('SAVE_WARNING_DETAILS'), do_lang_tempcode('DESCRIPTION_SAVE_WARNING_DETAILS'), 'save', '', false));

            foreach ($posts_deletable as $post_id => $_post_deletable) {
                list($post_context, $post_id, $topic_id, $topic_title, $post_time, $forum_id) = $_post_deletable;
                $post_url = $GLOBALS['FORUM_DRIVER']->post_url($post_id, $forum_id, true);

                $list_options = new Tempcode();
                $list_options->attach(form_input_list_entry('', !$spam_mode, do_lang_tempcode('HANDLE_POST__NOTHING')));
                switch ($post_context) {
                    case POST_STANDALONE_AT_END:
                        $handle_label = do_lang_tempcode('HANDLE_POST__POST_STANDALONE_AT_END', escape_html($topic_title), escape_html(integer_format($post_id)), array(escape_html(integer_format($topic_id)), escape_html($post_url->evaluate())));
                        $list_options->attach(form_input_list_entry('delete_post', $spam_mode, do_lang_tempcode('HANDLE_POST__DELETE_POST', escape_html($topic_title), escape_html(integer_format($post_id)), array(escape_html(integer_format($topic_id)), escape_html($post_url->evaluate())))));
                        break;

                    case POST_STANDALONE_IN_MIDDLE:
                        $num_replies = $GLOBALS['FORUM_DB']->query_value_if_there('SELECT COUNT(*) FROM ' . $GLOBALS['FORUM_DB']->get_table_prefix() . 'f_posts WHERE p_topic_id=' . strval($topic_id) . ' AND p_time>' . strval($post_time));
                        $handle_label = do_lang_tempcode('HANDLE_POST__POST_STANDALONE_IN_MIDDLE', escape_html($topic_title), escape_html(integer_format($post_id)), array(escape_html(integer_format($topic_id)), escape_html($post_url->evaluate()), escape_html(integer_format($num_replies))));
                        $list_options->attach(form_input_list_entry('delete_post', $spam_mode, do_lang_tempcode('HANDLE_POST__DELETE_POST_WITH_GAP', escape_html($topic_title), escape_html(integer_format($post_id)), array(escape_html(integer_format($topic_id)), escape_html($post_url->evaluate()), escape_html(integer_format($num_replies))))));
                        $list_options->attach(form_input_list_entry('delete_post_and_following', false, do_lang_tempcode('HANDLE_POST__DELETE_POST_AND_FOLLOWING', escape_html($topic_title), escape_html(integer_format($post_id)), array(escape_html(integer_format($topic_id)), escape_html($post_url->evaluate()), escape_html(integer_format($num_replies))))));
                        break;

                    case POST_AS_TOPIC_FULL:
                        $num_replies = $GLOBALS['FORUM_DB']->query_value_if_there('SELECT COUNT(*) FROM ' . $GLOBALS['FORUM_DB']->get_table_prefix() . 'f_posts WHERE p_topic_id=' . strval($topic_id) . ' AND p_time>' . strval($post_time));
                        $handle_label = do_lang_tempcode('HANDLE_POST__POST_AS_TOPIC_FULL', escape_html($topic_title), escape_html(integer_format($post_id)), array(escape_html(integer_format($topic_id)), escape_html($post_url->evaluate()), escape_html(integer_format($num_replies))));
                        $list_options->attach(form_input_list_entry('delete_post_and_following', $spam_mode, do_lang_tempcode('HANDLE_POST__DELETE_TOPIC_WITH_REPLIES', escape_html($topic_title), escape_html(integer_format($post_id)), array(escape_html(integer_format($topic_id)), escape_html($post_url->evaluate()), escape_html(integer_format($num_replies))))));
                        break;

                    case POST_AS_TOPIC_STARTER:
                        $handle_label = do_lang_tempcode('HANDLE_POST__POST_AS_TOPIC_STARTER', escape_html($topic_title), escape_html(integer_format($post_id)), array(escape_html(integer_format($topic_id)), escape_html($post_url->evaluate())));
                        $list_options->attach(form_input_list_entry('delete_post_and_following', $spam_mode, do_lang_tempcode('HANDLE_POST__DELETE_TOPIC', escape_html($topic_title), escape_html(integer_format($post_id)), array(escape_html(integer_format($topic_id)), escape_html($post_url->evaluate())))));
                        break;
                }
                $fields->attach(form_input_list($handle_label, '', 'handle_post__' . strval($post_id), $list_options, null, false, false));
            }
        }

        return array($fields, $hidden);
    }

    /**
     * Standard crud_module table function.
     *
     * @param  array $url_map Details to go to build_url for link to the next screen.
     * @return array A quartet: The choose table, Whether reordering is supported from this screen, Search URL, Archive URL.
     */
    public function create_selection_list_choose_table($url_map)
    {
        require_code('templates_results_table');

        $current_ordering = get_param_string('sort', 'w_time DESC', true);
        if (strpos($current_ordering, ' ') === false) {
            warn_exit(do_lang_tempcode('INTERNAL_ERROR'));
        }
        list($sortable, $sort_order) = explode(' ', $current_ordering, 2);
        $sortables = array(
            'w_time' => do_lang_tempcode('DATE'),
        );
        if (addon_installed('points')) {
            $sortables['p_charged_points'] = do_lang_tempcode('POINTS');
        }
        if (((strtoupper($sort_order) != 'ASC') && (strtoupper($sort_order) != 'DESC')) || (!array_key_exists($sortable, $sortables))) {
            log_hack_attack_and_exit('ORDERBY_HACK');
        }

        $fh = array(
            do_lang_tempcode('USERNAME'),
            do_lang_tempcode('BY'),
            do_lang_tempcode('DATE'),
        );
        if (addon_installed('points')) {
            $fh[] = do_lang_tempcode('POINTS');
        }
        $fh[] = do_lang_tempcode('ACTIONS');

        $header_row = results_field_title($fh, $sortables, 'sort', $sortable . ' ' . $sort_order);

        $fields = new Tempcode();

        require_code('form_templates');
        list($rows, $max_rows) = $this->get_entry_rows(false, $current_ordering);
        foreach ($rows as $row) {
            $edit_link = build_url($url_map + array('id' => $row['id']), '_SELF');

            $username = $GLOBALS['FORUM_DRIVER']->member_profile_hyperlink($row['w_member_id'], false, '', false);
            $by = $GLOBALS['FORUM_DRIVER']->member_profile_hyperlink($row['w_by']);

            $map = array(
                protect_from_escaping($username),
                protect_from_escaping($by),
                get_timezoned_date($row['w_time']),
            );

            if (addon_installed('points')) {
                $map[] = integer_format($row['p_charged_points']);
            }

            $map[] = protect_from_escaping(hyperlink($edit_link, do_lang_tempcode('EDIT'), false, true, do_lang('EDIT') . ' #' . strval($row['id'])));

            $fields->attach(results_entry($map, true));
        }

        $search_url = null;
        $archive_url = null;

        return array(results_table(do_lang($this->menu_label), get_param_integer('start', 0), 'start', get_param_integer('max', 20), 'max', $max_rows, $header_row, $fields, $sortables, $sortable, $sort_order), false, $search_url, $archive_url);
    }

    /**
     * Standard crud_module list function.
     *
     * @return Tempcode The selection list
     */
    public function create_selection_list_entries()
    {
        $_m = $GLOBALS['FORUM_DB']->query_select('f_warnings', array('*'), null, 'ORDER BY w_time DESC');
        $entries = new Tempcode();
        foreach ($_m as $m) {
            $entries->attach(form_input_list_entry(strval($m['id']), false, $GLOBALS['FORUM_DRIVER']->get_username($m['w_member_id']) . ' (' . get_timezoned_date($m['w_time']) . ')'));
        }

        return $entries;
    }

    /**
     * Standard crud_module edit form filler.
     *
     * @param  ID_TEXT $id The entry being edited
     * @return array A pair: the Tempcode for the visible fields, and the Tempcode for the hidden fields
     */
    public function fill_in_edit_form($id)
    {
        $warning = $GLOBALS['FORUM_DB']->query_select('f_warnings', array('w_explanation', 'w_by', 'w_member_id', 'w_is_warning'), array('id' => intval($id)), '', 1);
        if (!array_key_exists(0, $warning)) {
            warn_exit(do_lang_tempcode('MISSING_RESOURCE'));
        }

        return $this->get_form_fields(false, $warning[0]['w_explanation'], $warning[0]['w_is_warning'], $warning[0]['w_member_id']);
    }

    /**
     * Standard crud_module add actualiser.
     *
     * @return ID_TEXT The entry added
     */
    public function add_actualisation()
    {
        $explanation = post_param_string('explanation');
        $member_id = post_param_integer('member_id');
        $message = post_param_string('message', '');
        $username = $GLOBALS['FORUM_DRIVER']->get_username($member_id);
        if (is_null($username)) {
            warn_exit(do_lang_tempcode('MEMBER_NO_EXIST'));
        }

        $save = post_param_string('save');
        if ($save != '') {
            $GLOBALS['FORUM_DB']->query_delete('f_saved_warnings', array('s_title' => $save), '', 1);
            $GLOBALS['FORUM_DB']->query_insert('f_saved_warnings', array(
                's_title' => $save,
                's_explanation' => $explanation,
                's_message' => $message,
            ));
        }

        // Send PT
        if ($message != '') {
            require_code('cns_topics_action');
            require_code('cns_topics_action2');
            require_code('cns_posts_action');
            require_code('cns_posts_action2');

            $_title = do_lang('NEW_WARNING_TO_YOU');

            $pt_topic_id = cns_make_topic(null, '', '', 1, 1, 0, 0, 0, get_member(), $member_id);
            $post_id = cns_make_post($pt_topic_id, $_title, $message, 0, true, 1, 1/*emphasised*/, null, null, null, null, null, null, null, false);

            send_pt_notification($post_id, $_title, $pt_topic_id, $member_id);
        }

        // Topic silencing
        $silence_from_topic = post_param_integer('topic_id', null);
        if (!is_null($silence_from_topic)) {
            $_silence_from_topic = post_param_date('silence_from_topic');
            $GLOBALS['FORUM_DB']->query_delete('member_privileges', array(
                'member_id' => $member_id,
                'privilege' => 'submit_lowrange_content',
                'the_page' => '',
                'module_the_name' => 'topics',
                'category_name' => strval($silence_from_topic),
            ));

            require_code('cns_general_action2');
            cns_mod_log_it('SILENCE_FROM_TOPIC', strval($member_id), strval($silence_from_topic));
        } else {
            $_silence_from_topic = null;
        }
        if (!is_null($_silence_from_topic)) {
            $GLOBALS['FORUM_DB']->query_insert('member_privileges', array(
                'active_until' => $_silence_from_topic,
                'member_id' => $member_id,
                'privilege' => 'submit_lowrange_content',
                'the_page' => '',
                'module_the_name' => 'topics',
                'category_name' => strval($silence_from_topic),
                'the_value' => '0'
            ));
        } else {
            $silence_from_topic = null;
        }

        // Forum silencing
        $silence_from_forum = post_param_integer('forum_id', null);
        if (!is_null($silence_from_forum)) {
            $GLOBALS['FORUM_DB']->query_delete('member_privileges', array(
                'member_id' => $member_id,
                'privilege' => 'submit_lowrange_content',
                'the_page' => '',
                'module_the_name' => 'forums',
                'category_name' => strval($silence_from_forum),
            ));
            $GLOBALS['FORUM_DB']->query_delete('member_privileges', array(
                'member_id' => $member_id,
                'privilege' => 'submit_midrange_content',
                'the_page' => '',
                'module_the_name' => 'forums',
                'category_name' => strval($silence_from_forum),
            ));
            $_silence_from_forum = post_param_date('silence_from_forum');

            require_code('cns_general_action2');
            cns_mod_log_it('SILENCE_FROM_FORUM', strval($member_id), strval($silence_from_forum));
        } else {
            $_silence_from_forum = null;
        }
        if (!is_null($_silence_from_forum)) {
            $GLOBALS['FORUM_DB']->query_insert('member_privileges', array(
                'active_until' => $_silence_from_forum,
                'member_id' => $member_id,
                'privilege' => 'submit_lowrange_content',
                'the_page' => '',
                'module_the_name' => 'forums',
                'category_name' => strval($silence_from_forum),
                'the_value' => '0'
            ));
            $GLOBALS['FORUM_DB']->query_insert('member_privileges', array(
                'active_until' => $_silence_from_forum,
                'member_id' => $member_id,
                'privilege' => 'submit_midrange_content',
                'the_page' => '',
                'module_the_name' => 'forums',
                'category_name' => strval($silence_from_forum),
                'the_value' => '0'
            ));
        } else {
            $silence_from_forum = null;
        }

        // Post deletion
        $deleted_all = false;
        if (has_delete_permission('mid', get_member(), $member_id, 'topics')) {
            $where = array('p_poster' => $member_id);
            $sup = 'ORDER BY p_time';
            if (!has_privilege(get_member(), 'view_other_pt')) {
                $sup = ' AND p_cache_forum_id IS NOT NULL ' . $sup;
            }
            $posts_already_deleted = array();
            $posts_by_member = $GLOBALS['FORUM_DB']->query_select('f_posts', array('id', 'p_topic_id', 'p_time'), $where, $sup);
            $deleted_all = true;
            foreach ($posts_by_member as $post) {
                if (isset($posts_already_deleted[$post['id']])) {
                    continue;
                }
                require_code('cns_posts_action3');
                $post_action = post_param_string('handle_post__' . strval($post['id']), '');
                $posts = array();
                switch ($post_action) {
                    case 'delete_post':
                        $posts[] = $post['id'];
                        $posts_already_deleted[$post['id']] = true;
                        break;
                    case 'delete_post_and_following':
                        $posts[] = $post['id'];
                        $further_posts = $GLOBALS['FORUM_DB']->query_select('f_posts', array('id'), array('p_topic_id' => $post['p_topic_id']), 'AND p_time>' . strval($post['p_time']));
                        foreach ($further_posts as $_post) {
                            $posts[] = $_post['id'];
                            $posts_already_deleted[$_post['id']] = true;
                        }
                        break;
                    default:
                        $deleted_all = false;
                        break;
                }
                cns_delete_posts_topic($post['p_topic_id'], $posts, $explanation, false);
            }
        }

        // Probation
        $probation = post_param_integer('probation', 0);
        if (has_privilege(get_member(), 'probate_members')) {
            if ($probation != 0) {
                $on_probation_until = $GLOBALS['FORUM_DRIVER']->get_member_row_field($member_id, 'm_on_probation_until');
                if ((is_null($on_probation_until)) || ($on_probation_until < time())) {
                    $on_probation_until = time();
                }
                $on_probation_until += $probation * 60 * 60 * 24;
                $GLOBALS['FORUM_DB']->query_update('f_members', array('m_on_probation_until' => $on_probation_until), array('id' => $member_id), '', 1);

                require_code('cns_general_action2');
                cns_mod_log_it('PUT_ON_PROBATION', strval($member_id), $username);
            }
        }

        // Ban member
        if (has_privilege(get_member(), 'member_maintenance')) {
            $banned_member = post_param_integer('banned_member', 0);
            if ($banned_member == 1) {
                $GLOBALS['FORUM_DB']->query_update('f_members', array('m_is_perm_banned' => 1), array('id' => $member_id), '', 1);

                require_code('cns_general_action2');
                cns_mod_log_it('BAN_MEMBER', strval($member_id), $username);
            }
        } else {
            $banned_member = 0;
        }

        // IP ban
        $banned_ip = '';
        if (addon_installed('securitylogging')) {
            if (has_actual_page_access(get_member(), 'admin_ip_ban')) {
                $_banned_ip = post_param_integer('banned_ip', 0);
                if ($_banned_ip == 1) {
                    $banned_ip = $GLOBALS['FORUM_DRIVER']->get_member_row_field($member_id, 'm_ip_address');
                    require_code('failure');
                    add_ip_ban($banned_ip);
                    log_it('IP_BANNED', $banned_ip);
                }
            }
        }

        // Stop Forum Spam report
        $stopforumspam = post_param_integer('stopforumspam', 0);
        if ($stopforumspam == 1) {
            $banned_ip = $GLOBALS['FORUM_DRIVER']->get_member_row_field($member_id, 'm_ip_address');
            require_code('failure');
            require_code('failure_spammers');
            syndicate_spammer_report($banned_ip, $username, $GLOBALS['FORUM_DRIVER']->get_member_email_address($member_id), $explanation, false);

            require_code('cns_general_action2');
            cns_mod_log_it('MARK_AS_SPAMMER', strval($member_id), $username);
        }

        // Change group
        $changed_usergroup_from = null;
        if (has_privilege(get_member(), 'member_maintenance')) {
            $__changed_usergroup_from = post_param_string('changed_usergroup_from');
            if ($__changed_usergroup_from == '') {
                $_changed_usergroup_from = null;
            } else {
                $_changed_usergroup_from = intval($__changed_usergroup_from);
            }
            if ((!is_null($_changed_usergroup_from)) && ($_changed_usergroup_from != -1)) {
                $changed_usergroup_from = $GLOBALS['FORUM_DRIVER']->get_member_row_field($member_id, 'm_primary_group');
                $GLOBALS['FORUM_DB']->query_update('f_members', array('m_primary_group' => $_changed_usergroup_from), array('id' => $member_id), '', 1);
            }
        }

        // Prepare to charge points (used in cns_make_warning)
        $charged_points = post_param_integer('charged_points', 0);

        // Make the warning
        $warning_id = cns_make_warning($member_id, $explanation, null, null, post_param_integer('is_warning', 0), $silence_from_topic, $silence_from_forum, $probation, $banned_ip, $charged_points, $banned_member, $changed_usergroup_from);

        // Charge points
        if (addon_installed('points')) {
            if (has_actual_page_access(get_member(), 'admin_points')) {
                if ($charged_points != 0) {
                    require_code('points2');
                    charge_member($member_id, $charged_points, do_lang('FOR_PUNISHMENT', strval($warning_id)));
                }
            }
        }

        if ((get_param_string('redirect', '') == '') || ($deleted_all)) {
            require_code('site2');
            assign_refresh($GLOBALS['FORUM_DRIVER']->member_profile_url($member_id, true, true), 0.0);
            unset($_GET['redirect']);
        }

        return strval($warning_id);
    }

    /**
     * Standard crud_module edit actualiser.
     *
     * @param  ID_TEXT $id The entry being edited
     */
    public function edit_actualisation($id)
    {
        $member_id = cns_edit_warning(intval($id), post_param_string('explanation'), post_param_integer('is_warning', 0));

        if (get_param_string('redirect', '') == '') {
            require_code('site2');
            assign_refresh($GLOBALS['FORUM_DRIVER']->member_profile_url($member_id, true, true), 0.0);
        }
    }

    /**
     * Standard crud_module submitter getter.
     *
     * @param  ID_TEXT $id The entry for which the submitter is sought
     * @return array The submitter, and the time of submission (null submission time implies no known submission time)
     */
    public function get_submitter($id)
    {
        $rows = $GLOBALS['FORUM_DB']->query_select('f_warnings', array('w_by', 'w_time'), array('id' => intval($id)), '', 1);
        if (!array_key_exists(0, $rows)) {
            return array(null, null);
        }
        return array($rows[0]['w_by'], $rows[0]['w_time']);
    }

    /**
     * Standard crud_module delete actualiser.
     *
     * @param  ID_TEXT $id The entry being deleted
     */
    public function delete_actualisation($id)
    {
        $member_id = cns_delete_warning(intval($id));

        if (get_param_string('redirect', '') == '') {
            require_code('site2');
            assign_refresh($GLOBALS['FORUM_DRIVER']->member_profile_url($member_id, true, true), 0.0);
        }
    }
}
