<?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    quizzes
 */

require_code('crud_module');

/**
 * Module page class.
 */
class Module_cms_quiz extends Standard_crud_module
{
    public $lang_type = 'QUIZ';
    public $select_name = 'NAME';
    public $permissions_require = 'high';
    public $permissions_cat_require = 'quiz';
    public $permission_module = 'quiz';
    public $permissions_cat_name = null;
    public $user_facing = true;
    public $seo_type = 'quiz';
    public $content_type = 'quiz';
    public $view_entry_point = '_SEARCH:quiz:do:_ID';
    public $archive_entry_point = '_SEARCH:quiz:browse';
    public $javascript = 'var hide_func=function() { var ob=document.getElementById(\'type\'); if (ob.value==\'TEST\') { document.getElementById(\'percentage\').disabled=false; document.getElementById(\'num_winners\').disabled=true; }  if (ob.value==\'COMPETITION\') { document.getElementById(\'num_winners\').disabled=false; document.getElementById(\'percentage\').disabled=true; }  if (ob.value==\'SURVEY\') { document.getElementById(\'text\').value=document.getElementById(\'text\').value.replace(/ \[\*\]/g,\'\'); document.getElementById(\'num_winners\').disabled=true; document.getElementById(\'percentage\').disabled=true; } }; document.getElementById(\'type\').onchange=hide_func; hide_func();';
    public $menu_label = 'QUIZZES';
    public $table = 'quizzes';
    public $orderer = 'q_add_date';

    public $donext_type = null;
    public $donext_entry_content_type = 'quiz';
    public $donext_category_content_type = null;

    /**
     * Find privileges defined as overridable by this module.
     *
     * @return array A map of privileges that are overridable; privilege to 0 or 1. 0 means "not category overridable". 1 means "category overridable".
     */
    public function get_privilege_overrides()
    {
        require_lang('quiz');
        return array('submit_highrange_content' => array(0, 'ADD_QUIZ'), 'bypass_validation_highrange_content' => array(0, 'BYPASS_VALIDATION_QUIZ'), 'edit_own_highrange_content' => array(0, 'EDIT_OWN_QUIZ'), 'edit_highrange_content' => array(0, 'EDIT_QUIZ'), 'delete_own_highrange_content' => array(0, 'DELETE_OWN_QUIZ'), 'delete_highrange_content' => array(0, 'DELETE_QUIZ'));
    }

    /**
     * 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)
    {
        $ret = array(
            'browse' => array('MANAGE_QUIZZES', 'menu/rich_content/quiz'),
        ) + parent::get_entry_points();

        if ($support_crosslinks) {
            require_code('fields');
            $ret += manage_custom_fields_entry_points('quiz');
        }

        return $ret;
    }

    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');

        require_lang('quiz');

        inform_non_canonical_parameter('validated');

        set_helper_panel_tutorial('tut_quizzes');

        if ($type == 'browse') {
            if (has_actual_page_access(get_member(), 'admin_quiz')) {
                $also_url = build_url(array('page' => 'admin_quiz'), get_module_zone('admin_quiz'));
                attach_message(do_lang_tempcode('menus:ALSO_SEE_ADMIN', escape_html($also_url->evaluate())), 'inform', true);
            }
        }

        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('quiz');
        require_code('quiz2');

        $this->add_one_label = do_lang_tempcode('ADD_QUIZ');
        $this->edit_this_label = do_lang_tempcode('EDIT_THIS_QUIZ');
        $this->edit_one_label = do_lang_tempcode('EDIT_QUIZ');
        $this->archive_label = 'VIEW_ALL_QUIZZES';
        $this->view_label = do_lang_tempcode('TRY_QUIZ');

        if ($type == 'browse') {
            return $this->browse();
        }

        return new Tempcode();
    }

    /**
     * The do-next manager for before content management.
     *
     * @return Tempcode The UI
     */
    public function browse()
    {
        require_code('templates_donext');
        require_code('fields');
        return do_next_manager(get_screen_title('MANAGE_QUIZZES'), comcode_lang_string('DOC_QUIZZES'),
            array_merge(array(
                array('menu/_generic_admin/add_one', array('_SELF', array('type' => 'add'), '_SELF'), do_lang('ADD_QUIZ')),
                array('menu/_generic_admin/edit_one', array('_SELF', array('type' => 'edit'), '_SELF'), do_lang('EDIT_QUIZ')),
            ), manage_custom_fields_donext_link('quiz')),
            do_lang('MANAGE_QUIZZES')
        );
    }

    /**
     * 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', 'q_name ASC');
        if (strpos($current_ordering, ' ') === false) {
            warn_exit(do_lang_tempcode('INTERNAL_ERROR'));
        }
        list($sortable, $sort_order) = explode(' ', $current_ordering, 2);
        $sortables = array(
            'q_name' => do_lang_tempcode('TITLE'),
            'q_type' => do_lang_tempcode('TYPE'),
        );
        if (((strtoupper($sort_order) != 'ASC') && (strtoupper($sort_order) != 'DESC')) || (!array_key_exists($sortable, $sortables))) {
            log_hack_attack_and_exit('ORDERBY_HACK');
        }

        $_header_row = array(
            do_lang_tempcode('TITLE'),
            do_lang_tempcode('TYPE'),
            do_lang_tempcode('DATE'),
        );
        if (addon_installed('points')) {
            $_header_row[] = do_lang_tempcode('POINTS');
        }
        $_header_row[] = do_lang_tempcode('ACTIONS');
        $header_row = results_field_title($_header_row, $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');

            $type = do_lang_tempcode($row['q_type']);

            $results_entry = array(
                protect_from_escaping(hyperlink(build_url(array('page' => 'quiz', 'type' => 'do', 'id' => $row['id']), get_module_zone('quiz')), get_translated_text($row['q_name']), false, true)),
                $type,
                get_timezoned_date($row['q_add_date'], false),
            );
            if (addon_installed('points')) {
                $results_entry[] = integer_format($row['q_points_for_passing']);
            }
            $results_entry[] = protect_from_escaping(hyperlink($edit_link, do_lang_tempcode('EDIT'), false, true, do_lang('EDIT') . ' #' . strval($row['id'])));

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

        $search_url = build_url(array('page' => 'search', 'id' => 'quiz'), get_module_zone('search'));
        $archive_url = build_url(array('page' => 'quiz'), get_module_zone('quiz'));

        return array(results_table(do_lang($this->menu_label), get_param_integer('start', 0), 'start', either_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['SITE_DB']->query_select('quizzes', array('id', 'q_name'), null, 'ORDER BY q_add_date DESC', intval(get_option('general_safety_listing_limit')));
        $entries = new Tempcode();
        foreach ($_m as $m) {
            $entries->attach(form_input_list_entry(strval($m['id']), false, get_translated_text($m['q_name'])));
        }

        return $entries;
    }

    /**
     * Standard crud_module cat getter.
     *
     * @param  ID_TEXT $id The entry for which the cat is sought
     * @return mixed The cat
     */
    public function get_cat($id)
    {
        return $id;
    }

    /**
     * Get Tempcode for a adding/editing form.
     *
     * @param  ?AUTO_LINK $id The quiz ID (null: new)
     * @param  SHORT_TEXT $name The name of the quiz
     * @param  ?integer $timeout The number of minutes allowed for completion (null: NA)
     * @param  LONG_TEXT $start_text The text shown at the start of the quiz
     * @param  LONG_TEXT $end_text The text shown at the end of the quiz
     * @param  LONG_TEXT $end_text_fail The text shown at the end of the quiz on failure
     * @param  LONG_TEXT $notes Notes
     * @param  integer $percentage Percentage correctness required for competition
     * @param  ?TIME $open_time The time the quiz is opened (null: now)
     * @param  ?TIME $close_time The time the quiz is closed (null: never)
     * @param  integer $num_winners The number of winners for this if it is a competition
     * @param  ?integer $redo_time The minimum number of hours between attempts (null: no restriction)
     * @param  ID_TEXT $type The type
     * @set    SURVEY COMPETITION TEST
     * @param  BINARY $validated Whether this is validated
     * @param  ?string $text Text for questions (null: default)
     * @param  integer $points_for_passing The number of points awarded for completing/passing the quiz/test
     * @param  ?AUTO_LINK $tied_newsletter Newsletter for which a member must be on to enter (null: none)
     * @param  BINARY $reveal_answers Whether to reveal correct answers after the quiz is complete, so that the answerer can learn from the experience
     * @param  BINARY $shuffle_questions Whether to shuffle questions, to make cheating a bit harder
     * @param  BINARY $shuffle_answers Whether to shuffle multiple-choice answers, to make cheating a bit harder
     * @return array A pair: The input fields, Hidden fields
     */
    public function get_form_fields($id = null, $name = '', $timeout = null, $start_text = '', $end_text = '', $end_text_fail = '', $notes = '', $percentage = 70, $open_time = null, $close_time = null, $num_winners = 2, $redo_time = null, $type = 'SURVEY', $validated = 1, $text = null, $points_for_passing = 0, $tied_newsletter = null, $reveal_answers = 0, $shuffle_questions = 0, $shuffle_answers = 0)
    {
        if (is_null($open_time)) {
            $open_time = time();
        }

        if (is_null($text)) {
            $text = do_lang('EXAMPLE_QUESTIONS');
        }

        $fields = new Tempcode();
        $fields->attach(form_input_line(do_lang_tempcode('NAME'), do_lang_tempcode('DESCRIPTION_NAME'), 'name', $name, true));
        $list = new Tempcode();
        $list->attach(form_input_list_entry('SURVEY', $type == 'SURVEY', do_lang_tempcode('SURVEY')));
        $list->attach(form_input_list_entry('TEST', $type == 'TEST', do_lang_tempcode('TEST')));
        $list->attach(form_input_list_entry('COMPETITION', $type == 'COMPETITION', do_lang_tempcode('COMPETITION')));
        $fields->attach(form_input_list(do_lang_tempcode('TYPE'), do_lang_tempcode('DESCRIPTION_QUIZ_TYPE'), 'type', $list, null, true));
        $fields->attach(form_input_huge(do_lang_tempcode('QUESTIONS'), do_lang_tempcode('IMPORT_QUESTIONS_TEXT'), 'text', $text, true, null, 20, '', true));
        $fields->attach(form_input_text_comcode(do_lang_tempcode('QUIZ_START_TEXT'), do_lang_tempcode('DESCRIPTION_QUIZ_START_TEXT'), 'start_text', $start_text, false));
        $fields->attach(form_input_text_comcode(do_lang_tempcode('QUIZ_END_TEXT'), do_lang_tempcode('DESCRIPTION_QUIZ_END_TEXT'), 'end_text', $end_text, false));
        if ($validated == 0) {
            $validated = get_param_integer('validated', 0);
            if (($validated == 1) && (addon_installed('unvalidated'))) {
                attach_message(do_lang_tempcode('WILL_BE_VALIDATED_WHEN_SAVING'));
            }
        }
        if (addon_installed('unvalidated')) {
            $fields->attach(form_input_tick(do_lang_tempcode('VALIDATED'), do_lang_tempcode('DESCRIPTION_VALIDATED_SIMPLE'), 'validated', $validated == 1));
        }

        $fields->attach(do_template('FORM_SCREEN_FIELD_SPACER', array('_GUID' => '43499b3d39e5743f27852e84cd6d3296', 'TITLE' => do_lang_tempcode('TEST'), 'SECTION_HIDDEN' => $type != 'TEST')));
        $fields->attach(form_input_integer(do_lang_tempcode('COMPLETION_PERCENTAGE'), do_lang_tempcode('DESCRIPTION_COMPLETION_PERCENTAGE'), 'percentage', $percentage, true));
        $fields->attach(form_input_tick(do_lang_tempcode('REVEAL_ANSWERS'), do_lang_tempcode('DESCRIPTION_REVEAL_ANSWERS'), 'reveal_answers', $reveal_answers == 1));
        $fields->attach(form_input_text_comcode(do_lang_tempcode('QUIZ_END_TEXT_FAIL'), do_lang_tempcode('DESCRIPTION_QUIZ_END_TEXT_FAIL'), 'end_text_fail', $end_text_fail, false));

        $fields->attach(do_template('FORM_SCREEN_FIELD_SPACER', array('_GUID' => '40f0d67ae21fd3768cc7688d90c99d6e', 'TITLE' => do_lang_tempcode('COMPETITION'), 'SECTION_HIDDEN' => $type != 'COMPETITION')));
        $fields->attach(form_input_integer(do_lang_tempcode('NUM_WINNERS'), do_lang_tempcode('DESCRIPTION_NUM_WINNERS'), 'num_winners', $num_winners, true));

        $fields->attach(do_template('FORM_SCREEN_FIELD_SPACER', array(
            '_GUID' => '00b9a6a21eab07864d41d5465d9569cd',
            'SECTION_HIDDEN' => is_null($redo_time) && is_null($timeout) && ((is_null($open_time)) || ($open_time <= time())) && is_null($close_time) && $points_for_passing == 0 && is_null($tied_newsletter) && $notes == '',
            'TITLE' => do_lang_tempcode('ADVANCED'),
        )));
        $fields->attach(form_input_tick(do_lang_tempcode('SHUFFLE_QUESTIONS'), do_lang_tempcode('DESCRIPTION_SHUFFLE_QUESTIONS'), 'shuffle_questions', $shuffle_questions == 1));
        $fields->attach(form_input_tick(do_lang_tempcode('SHUFFLE_ANSWERS'), do_lang_tempcode('DESCRIPTION_SHUFFLE_ANSWERS'), 'shuffle_answers', $shuffle_answers == 1));
        $fields->attach(form_input_integer(do_lang_tempcode('REDO_TIME'), do_lang_tempcode('DESCRIPTION_REDO_TIME'), 'redo_time', $redo_time, false));
        $fields->attach(form_input_integer(do_lang_tempcode('TIMEOUT'), do_lang_tempcode('DESCRIPTION_QUIZ_TIMEOUT'), 'timeout', $timeout, false));
        $fields->attach(form_input_date(do_lang_tempcode('OPEN_TIME'), do_lang_tempcode('DESCRIPTION_OPEN_TIME'), 'open_time', true, false, true, $open_time, 2));
        $fields->attach(form_input_date(do_lang_tempcode('CLOSE_TIME'), do_lang_tempcode('DESCRIPTION_CLOSE_TIME'), 'close_time', false, is_null($close_time), true, is_null($close_time) ? (null/*time()+60*60*24*30*/) : $close_time, 2));
        if (addon_installed('points')) {
            $fields->attach(form_input_integer(do_lang_tempcode('POINTS_FOR_COMPLETING'), do_lang_tempcode('DESCRIPTION_POINTS_FOR_COMPLETING'), 'points_for_passing', $points_for_passing, true));
        }
        if (addon_installed('newsletter')) {
            $newsletters = new Tempcode();
            $newsletters->attach(form_input_list_entry('', false, do_lang_tempcode('NONE_EM')));
            $_newsletters = $GLOBALS['SITE_DB']->query_select('newsletters', array('*'), null, 'ORDER BY id');
            foreach ($_newsletters as $n) {
                $newsletters->attach(form_input_list_entry(strval($n['id']), $tied_newsletter == $n['id'], get_translated_text($n['title'])));
            }
            if (!$newsletters->is_empty()) {
                $fields->attach(form_input_list(do_lang_tempcode('TIED_TO_NEWSLETTER'), do_lang_tempcode('DESCRIPTION_TIED_TO_NEWSLETTER'), 'tied_newsletter', $newsletters, null, false, false));
            }
        }
        if (get_option('enable_staff_notes') == '1') {
            $fields->attach(form_input_text(do_lang_tempcode('NOTES'), do_lang_tempcode('DESCRIPTION_NOTES'), 'notes', $notes, false));
        }

        $fields->attach(metadata_get_fields('quiz', is_null($id) ? null : strval($id)));
        require_code('seo2');
        $fields->attach(seo_get_fields($this->seo_type, is_null($id) ? null : strval($id), false));

        if (addon_installed('content_reviews')) {
            $fields->attach(content_review_get_fields('quiz', is_null($id) ? null : strval($id)));
        }

        // Permissions
        $fields->attach($this->get_permission_fields(($id === null) ? null : strval($id), null, ($id === null)));

        return array($fields, new Tempcode());
    }

    /**
     * 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['SITE_DB']->query_select('quizzes', array('q_submitter', 'q_add_date'), array('id' => intval($id)), '', 1);
        if (!array_key_exists(0, $rows)) {
            return array(null, null);
        }
        return array($rows[0]['q_submitter'], $rows[0]['q_add_date']);
    }

    /**
     * Standard crud_module edit form filler.
     *
     * @param  ID_TEXT $_id The entry being edited
     * @return array A pair: The input fields, Hidden fields
     */
    public function fill_in_edit_form($_id)
    {
        $id = intval($_id);

        $myrows = $GLOBALS['SITE_DB']->query_select('quizzes', array('*'), array('id' => $id), '', 1);
        if (!array_key_exists(0, $myrows)) {
            warn_exit(do_lang_tempcode('MISSING_RESOURCE', 'quiz'));
        }
        $myrow = $myrows[0];

        $text = load_quiz_questions_to_string($id);

        return $this->get_form_fields(
            $myrow['id'],
            get_translated_text($myrow['q_name']),
            $myrow['q_timeout'],
            get_translated_text($myrow['q_start_text']),
            get_translated_text($myrow['q_end_text']),
            get_translated_text($myrow['q_end_text_fail']),
            $myrow['q_notes'],
            $myrow['q_percentage'],
            $myrow['q_open_time'],
            $myrow['q_close_time'],
            $myrow['q_num_winners'],
            $myrow['q_redo_time'],
            $myrow['q_type'],
            $myrow['q_validated'],
            $text,
            $myrow['q_points_for_passing'],
            $myrow['q_tied_newsletter'],
            $myrow['q_reveal_answers'],
            $myrow['q_shuffle_questions'],
            $myrow['q_shuffle_answers']
        );
    }

    /**
     * Standard crud_module add actualiser.
     *
     * @return ID_TEXT The ID of the new entry
     */
    public function add_actualisation()
    {
        $open_time = post_param_date('open_time');
        $close_time = post_param_date('close_time');

        $validated = post_param_integer('validated', 0);

        $_tied_newsletter = post_param_string('tied_newsletter', '');
        $tied_newsletter = ($_tied_newsletter == '') ? null : intval($_tied_newsletter);
        $name = post_param_string('name');

        $metadata = actual_metadata_get_fields('quiz', null);

        $id = add_quiz(
            $name,
            post_param_integer('timeout', null),
            post_param_string('start_text'),
            post_param_string('end_text'),
            post_param_string('end_text_fail'),
            post_param_string('notes', ''),
            post_param_integer('percentage', 0),
            $open_time,
            $close_time,
            post_param_integer('num_winners', 0),
            post_param_integer('redo_time', null),
            post_param_string('type'),
            $validated,
            post_param_string('text'),
            null,
            post_param_integer('points_for_passing', 0),
            $tied_newsletter,
            post_param_integer('reveal_answers', 0),
            post_param_integer('shuffle_questions', 0),
            post_param_integer('shuffle_answers', 0),
            $metadata['add_time']
        );

        set_url_moniker('quiz', strval($id));

        $this->set_permissions(strval($id));

        if (($validated == 1) || (!addon_installed('unvalidated'))) {
            if (has_actual_page_access(get_modal_user(), 'quiz')) {
                require_code('activities');
                syndicate_described_activity('quiz:ACTIVITY_ADD_QUIZ', $name, '', '', '_SEARCH:quiz:do:' . strval($id), '', '', 'quizzes');
            }
        }

        if (addon_installed('content_reviews')) {
            content_review_set('quiz', strval($id));
        }

        return strval($id);
    }

    /**
     * Standard crud_module edit actualiser.
     *
     * @param  ID_TEXT $_id The entry being edited
     */
    public function edit_actualisation($_id)
    {
        $id = intval($_id);

        $open_time = fractional_edit() ? INTEGER_MAGIC_NULL : post_param_date('open_time');
        $close_time = fractional_edit() ? INTEGER_MAGIC_NULL : post_param_date('close_time');

        $_tied_newsletter = post_param_string('tied_newsletter', '');
        $tied_newsletter = ($_tied_newsletter == '') ? null : intval($_tied_newsletter);
        if (fractional_edit()) {
            $tied_newsletter = INTEGER_MAGIC_NULL;
        }

        $name = post_param_string('name', STRING_MAGIC_NULL);
        $validated = post_param_integer('validated', fractional_edit() ? INTEGER_MAGIC_NULL : 0);

        if (($validated == 1) && ($GLOBALS['SITE_DB']->query_select_value_if_there('quizzes', 'q_validated', array('id' => $id)) === 0)) { // Just became validated, syndicate as just added
            $submitter = $GLOBALS['SITE_DB']->query_select_value('quizzes', 'q_submitter', array('id' => $id));

            if (has_actual_page_access(get_modal_user(), 'quiz')) {
                require_code('activities');
                syndicate_described_activity(($submitter != get_member()) ? 'quiz:ACTIVITY_VALIDATE_QUIZ' : 'quiz:ACTIVITY_ADD_QUIZ', $name, '', '', '_SEARCH:quiz:do:' . strval($id), '', '', 'quizzes', 1, null/*$submitter*/);
            }
        }

        $metadata = actual_metadata_get_fields('quiz', strval($id));

        edit_quiz(
            $id,
            $name,
            post_param_integer('timeout', fractional_edit() ? INTEGER_MAGIC_NULL : null),
            post_param_string('start_text', STRING_MAGIC_NULL),
            post_param_string('end_text', STRING_MAGIC_NULL),
            post_param_string('end_text_fail', STRING_MAGIC_NULL),
            post_param_string('notes', fractional_edit() ? STRING_MAGIC_NULL : ''),
            post_param_integer('percentage', fractional_edit() ? INTEGER_MAGIC_NULL : 0),
            $open_time,
            $close_time,
            post_param_integer('num_winners', fractional_edit() ? INTEGER_MAGIC_NULL : 0),
            post_param_integer('redo_time', fractional_edit() ? INTEGER_MAGIC_NULL : null),
            post_param_string('type', STRING_MAGIC_NULL),
            $validated,
            post_param_string('text', STRING_MAGIC_NULL),
            post_param_string('meta_keywords', fractional_edit() ? STRING_MAGIC_NULL : ''),
            post_param_string('meta_description', fractional_edit() ? STRING_MAGIC_NULL : ''),
            post_param_integer('points_for_passing', fractional_edit() ? INTEGER_MAGIC_NULL : 0),
            $tied_newsletter,
            post_param_integer('reveal_answers', fractional_edit() ? INTEGER_MAGIC_NULL : 0),
            post_param_integer('shuffle_questions', fractional_edit() ? INTEGER_MAGIC_NULL : 0),
            post_param_integer('shuffle_answers', fractional_edit() ? INTEGER_MAGIC_NULL : 0),
            $metadata['add_time'],
            $metadata['submitter'],
            true
        );

        if (!fractional_edit()) {
            $this->set_permissions(strval($id));
        }

        if (addon_installed('content_reviews')) {
            content_review_set('quiz', strval($id));
        }
    }

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

        delete_quiz($id);
    }
}
