Skip to content
Snippets Groups Projects
textdownload.php 4.43 KiB
Newer Older
  • Learn to ignore specific revisions
  • <?php
    // This file is part of Stack - http://stack.maths.ed.ac.uk/
    //
    // Stack is free software: you can redistribute it and/or modify
    // it under the terms of the GNU General Public License as published by
    // the Free Software Foundation, either version 3 of the License, or
    // (at your option) any later version.
    //
    // Stack is distributed in the hope that it will be useful,
    // but WITHOUT ANY WARRANTY; without even the implied warranty of
    // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    // GNU General Public License for more details.
    //
    // You should have received a copy of the GNU General Public License
    // along with Stack.  If not, see <http://www.gnu.org/licenses/>.
    
    /**
     * This script serves text files generated on demand by rendering CASText
     * of a given question with a given seed. For generated data transfer needs.
     *
     * @copyright  2021 Aalto University
     * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
     */
    
    require_once(__DIR__ . '/../../../config.php');
    
    require_once(__DIR__ . '/vle_specific.php');
    
    
    global $CFG;
    require_once($CFG->libdir . '/questionlib.php');
    
    require_login();
    
    
    Chris Sangwin's avatar
    Chris Sangwin committed
    // Start by checking that we have what we need.
    
    if (!(isset($_GET['qaid']) && isset($_GET['id']) && isset($_GET['name']))) {
        header('HTTP/1.0 404 Not Found');
        header('Content-Type: text/plain;charset=UTF-8');
        echo 'Incomplete request';
        die();
    }
    
    // Extract the details we need for this action.
    $qaid = $_GET['qaid'];
    $tdid = $_GET['id'];
    $name = $_GET['name'];
    
    // Check that they are of the correct type.
    if (!is_numeric($qaid) || !is_numeric($tdid)) {
        header('HTTP/1.0 404 Not Found');
        header('Content-Type: text/plain;charset=UTF-8');
        echo 'Incomplete request';
    
    Chris Sangwin's avatar
    Chris Sangwin committed
        die();
    
    }
    
    // So what we are doing is that we need to instanttiate the question
    // of that attempt to have correct seed and then we need to render
    // that specific td-file and serve it out with a specific name.
    $dm = new question_engine_data_mapper();
    $qa = $dm->load_question_attempt($qaid);
    $question = $qa->get_question();
    
    $question->apply_attempt_state($qa->get_step(0));
    
    // We have a slight problem accessing the user connected to that attempt and
    // therefore this will only work with `quiz` type activities for now.
    $params = [$qa->get_usage_id(), 'mod_quiz'];
    
    Chris Sangwin's avatar
    Chris Sangwin committed
    $tmp = $DB->get_record_sql('SELECT qas.userid FROM {quiz_attempts} qas, {question_usages} qu ' .
        'WHERE qu.id = ? AND qu.component = ? AND qu.id = qas.uniqueid;', $params, IGNORE_MISSING);
    
    $usageuser = -1;
    if ($tmp !== false) {
        $usageuser = $tmp->userid;
    }
    
    if (!(stack_user_can_view_question($question) || $USER->id === $usageuser)) {
    
        header('HTTP/1.0 403 Forbidden');
        header('Content-Type: text/plain;charset=UTF-8');
        echo 'This question is not accessible for the active user';
    
    Chris Sangwin's avatar
    Chris Sangwin committed
        die();
    
    }
    // Unlock session during instantiation.
    \core\session\manager::write_close();
    
    // Make sure that the cache is good, as this is one of those places where
    
    Chris Sangwin's avatar
    Chris Sangwin committed
    // the identifier for the cached item comes from outside and we cannot
    
    // cannot directly ask for it as that would allow people to force the cache
    // to be regenerated.
    
    // This will generate the cache if it is missing, which is highly unlikely.
    
    Chris Sangwin's avatar
    Chris Sangwin committed
    $question->get_cached('units');
    
    
    if (!isset($question->compiledcache['castext-td-' . $tdid])) {
        header('HTTP/1.0 404 Not Found');
        header('Content-Type: text/plain;charset=UTF-8');
        echo 'No such textdownload object in this question';
    
    Chris Sangwin's avatar
    Chris Sangwin committed
        die();
    
    }
    
    require_once(__DIR__ . '/stack/cas/castext2/castext2_evaluatable.class.php');
    
    Chris Sangwin's avatar
    Chris Sangwin committed
    $ct = castext2_evaluatable::make_from_compiled($question->compiledcache['castext-td-' .
        $tdid], $name, new castext2_static_replacer($question->get_cached('static-castext-strings')));
    
    
    // Get the context from the question.
    
    $ses = new stack_cas_session2([], $question->options, $question->seed);
    
    $question->add_question_vars_to_session($ses);
    
    $ses->add_statement($ct);
    
    // Is it valid?
    if (!$ses->get_valid()) {
        header('HTTP/1.0 500 Internal Server Error');
        header('Content-Type: text/plain;charset=UTF-8');
    
    Chris Sangwin's avatar
    Chris Sangwin committed
        echo 'Unknown issue related to the generation of this data.';
    
    Chris Sangwin's avatar
    Chris Sangwin committed
        die();
    
    }
    
    // Render it.
    $ses->instantiate();
    $content = $ct->get_rendered();
    
    
    Chris Sangwin's avatar
    Chris Sangwin committed
    // Now pick some sensible headers.
    
    header('HTTP/1.0 200 OK');
    header("Content-Disposition: attachment; filename=\"$name\"");
    if (strripos($name, '.csv') === strlen($name) - 4) {
        header('Content-Type: text/csv;charset=UTF-8');
    } else {
        header('Content-Type: text/plain;charset=UTF-8');
    }
    
    Chris Sangwin's avatar
    Chris Sangwin committed
    echo($content);