/** * Emit the text and form fields to support the done option */ public static function done() { global $USER; if (!$USER->instructor) { return; } $done = Settings::linkGet('done', ''); ?> <label for="done"> This option allows you to control the existance and behavior of a "Done" button for this tool. If you leave this blank the tool will assume it is in an iFrame and will not show a Done button. If you put a URL here, a Done button will be shown and when pressed the tool will navigate to the specified URL. If you expect to launch this tool in a popup, enter "_close" here and the tool will close its window when Done is pressed.<br/> <input type="text" class="form-control" value="<?php echo htmlspec_utf8($done); ?> " name="done"></label> <?php }
/** * Emit a properly styled done button for use in the launched frame/window * * This is a bit tricky because custom settings can control the "Done" * behavior. These settings can come from one of three places: (1) * in the link settings, (2) from a custom parameter named 'done', or * (3) from a GET parameter done= * * The value for this is a URL, "_close", or "_return". * * TODO: Implement _return */ function exitButton($text = false) { if ($text === false) { $text = _m("Exit"); } $url = Settings::linkGet('done'); if ($url == false) { if (isset($_SESSION['lti_post']) && isset($_SESSION['lti_post']['custom_done'])) { $url = $_SESSION['lti_post']['custom_done']; } else { if (isset($_GET["done"])) { $url = $_GET['done']; } } } // If we have no where to go and nothing to do, if ($url === false || strlen($url) < 1) { return; } $button = "btn-success"; if ($text == "Cancel" || $text == _m("Cancel")) { $button = "btn-warning"; } if ($url == "_close") { echo "<a href=\"#\" onclick=\"window.close();\" class=\"btn " . $button . "\">" . $text . "</a>\n"; } else { echo "<a href==\"{$url}\" class=\"btn " . $button . "\">" . $text . "</button>\n"; } }
require_once "../../config.php"; require_once $CFG->dirroot . "/pdo.php"; require_once $CFG->dirroot . "/lib/lms_lib.php"; use Tsugi\Core\Settings; use Tsugi\Core\LTIX; use Tsugi\UI\SettingsForm; $LTI = LTIX::requireData(); $p = $CFG->dbprefix; if (SettingsForm::handleSettingsPost()) { header('Location: ' . addSession('index.php')); return; } // All the assignments we support $assignments = array('single_mysql.php' => 'Single Table MySQL (Users)', 'single_lite.php' => 'Single Table SQLITE (Users)', 'count_lite.php' => 'Email Counter SQLITE', 'many_one_lite.php' => 'Many-to-One SQLITE (Tracks)', 'many_many_mysql.php' => 'Many-to-Many MySQL (Courses)', 'many_many_lite.php' => 'Many-to-Many SQLITE (Courses)'); $oldsettings = Settings::linkGetAll(); $assn = Settings::linkGet('exercise'); // Get any due date information $dueDate = SettingsForm::getDueDate(); // Let the assignment handle the POST if (count($_POST) > 0 && $assn && isset($assignments[$assn])) { include $assn; return; } // View $OUTPUT->header(); $OUTPUT->bodyStart(); // Settings button and dialog echo '<span style="position: fixed; right: 10px; top: 5px;">'; if ($USER->instructor) { echo '<a href="grades.php" target="_blank"><button class="btn btn-info">Grade detail</button></a> ' . "\n"; }
/** * Extract all of the post data, set up data in tables, and set up session. */ public static function setupSession() { global $CFG, $PDOX; if (!LTI::isRequest()) { return false; } // Pull LTI data out of the incoming $_POST and map into the same // keys that we use in our database (i.e. like $row) $post = self::extractPost(); if ($post === false) { $pdata = safe_var_dump($_POST); error_log('Missing post data: ' . $pdata); require 'lti/nopost.php'; return; } if ($post['key'] == '12345' && !$CFG->DEVELOPER) { die_with_error_log('You can only use key 12345 in developer mode'); } // We make up a Session ID Key because we don't want a new one // each time the same user launches the same link. $session_id = self::getCompositeKey($post, $CFG->sessionsalt); session_id($session_id); session_start(); header('Content-Type: text/html; charset=utf-8'); // Since we might reuse session IDs, clean everything out session_unset(); $_SESSION['LAST_ACTIVITY'] = time(); // update last activity time stamp // Read all of the data from the database with a very long // LEFT JOIN and get all the data we have back in the $row variable // $row = loadAllData($CFG->dbprefix, false, $post); $row = self::loadAllData($CFG->dbprefix, $CFG->dbprefix . 'profile', $post); $delta = 0; if (isset($_POST['oauth_timestamp'])) { $server_time = $_POST['oauth_timestamp'] + 0; $delta = abs(time() - $server_time); if ($delta > 480) { // More than four minutes is getting close error_log('Warning: Time skew, delta=' . $delta . ' sever_time=' . $server_time . ' our_time=' . time()); } } // Check the nonce to make sure there is no reuse if ($row['nonce'] !== null) { die_with_error_log('OAuth nonce error key=' . $post['key'] . ' nonce=' . $row['nonce']); } // Use returned data to check the OAuth signature on the // incoming data - returns true or an array $valid = LTI::verifyKeyAndSecret($post['key'], $row['secret']); // If there is a new_secret it means an LTI2 re-registration is in progress and we // need to check both the current and new secret until the re-registration is committed if ($valid !== true && strlen($row['new_secret']) > 0 && $row['new_secret'] != $row['secret']) { $valid = LTI::verifyKeyAndSecret($post['key'], $row['new_secret']); if ($valid) { $row['secret'] = $row['new_secret']; } $row['new_secret'] = null; } if ($valid !== true) { print "<pre>\n"; print_r($valid); print "</pre>\n"; die_with_error_log('OAuth validation fail key=' . $post['key'] . ' delta=' . $delta . ' error=' . $valid[0]); } $actions = self::adjustData($CFG->dbprefix, $row, $post); // Record the nonce but first probabilistically check if ($CFG->noncecheck > 0) { if (time() % $CFG->noncecheck == 0) { $PDOX->queryDie("DELETE FROM {$CFG->dbprefix}lti_nonce WHERE\n created_at < DATE_ADD(CURRENT_TIMESTAMP(), INTERVAL -{$CFG->noncetime} SECOND)"); // error_log("Nonce table cleanup done."); } $PDOX->queryDie("INSERT INTO {$CFG->dbprefix}lti_nonce\n (key_id, nonce) VALUES ( :key_id, :nonce)", array(':nonce' => $post['nonce'], ':key_id' => $row['key_id'])); } // If there is an appropriate role override variable, we use that role if (isset($row['role_override']) && isset($row['role']) && $row['role_override'] > $row['role']) { $row['role'] = $row['role_override']; } // Put the information into the row variable // TODO: do AES on the secret $_SESSION['lti'] = $row; $_SESSION['lti_post'] = $_POST; if (isset($_SERVER['HTTP_USER_AGENT'])) { $_SESSION['HTTP_USER_AGENT'] = $_SERVER['HTTP_USER_AGENT']; } if (isset($_SERVER['REMOTE_ADDR'])) { $_SESSION['REMOTE_ADDR'] = $_SERVER['REMOTE_ADDR']; } $_SESSION['CSRF_TOKEN'] = uniqid(); // Save this to make sure the user does not wander unless we launched from the root $scp = getScriptPath(); if (strlen($scp) > 0) { $_SESSION['script_path'] = getScriptPath(); } // Check if we can auto-login the system user if (Settings::linkGet('dologin', false) && isset($PDOX) && $PDOX !== false) { loginSecureCookie(); } // Set up basic custom values (legacy) if (isset($_POST['custom_due'])) { $when = strtotime($_POST['custom_due']); if ($when === false) { echo '<p>Error, bad setting for custom_due=' . htmlentities($_POST['custom_due']) . '</p>'; error_log('Bad custom_due=' . $_POST['custom_due']); flush(); } else { $_SESSION['due'] = $_POST['custom_due']; } } if (isset($_POST['custom_timezone'])) { $_SESSION['timezone'] = $_POST['custom_timezone']; } if (isset($_POST['custom_penalty_time'])) { if ($_POST['custom_penalty_time'] + 0 == 0) { echo '<p>Error, bad setting for custom_penalty_time=' . htmlentities($_POST['custom_penalty_time']) . '</p>'; error_log('Bad custom_penalty_time=' . $_POST['custom_penalty_time']); flush(); } else { $_SESSION['penalty_time'] = $_POST['custom_penalty_time']; } } if (isset($_POST['custom_penalty_cost'])) { if ($_POST['custom_penalty_cost'] + 0 == 0) { echo '<p>Error, bad setting for custom_penalty_cost=' . htmlentities($_POST['custom_penalty_cost']) . '</p>'; error_log('Bad custom_penalty_cost=' . $_POST['custom_penalty_cost']); flush(); } else { $_SESSION['penalty_cost'] = $_POST['custom_penalty_cost']; } } $breadcrumb = 'Launch,'; $breadcrumb .= isset($row['key_id']) ? $row['key_id'] : ''; $breadcrumb .= ','; $breadcrumb .= isset($row['user_id']) ? $row['user_id'] : ''; $breadcrumb .= ','; $breadcrumb .= isset($_POST['user_id']) ? str_replace(',', ';', $_POST['user_id']) : ''; $breadcrumb .= ','; $breadcrumb .= $session_id; $breadcrumb .= ','; $breadcrumb .= curPageURL(); $breadcrumb .= ','; $breadcrumb .= isset($_SESSION['email']) ? $_SESSION['email'] : ''; error_log($breadcrumb); return $session_id; }
function percent($x) { return sprintf("%.1f%%", $x * 100); } $LTI = LTIX::requireData(); $p = $CFG->dbprefix; if (SettingsForm::handleSettingsPost()) { header('Location: ' . addSession('index.php')); return; } // Get the settings $max_tries = Settings::linkGet('tries') + 0; if ($max_tries < 1) { $max_tries = 1; } $delay = Settings::linkGet('delay') + 0; // Get any due date information $dueDate = SettingsForm::getDueDate(); // Load the quiz $gift = $LINK->getJson(); // parse the quiz questions $questions = false; $errors = array("No questions found"); if (strlen($gift) > 0) { $questions = array(); $errors = array(); parse_gift($gift, $questions, $errors); } // Load the previous attempt $attempt = json_decode($RESULT->getJson()); $when = 0;
require_once "exercises.php"; use \Tsugi\Core\LTIX; use \Tsugi\Core\Settings; use \Tsugi\UI\SettingsForm; // Sanity checks $LTI = LTIX::requireData(); $p = $CFG->dbprefix; if ( SettingsForm::handleSettingsPost() ) { header( 'Location: '.addSession('index.php?howdysuppress=1') ) ; return; } $oldsettings = Settings::linkGetAll(); // Get the current user's grade data $row = gradeLoad(); $OLDCODE = false; $json = array(); $editor = 1; if ( $row !== false && isset($row['json'])) { $json = json_decode($row['json'], true); if ( isset($json["code"]) ) $OLDCODE = $json["code"]; if ( isset($json["editor"]) ) $editor = $json["editor"]; } if ( isset($_GET['editor']) && ( $_GET['editor'] == '1' || $_GET['editor'] == '0' ) ) { $neweditor = $_GET['editor']+0; if ( $editor != $neweditor ) {
if ($USER->instructor) { SettingsForm::start(); echo '<label for="sample_key">Please enter a string for "sample_key" below.<br/>' . "\n"; SettingsForm::text('sample_key'); echo "</label>\n"; SettingsForm::end(); } echo "<h1>Settings Test Harness</h1>\n"; $OUTPUT->welcomeUserCourse(); if ($USER->instructor) { echo "<p>Press the settings button in the upper left to change the settings.</p>\n"; } // Load the old values for the settings $sk = Settings::linkGet('sample_key'); echo "<p>The currentsetting for sample_key is: <b>" . htmlent_utf8($sk) . "</b></p>\n"; $mk = Settings::linkGet('manual_key'); echo "<p>The currentsetting for manual_key is: <b>" . htmlent_utf8($mk) . "</b></p>\n"; // Lets show how to set a setting in our own code if ($USER->instructor) { ?> <form method="post"> Enter value for 'manual_key' setting: <input type="text" name="manual_key" size="40" value="<?php echo htmlent_utf8($mk); ?> "><br/> <input type="submit" name="send" value="Update 'manual_key' setting"> </form> <hr/> <?php }
<?php require_once "../../config.php"; require_once $CFG->dirroot . "/pdo.php"; require_once $CFG->dirroot . "/lib/lms_lib.php"; // The Tsugi PHP API Documentation is available at: // http://do1.dr-chuck.com/tsugi/phpdoc/namespaces/Tsugi.html use Tsugi\Core\Settings; use Tsugi\Core\LTIX; // No parameter means we require CONTEXT, USER, and LINK $LTI = LTIX::requireData(); // Model $p = $CFG->dbprefix; $old_code = Settings::linkGet('code', ''); if (isset($_POST['code']) && isset($_POST['set']) && $USER->instructor) { Settings::linkSet('code', $_POST['code']); $_SESSION['success'] = 'Code updated'; header('Location: ' . addSession('index.php')); return; } else { if (isset($_POST['clear']) && $USER->instructor) { $rows = $PDOX->queryDie("DELETE FROM {$p}attend WHERE link_id = :LI", array(':LI' => $LINK->id)); $_SESSION['success'] = 'Data cleared'; header('Location: ' . addSession('index.php')); return; } else { if (isset($_POST['code'])) { // Student if ($old_code == $_POST['code']) { $PDOX->queryDie("INSERT INTO {$p}attend\n (link_id, user_id, ipaddr, attend, updated_at)\n VALUES ( :LI, :UI, :IP, NOW(), NOW() )\n ON DUPLICATE KEY UPDATE updated_at = NOW()", array(':LI' => $LINK->id, ':UI' => $USER->id, ':IP' => $_SERVER["REMOTE_ADDR"])); $_SESSION['success'] = _('Attendance Recorded...');