コード例 #1
0
function test_auto_marking_sc($request)
{
    Authenticator::assert_manager_or_professor($request->cookies['authToken']);
    $msg = new Messages($GLOBALS['locale'], '/new-question/errors');
    try {
        $model = new Model();
        $raw_input = $request->getBody();
        $content_type = explode(';', $request->type)[0];
        if ($content_type !== 'application/json') {
            Util::output_errors_and_die($msg->_('invalid-format'), 415);
        }
        $input_data = json_decode($raw_input, true);
        if (empty($input_data) || !isset($input_data['question']) || !isset($input_data['source-code']) || !is_string($input_data['source-code'])) {
            Util::output_errors_and_die($msg->_('invalid-format'), 400);
        }
        $extra = !empty($input_data['extra']) ? $input_data['extra'] : [];
        $qd = $input_data['question'];
        set_empty_if_undefined($qd['type']);
        if ($qd['type'] != 'source-code') {
            Util::output_errors_and_die('', 400);
        }
        $q = new QuestionSC($qd, Question::FROM_USER, $extra);
        $q->mark_automatically(array('source-code' => $input_data['source-code']), $log, $result);
        http_response_code(200);
        header('Content-Type: application/json');
        echo my_json_encode($result);
    } catch (DatabaseException $e) {
        Util::output_errors_and_die($e->getMessage(), 503);
    } catch (Exception $e) {
        Util::output_errors_and_die($e->getMessage(), 400);
    }
}
コード例 #2
0
 public function from_user($qd, $extra = [])
 {
     parent::from_user($qd, $extra);
     $err = [];
     if ($this->auto_marking_method == 'binary') {
         if (!isset($qd['answer']) || empty($qd['answer'])) {
             $err['answer'] = $this->msg->_('sa-missing-answer');
         } elseif (!Validator::validate_answer($qd['answer'])) {
             $err['answer'] = $this->msg->_('answer-too-long');
         } else {
             $this->raw_answer = $qd['answer'];
         }
         $r = Validator::build_regex($qd['answer'], 'iu', true);
         if (!$r) {
             $err['answer'] = $this->msg->_('invalid-regex', [$qd['answer']]);
         } else {
             $this->answer = $r;
         }
     } else {
         set_empty_if_undefined($qd['answer']);
         if (!Validator::validate_answer($qd['answer'])) {
             $err['answer'] = $this->msg->_('answer-too-long');
         } else {
             $this->answer = $qd['answer'];
         }
     }
     if ($err) {
         throw new Exception(my_json_encode($err));
     }
 }
コード例 #3
0
function test_auto_marking($request)
{
    Authenticator::assert_manager_or_professor($request->cookies['authToken']);
    $msg = new Messages($GLOBALS['locale'], '/new-question/errors');
    try {
        $model = new Model();
        $raw_input = $request->getBody();
        $content_type = explode(';', $request->type)[0];
        if ($content_type !== 'application/json') {
            Util::output_errors_and_die($msg->_('invalid-format'), 415);
        }
        $input_data = json_decode($raw_input, true);
        if (empty($input_data) || !isset($input_data['question']) || !isset($input_data['studentAnswer'])) {
            Util::output_errors_and_die($msg->_('invalid-format'), 400);
        }
        $extra = !empty($input_data['extra']) ? $input_data['extra'] : [];
        $qd = $input_data['question'];
        set_empty_if_undefined($qd['type']);
        if (!Validator::validate_question_type($qd['type'])) {
            Util::output_errors_and_die($msg->_('invalid-type'), 400);
        }
        switch ($qd['type']) {
            case 'short-answer':
                $q = new QuestionSA($qd, Question::FROM_USER, $extra);
                break;
            case 'essay':
                $q = new QuestionES($qd, Question::FROM_USER, $extra);
                break;
            case 'multiple-choice':
                $q = new QuestionMC($qd, Question::FROM_USER, $extra);
                break;
            case 'matching':
                $q = new QuestionMA($qd, Question::FROM_USER, $extra);
                break;
            case 'fitb-type':
                $q = new QuestionFT($qd, Question::FROM_USER, $extra);
                break;
            case 'fitb-select':
                $q = new QuestionFS($qd, Question::FROM_USER, $extra);
                break;
            case 'source-code':
                $q = new QuestionSC($qd, Question::FROM_USER, $extra);
                break;
        }
        http_response_code(200);
        header('Content-Type: application/json');
        $mark = $q->mark_automatically($input_data['studentAnswer'], $log);
        foreach ($log as $i => $line) {
            $log[$i] = $msg->_('/auto-marking/' . $line[0], $line[1]);
        }
        $log = implode('<br/>', $log);
        echo my_json_encode(array('log' => $log, 'mark' => $mark));
    } catch (DatabaseException $e) {
        Util::output_errors_and_die($e->getMessage(), 503);
    } catch (Exception $e) {
        Util::output_errors_and_die($e->getMessage(), 400);
    }
}
コード例 #4
0
function create_session($request)
{
    $raw_input = $request->getBody();
    $content_type = explode(';', $request->type)[0];
    switch ($content_type) {
        case 'application/json':
            $input_data = json_decode($raw_input, true);
            break;
        case 'application/x-www-form-urlencoded':
            $input_data = array();
            parse_str($raw_input, $input_data);
            break;
        default:
            Util::output_errors_and_die('', 415);
    }
    if ($input_data === null) {
        Util::output_errors_and_die('', 400);
    }
    set_empty_if_undefined($input_data['username_or_email']);
    set_empty_if_undefined($input_data['password']);
    $msg = new Messages($GLOBALS['locale'], '/signin');
    try {
        $model = new Model();
        $user_data = $model->is_valid_user($input_data['username_or_email'], $input_data['password']);
        if (!$user_data) {
            Util::output_errors_and_die($msg->_('invalid-username-pw'), 403);
        }
        switch ($user_data['status']) {
            case 'pending-activation':
                Util::output_errors_and_die($msg->_('pending-activation'), 403);
                break;
            case 'pending-approval':
                Util::output_errors_and_die($msg->_('pending-approval'), 403);
                break;
            case 'banned':
                Util::output_errors_and_die($msg->_('banned'), 403);
                break;
            case 'active':
                $token = generate_token($user_data);
                $now = new DateTime('now');
                $expires_at = clone $now;
                $expires_at->add(new DateInterval('P7D'));
                $model->insert_auth_token($user_data['user_id'], $token, $now, $expires_at);
                http_response_code(201);
                $output = array('token' => $token, 'expires_at' => $expires_at->format('Y-m-d H:i:s'));
                setcookie('authToken', $token, $expires_at->getTimestamp(), '/', '', $secure = true, $httponly = true);
                header('Content-Type: application/json');
                echo my_json_encode($output);
                die;
                break;
        }
    } catch (DatabaseException $e) {
        Util::output_errors_and_die($e->getMessage(), 503);
    } catch (Exception $e) {
        Util::output_errors_and_die($e->getMessage(), 400);
    }
}
コード例 #5
0
function create_user($request)
{
    $raw_input = $request->getBody();
    $content_type = explode(';', $request->type)[0];
    switch ($content_type) {
        case 'application/json':
            $input_data = json_decode($raw_input, true);
            break;
        case 'application/x-www-form-urlencoded':
            $input_data = array();
            parse_str($raw_input, $input_data);
            break;
        default:
            Util::output_errors_and_die('', 415);
    }
    if ($input_data === null) {
        Util::output_errors_and_die('', 400);
    }
    $fields = array('full_name' => '', 'email' => '', 'gender' => '', 'birth_date' => '', 'username' => '', 'role' => '');
    $user_data = array();
    foreach ($fields as $f => $v) {
        if (array_key_exists($f, $input_data)) {
            if (!is_string($input_data[$f])) {
                Util::output_errors_and_die('', 400);
            }
            $user_data[$f] = trim($input_data[$f]);
        } else {
            $user_data[$f] = '';
        }
    }
    if (isset($input_data['password'])) {
        if (!is_string($input_data['password'])) {
            Util::output_errors_and_die('', 400);
        }
        $user_data['password'] = $input_data['password'];
    }
    set_empty_if_undefined($user_data['password']);
    try {
        $model = new Model();
        $uid = $model->create_user($user_data);
    } catch (DatabaseException $e) {
        Util::output_errors_and_die($e->getMessage(), 503);
    } catch (ConflictException $e) {
        Util::output_errors_and_die($e->getMessage(), 409);
    } catch (Exception $e) {
        Util::output_errors_and_die($e->getMessage(), 400);
    }
    if ($uid) {
        http_response_code(201);
        header('Content-Type: text/plain');
        echo '/users/' . $uid;
        die;
    } else {
        Util::output_errors_and_die('', 400);
    }
}
コード例 #6
0
function create_question($request, $assignment_id = null)
{
    Authenticator::assert_manager_or_professor($request->cookies['authToken']);
    $msg = new Messages($GLOBALS['locale']);
    try {
        $model = new Model();
        $raw_input = $request->getBody();
        $content_type = explode(';', $request->type)[0];
        if ($content_type !== 'application/json') {
            Util::output_errors_and_die('', 415);
        }
        $input_data = json_decode($raw_input, true);
        if (empty($input_data)) {
            Util::output_errors_and_die('', 400);
        }
        set_empty_if_undefined($input_data['type']);
        if (!Validator::validate_question_type($input_data['type'])) {
            Util::output_errors_and_die($msg->_('invalid-type'), 400);
        }
        switch ($input_data['type']) {
            case 'short-answer':
                $q = new QuestionSA($input_data, Question::FROM_USER);
                break;
            case 'essay':
                $q = new QuestionES($input_data, Question::FROM_USER);
                break;
            case 'multiple-choice':
                $q = new QuestionMC($input_data, Question::FROM_USER);
                break;
            case 'matching':
                $q = new QuestionMA($input_data, Question::FROM_USER);
                break;
            case 'fitb-type':
                $q = new QuestionFT($input_data, Question::FROM_USER);
                break;
            case 'fitb-select':
                $q = new QuestionFS($input_data, Question::FROM_USER);
                break;
            case 'source-code':
                $q = new QuestionSC($input_data, Question::FROM_USER);
                break;
        }
        $qid = $model->create_question($q);
        header('Content-Type: text/plain');
        echo '/question_bank/questions/' . $qid;
        http_response_code(201);
        die;
    } catch (ConflictException $e) {
        Util::output_errors_and_die($e->getMessage(), 409);
    } catch (DatabaseException $e) {
        Util::output_errors_and_die($e->getMessage(), 503);
    } catch (Exception $e) {
        Util::output_errors_and_die($e->getMessage(), 400);
    }
}
コード例 #7
0
function test_question($request)
{
    Authenticator::assert_manager_or_professor($request->cookies['authToken']);
    $msg = new Messages($GLOBALS['locale'], '/new-question/errors');
    try {
        $model = new Model();
        $raw_input = $request->getBody();
        $content_type = explode(';', $request->type)[0];
        if ($content_type !== 'application/json') {
            Util::output_errors_and_die($msg->_('invalid-format'), 415);
        }
        $input_data = json_decode($raw_input, true);
        if (empty($input_data)) {
            Util::output_errors_and_die($msg->_('invalid-format'), 400);
        }
        set_empty_if_undefined($input_data['type']);
        if (!Validator::validate_question_type($input_data['type'])) {
            Util::output_errors_and_die($msg->_('invalid-type'), 400);
        }
        switch ($input_data['type']) {
            case 'short-answer':
                $q = new QuestionSA($input_data, Question::FROM_USER);
                break;
            case 'essay':
                $q = new QuestionES($input_data, Question::FROM_USER);
                break;
            case 'multiple-choice':
                $q = new QuestionMC($input_data, Question::FROM_USER);
                break;
            case 'matching':
                $q = new QuestionMA($input_data, Question::FROM_USER);
                break;
            case 'fitb-type':
                $q = new QuestionFT($input_data, Question::FROM_USER);
                break;
            case 'fitb-select':
                $q = new QuestionFS($input_data, Question::FROM_USER);
                break;
            case 'source-code':
                $q = new QuestionSC($input_data, Question::FROM_USER);
                break;
        }
        http_response_code(200);
        header('Content-Type: application/json');
        echo my_json_encode($q->to_auto_marking_test(true, true));
    } catch (DatabaseException $e) {
        Util::output_errors_and_die($e->getMessage(), 503);
    } catch (Exception $e) {
        Util::output_errors_and_die($e->getMessage(), 400);
    }
}
コード例 #8
0
 public function from_user($qd, $extra = [])
 {
     parent::from_user($qd, $extra);
     $err = [];
     set_empty_if_undefined($qd['answer']);
     if (!Validator::validate_answer($qd['answer'])) {
         $err['answer'] = $this->msg->_('answer-too-long');
     } else {
         $this->answer = $qd['answer'];
     }
     if ($err) {
         throw new Exception(my_json_encode($err));
     }
 }
コード例 #9
0
 function create_programming_language($pl_data, $existing_id = null)
 {
     if (empty($pl_data)) {
         throw new Exception('-');
     }
     $this->conn->beginTransaction();
     if ($existing_id) {
         // ensure that it exists
         $sql = 'SELECT COUNT(*) AS n
            FROM `programming_language`
            WHERE programming_language_id = ?;';
         $s = $this->conn->prepare($sql);
         if (!$s) {
             $this->conn->rollBack();
             throw new DatabaseException($this->conn->errorInfo()[2]);
         }
         if (!$s->execute(array($existing_id))) {
             $this->conn->rollBack();
             throw new DatabaseException($s->errorInfo()[2]);
         }
         $n = $s->fetch(PDO::FETCH_ASSOC)['n'];
         if ($n < 1) {
             $this->conn->rollBack();
             return false;
         }
         $sql = 'DELETE FROM `compiler_flag`
            WHERE programming_language_id = ?;';
         $s = $this->conn->prepare($sql);
         if (!$s) {
             $this->conn->rollBack();
             throw new DatabaseException($this->conn->errorInfo()[2]);
         }
         if (!$s->execute(array($existing_id))) {
             $this->conn->rollBack();
             throw new DatabaseException($s->errorInfo()[2]);
         }
     }
     $fields = array('display_name', 'default_extension', 'editor_mode', 'check_command', 'compile_command', 'run_command');
     foreach ($fields as $f) {
         set_empty_if_undefined($pl_data[$f]);
         if (!is_string($pl_data[$f])) {
             throw new Exception();
         }
         $pl_data[$f] = trim($pl_data[$f]);
     }
     $pl_data['default_extension'] = trim(preg_replace('/^\\.+/', '', trim($pl_data['default_extension'])));
     $err = array();
     $this->msg->set_root('/new-pl/errors');
     if (!Validator::validate_pl_display_name($pl_data['display_name'])) {
         $err['display_name'] = $this->msg->_('display_name', array(1, 32));
     }
     if (!Validator::validate_pl_extension($pl_data['default_extension'])) {
         $err['default_extension'] = $this->msg->_('default_extension', array(1, 7));
     }
     if (!Validator::validate_pl_editor_mode($pl_data['editor_mode'])) {
         $err['editor_mode'] = $this->msg->_('editor_mode', array(31));
     }
     if (!Validator::validate_pl_command($pl_data['check_command'], false)) {
         $err['check_command'] = $this->msg->_('check_command', array(127));
     }
     if (!Validator::validate_pl_command($pl_data['compile_command'], false)) {
         $err['compile_command'] = $this->msg->_('compile_command', array(127));
     }
     if (!Validator::validate_pl_command($pl_data['run_command'], true)) {
         $err['run_command'] = $this->msg->_('run_command', array(1, 127));
     }
     if (!empty($err)) {
         $this->conn->rollBack();
         throw new Exception(my_json_encode($err));
     }
     if (!$existing_id) {
         $sql1 = 'INSERT IGNORE INTO `programming_language`
             (display_name, default_extension, editor_mode,
              check_command, compile_command, run_command)
            VALUES (:display_name, :default_extension, :editor_mode,
              :check_command, :compile_command, :run_command);';
     } else {
         $sql1 = 'UPDATE `programming_language`
            SET
              display_name = :display_name,
              default_extension = :default_extension,
              editor_mode = :editor_mode,
              check_command = :check_command,
              compile_command = :compile_command,
              run_command = :run_command
            WHERE
              programming_language_id = :pl_id;';
     }
     $s = $this->conn->prepare($sql1);
     if (!$s) {
         throw new DatabaseException($this->conn->errorInfo()[2]);
         $this->conn->rollBack();
     }
     $s->bindValue(':display_name', $pl_data['display_name']);
     $s->bindValue(':default_extension', $pl_data['default_extension']);
     $s->bindValue(':editor_mode', null_if_empty_string($pl_data['editor_mode']));
     $s->bindValue(':check_command', null_if_empty_string($pl_data['check_command']));
     $s->bindValue(':compile_command', null_if_empty_string($pl_data['compile_command']));
     $s->bindValue(':run_command', $pl_data['run_command']);
     if ($existing_id) {
         $s->bindValue(':pl_id', $existing_id);
     }
     if (!$s->execute()) {
         $this->conn->rollBack();
         throw new DatabaseException($s->errorInfo()[2]);
     }
     if (!$existing_id and $s->rowCount() < 1) {
         $this->conn->rollBack();
         $err[] = array('display_name' => $this->msg->_('display_name.exists'));
         throw new ConflictException(my_json_encode($err));
     }
     $lid = $existing_id ? $existing_id : $this->conn->lastInsertId();
     if (!isset($pl_data['compiler_flags'])) {
         $pl_data['compiler_flags'] = array();
     }
     $sql2 = 'INSERT INTO `compiler_flag`
            (flag, description, programming_language_id, enabled_by_default)
          VALUES ';
     $sql2_items = array();
     $arguments2 = array();
     foreach ($pl_data['compiler_flags'] as $cf) {
         set_empty_if_undefined($cf['flag']);
         set_empty_if_undefined($cf['description']);
         if (!isset($cf['enabled_by_default'])) {
             $cf['enabled_by_default'] = false;
         }
         if (!Validator::validate_pl_flag($cf['flag'])) {
             $err['flag'] = $this->msg->_('flag', [1, 31]);
         }
         if (!Validator::validate_boolean($cf['enabled_by_default'])) {
             $l = array(1, 31);
             $err['enabled_by_default'] = $this->msg->_('enabled_by_default', $l);
         }
         if (!Validator::validate_pl_flag_description($cf['description'])) {
             $err['description'] = $this->msg->_('flag_description', [63]);
         }
         $sql2_items[] = ' (?, ?, ?, ?)';
         $arguments2[] = $cf['flag'];
         $arguments2[] = null_if_empty_string($cf['description']);
         $arguments2[] = $lid;
         $arguments2[] = (int) $cf['enabled_by_default'];
     }
     if (!empty($err)) {
         $this->conn->rollBack();
         throw new Exception(my_json_encode($err));
     }
     if ($arguments2) {
         $sql2 .= implode(', ', $sql2_items) . ';';
         $s = $this->conn->prepare($sql2);
         if (!$s) {
             $this->conn->rollBack();
             throw new DatabaseException($this->conn->errorInfo()[2]);
         }
         if (!$s->execute($arguments2)) {
             $this->conn->rollBack();
             throw new DatabaseException($s->errorInfo()[2]);
         }
     }
     $this->conn->commit();
     return $lid;
 }
コード例 #10
0
 protected function from_user($qd, $extra = array())
 {
     $msg = $this->msg;
     $msg->set_root('/new-question/errors');
     $err = array();
     $this->is_template = true;
     $this->assignment_id = null;
     if (!isset($qd['title'])) {
         $qd['title'] = '';
     }
     if (!Validator::validate_question_title($qd['title'])) {
         $err['title'] = $msg->_('title', [1, 127]);
     }
     $this->title = $qd['title'];
     if (!isset($qd['programming_language_id'])) {
         $this->programming_language_id = null;
         $this->programming_language_name = null;
     } else {
         $pl = $this->model->get_programming_language($qd['programming_language_id']);
         if (!$pl) {
             $err['programming_language_id'] = $msg->_('pl_id');
         }
         $this->programming_language_id = $qd['programming_language_id'];
         $this->programming_language_name = $pl['display_name'];
         $this->programming_language_data = $pl;
     }
     if (!isset($qd['topic_ids'])) {
         $this->topic_ids = [];
     } elseif (!is_array($qd['topic_ids'])) {
         $err['topic_ids'] = $msg->_('invalid-format');
     } else {
         $this->topic_ids = [];
         $this->topic_names = [];
         $all_topics = array();
         foreach ($this->model->get_topics()['items'] as $t) {
             $all_topics[$t['topic_id']] = $t['name'];
         }
         foreach (array_unique($qd['topic_ids']) as $id) {
             if (!array_key_exists($id, $all_topics)) {
                 if (!isset($err['topic_ids'])) {
                     $err['topic_ids'] = '';
                 }
                 $err['topic_ids'] .= $msg->_('topic_ids', [$id]) . ' ';
             } else {
                 $this->topic_ids[] = $id;
                 $this->topic_names[] = $all_topics[$id];
             }
         }
     }
     if (isset($qd['new_topics'])) {
         if (!is_array($qd['topic_ids'])) {
             $err['new_topics'] = $msg->_('invalid-format');
         } else {
             foreach ($qd['new_topics'] as $topic) {
                 if (!Validator::validate_topic($topic)) {
                     $err['new_topics'] = $msg->_('/new-topic/error', array(1, 127));
                 } elseif (in_array($topic, $all_topics)) {
                     $this->topic_ids[] = array_search($topic, $all_topics);
                     $this->topic_names[] = $topic;
                 } else {
                     $this->topic_ids[] = null;
                     $this->topic_names[] = $topic;
                 }
             }
         }
     }
     set_empty_if_undefined($qd['level']);
     if (!Validator::validate_level($qd['level'])) {
         $err['level'] = $msg->_('level');
     } else {
         $this->level = $qd['level'];
     }
     if (!isset($qd['auto_marking_method']) || $qd['auto_marking_method'] === 'none') {
         $qd['auto_marking_method'] = null;
     } elseif (in_array($qd['auto_marking_method'], $this->valid_amm, true)) {
         $this->auto_marking_method = $qd['auto_marking_method'];
     } else {
         $err['auto_marking_method'] = $msg->_('amm', array('nMethods' => count($this->valid_amm), 'methods' => implode('; ', $this->valid_amm)));
     }
     set_empty_if_undefined($qd['body']);
     $qd['body'] = Validator::clean_HTML($qd['body']);
     if (!Validator::validate_question_body($qd['body'])) {
         $err['body'] = $msg->_('body-too-long');
     } else {
         $this->body = $qd['body'];
     }
     if ($err) {
         throw new Exception(my_json_encode($err));
     }
 }
コード例 #11
0
 public function from_user($qd, $extra = array())
 {
     parent::from_user($qd, $extra);
     $err = [];
     if (!isset($qd['answers'])) {
         $qd['answers'] = array();
     }
     if (!is_array($qd['answers'])) {
         $err['answers'] = $msg->_('invalid-format');
     }
     if (!empty($extra)) {
         if (!is_array($extra) || count($extra) != count($qd['answers'])) {
             $k = '/new-question/errors/invalid-format';
             throw new Exception($this->msg->_($k));
         }
     } else {
         $extra = false;
     }
     foreach ($qd['answers'] as $i => $a) {
         if (!is_array($a) || !(!empty($a['text']) && isset($a['fixed']) && isset($a['correct'])) || !is_string($a['text']) || !Validator::validate_boolean($a['fixed']) || !Validator::validate_boolean($a['correct'])) {
             $err['answers'] = $this->msg->_('invalid-format');
             break;
         }
         if (!$extra) {
             $hex_strings = [];
             do {
                 $hex_id = '#' . random_hex_string(8);
             } while (in_array($hex_id, $hex_strings));
             // just in case
             $hex_strings[] = $hex_id;
         } else {
             $hex_id = $extra[$i];
         }
         $this->answers[] = array('text' => $a['text'], 'correct' => $a['correct'], 'fixed' => $a['fixed'], 'hex_id' => $hex_id);
         $this->answers_by_hex_id[$hex_id] = array('text' => $a['text'], 'correct' => $a['correct'], 'fixed' => $a['fixed']);
         if ($a['correct']) {
             $this->correct_answers++;
         }
         $this->total_answers++;
     }
     if ($this->total_answers == 0) {
         $err['answers'] = $this->msg->_('mc-at-least-one');
     }
     if ($err) {
         throw new Exception(my_json_encode($err));
     }
     set_empty_if_undefined($qd['min_answers']);
     set_empty_if_undefined($qd['max_answers']);
     if (!is_int($qd['min_answers'])) {
         $err['min_answers'] = $this->msg->_('invalid-format');
     } elseif (!($qd['min_answers'] >= 0) || !($qd['min_answers'] <= $this->correct_answers)) {
         $err['min_answers'] = $this->msg->_('mc-min');
     } elseif ($qd['min_answers'] == $this->total_answers) {
         $err['min-answers'] = $this->msg->_('mc-min-lt-total');
     } else {
         $this->min_answers = $qd['min_answers'];
     }
     if (!is_int($qd['max_answers'])) {
         $err['max_answers'] = $this->msg->_('invalid-format');
     } elseif (!($qd['max_answers'] >= $this->correct_answers) || !($qd['max_answers'] <= $this->total_answers)) {
         $err['max_answers'] = $this->msg->_('mc-max');
     } elseif ($qd['max_answers'] == 0) {
         $err['max-answers'] = $this->msg->_('mc-max-gt-zero');
     } else {
         $this->max_answers = $qd['max_answers'];
     }
     if ($err) {
         throw new Exception(my_json_encode($err));
     }
 }