summaryrefslogtreecommitdiffstats
path: root/modules-available/exams
diff options
context:
space:
mode:
authorSimon Rettberg2016-07-28 17:30:44 +0200
committerSimon Rettberg2016-07-28 17:30:44 +0200
commit71d3d4efb61d9171b5a5ec1120c1aa3cdd572366 (patch)
tree711a31835830739c72bede0605d93d5df76fb8af /modules-available/exams
parent[dozmod] API: Implement netrules and runscript fetching for lectures (diff)
downloadslx-admin-71d3d4efb61d9171b5a5ec1120c1aa3cdd572366.tar.gz
slx-admin-71d3d4efb61d9171b5a5ec1120c1aa3cdd572366.tar.xz
slx-admin-71d3d4efb61d9171b5a5ec1120c1aa3cdd572366.zip
[exams] Add autostart lecture feature
Diffstat (limited to 'modules-available/exams')
-rw-r--r--modules-available/exams/baseconfig/getconfig.inc.php5
-rw-r--r--modules-available/exams/inc/exams.inc.php7
-rw-r--r--modules-available/exams/lang/de/template-tags.json6
-rw-r--r--modules-available/exams/lang/en/template-tags.json6
-rw-r--r--modules-available/exams/page.inc.php32
-rw-r--r--modules-available/exams/templates/page-add-edit-exam.html62
-rw-r--r--modules-available/exams/templates/page-exams.html11
7 files changed, 107 insertions, 22 deletions
diff --git a/modules-available/exams/baseconfig/getconfig.inc.php b/modules-available/exams/baseconfig/getconfig.inc.php
index d26a20a9..2776d3a8 100644
--- a/modules-available/exams/baseconfig/getconfig.inc.php
+++ b/modules-available/exams/baseconfig/getconfig.inc.php
@@ -2,7 +2,10 @@
if (isset($configVars["SLX_LOCATIONS"])) {
$locationIds = explode(' ', $configVars["SLX_LOCATIONS"]);
- if (Exams::isInExamMode($locationIds)) {
+ if (Exams::isInExamMode($locationIds, $lectureId)) {
$configVars['SLX_EXAM'] = 'yes';
+ if (strlen($lectureId) > 0) {
+ $configVars['SLX_EXAM_START'] = $lectureId;
+ }
}
}
diff --git a/modules-available/exams/inc/exams.inc.php b/modules-available/exams/inc/exams.inc.php
index f781fc1e..e95a9392 100644
--- a/modules-available/exams/inc/exams.inc.php
+++ b/modules-available/exams/inc/exams.inc.php
@@ -7,7 +7,7 @@ class Exams
* @param int[] of location ids. must bot be an associative array.
* @return: bool true iff for any of the given location ids an exam is scheduled.
**/
- public static function isInExamMode($locationIds)
+ public static function isInExamMode($locationIds, &$lectureId)
{
if (!is_array($locationIds)) {
$locationIds = array($locationIds);
@@ -15,9 +15,12 @@ class Exams
return false;
}
$l = str_repeat(',?', count($locationIds));
- $res = Database::queryFirst("SELECT examid FROM exams"
+ $res = Database::queryFirst("SELECT lectureid FROM exams"
. " INNER JOIN exams_x_location USING (examid)"
. " WHERE UNIX_TIMESTAMP() BETWEEN starttime AND endtime AND locationid IN (0$l) LIMIT 1", $locationIds);
+ if ($res !== false) {
+ $lectureId = $res['lectureid'];
+ }
return $res !== false;
}
diff --git a/modules-available/exams/lang/de/template-tags.json b/modules-available/exams/lang/de/template-tags.json
index 797cc371..22f777ad 100644
--- a/modules-available/exams/lang/de/template-tags.json
+++ b/modules-available/exams/lang/de/template-tags.json
@@ -3,6 +3,9 @@
"lang_addExam": "Zeitraum hinzuf\u00fcgen",
"lang_addingBasedOnLecture": "F\u00fcge neuen Pr\u00fcfungszeitraum basierend auf vorhandener Veranstaltung an",
"lang_allExamPeriods": "Alle Pr\u00fcfungszeitr\u00e4ume",
+ "lang_autoStartInfo": "W\u00e4hlen Sie hier optional eine Veranstaltung, die automatisch nach dem Booten der Rechner auf den Clients gestartet werden soll. Die Studierenden sehen keine Loginmaske und keinen vmChooser. Dadurch ist der Benutzer nicht angemeldet, und es steht u.a. kein Home-Verzeichnis zur Verf\u00fcgung. Diese Funktion eignet sich somit nur, wenn in der Pr\u00fcfung keine Autentifizierung des Benutzers notwendig ist, oder diese anderweitig innerhalb der VM-Sitzung umgesetzt wird, z.B. indem sich der Pr\u00fcfling gesondert auf einer Lernplattform im Browser anmeldet. Beachten Sie au\u00dferdem, dass die gew\u00e4hlte Veranstaltung zum Pr\u00fcfungszeitraum durch den Dozenten aktiviert sein muss. Wird keine Veranstaltung f\u00fcr den Autostart ausgew\u00e4hlt, sieht der Pr\u00fcfling nach wie vor eine Anmeldemaske und anschlie\u00dfend den vmChooser, in dem dann jedoch ausschlie\u00dflich als Pr\u00fcfung markierte Veranstaltungen aufgelistet werden.",
+ "lang_autoStartLecture": "Automatisch zu startende Veranstaltung",
+ "lang_autostart": "Autostart-Veranstaltung",
"lang_begin": "Beginn",
"lang_begin_date": "Beginn Datum",
"lang_begin_time": "Uhrzeit",
@@ -20,8 +23,11 @@
"lang_headingMain": "bwLehrpool Pr\u00fcfungsmodus",
"lang_id": "ID",
"lang_lectureName": "Veranstaltungsname",
+ "lang_lectureOutOfRange": "Achtung: Start- bzw. Endzeitpunkt der Veranstaltung liegen au\u00dferhalb des oben angegebenen Zeitraums",
"lang_location": "Raum\/Ort",
+ "lang_locationInfo": "W\u00e4hlen Sie hier die R\u00e4ume und Orte aus, die w\u00e4hrend des unten ausgew\u00e4hlten Zeitraums in den Pr\u00fcfungsmodus versetzt werden. Wenn sie hier keine Auswahl treffen, werden alle R\u00e4ume in den Pr\u00fcfungsmodus versetzt.",
"lang_locations": "R\u00e4ume\/Orte",
"lang_noDescription": "Keine Beschreibung",
+ "lang_none": "(Keine)",
"lang_timeFrame": "Zeitraum"
} \ No newline at end of file
diff --git a/modules-available/exams/lang/en/template-tags.json b/modules-available/exams/lang/en/template-tags.json
index 2e5abeff..b5ab87ae 100644
--- a/modules-available/exams/lang/en/template-tags.json
+++ b/modules-available/exams/lang/en/template-tags.json
@@ -3,6 +3,9 @@
"lang_addExam": "Add exam period",
"lang_addingBasedOnLecture": "Adding exam period based on lecture",
"lang_allExamPeriods": "All exam periods",
+ "lang_autoStartInfo": "Here you can select a course that will be launched automatically after the client finishes booting up. This will skip the login prompt and vmChooser screen, and directly start the selected couse. In this case, no personalization like mapping of home directories can happen in the VM, so this is mostly useful if the exam relies on other means of authentication, e.g. logging in to an LMS system where results need to be submitted.",
+ "lang_autoStartLecture": "Automatically launched course",
+ "lang_autostart": "Autorun lecture",
"lang_begin": "Begin",
"lang_begin_date": "Begin Date",
"lang_begin_time": "Time",
@@ -20,8 +23,11 @@
"lang_headingMain": "bwLehrpool exam mode",
"lang_id": "ID",
"lang_lectureName": "Lecture name",
+ "lang_lectureOutOfRange": "Hint: Start or end date of given lecture lies outside of exam period given above",
"lang_location": "Room\/Location",
+ "lang_locationInfo": "Select the rooms and locations you want to enable the exam mode in. Selecting nothing at all means that all clients will boot into exam mode during the given time period.",
"lang_locations": "Rooms\/Locations",
"lang_noDescription": "No description",
+ "lang_none": "(None)",
"lang_timeFrame": "Time frame"
} \ No newline at end of file
diff --git a/modules-available/exams/page.inc.php b/modules-available/exams/page.inc.php
index d6b1ccea..e70fc3c7 100644
--- a/modules-available/exams/page.inc.php
+++ b/modules-available/exams/page.inc.php
@@ -30,9 +30,12 @@ class Page_Exams extends Page
protected function readExams()
{
- $tmp = Database::simpleQuery("SELECT examid, starttime, endtime, description, GROUP_CONCAT(locationid) AS locationids, "
- . "GROUP_CONCAT(locationname SEPARATOR ', ') AS locationnames FROM exams "
- . "NATURAL LEFT JOIN exams_x_location NATURAL LEFT JOIN location GROUP BY examid");
+ $tmp = Database::simpleQuery("SELECT e.examid, l.displayname AS lecturename, e.starttime, e.endtime, e.description, GROUP_CONCAT(exl.locationid) AS locationids, "
+ . "GROUP_CONCAT(loc.locationname SEPARATOR ', ') AS locationnames FROM exams e "
+ . "NATURAL LEFT JOIN exams_x_location exl "
+ . "NATURAL LEFT JOIN location loc "
+ . "LEFT JOIN sat.lecture l USING (lectureid) "
+ . "GROUP BY examid ");
while ($exam = $tmp->fetch(PDO::FETCH_ASSOC)) {
$this->exams[] = $exam;
}
@@ -211,7 +214,8 @@ class Page_Exams extends Page
$examid = Request::post('examid', 0, 'int');
$starttime = strtotime(Request::post('starttime_date') . " " . Request::post('starttime_time'));
$endtime = strtotime(Request::post('endtime_date') . " " . Request::post('endtime_time'));
- $description = Request::post('description');
+ $description = Request::post('description', '', 'string');
+ $lectureid = Request::post('lectureid', '', 'string');
if (!$this->isDateSane($starttime)) {
Message::addError('starttime-invalid', Request::post('starttime_date') . " " . Request::post('starttime_time'));
Util::redirect('?do=exams');
@@ -227,8 +231,8 @@ class Page_Exams extends Page
if ($examid === 0) {
// No examid given, is add
- $res = Database::exec("INSERT INTO exams(starttime, endtime, description) VALUES(:starttime, :endtime, :description);",
- compact('starttime', 'endtime', 'description')) !== false;
+ $res = Database::exec("INSERT INTO exams(lectureid, starttime, endtime, description) VALUES(:lectureid, :starttime, :endtime, :description);",
+ compact('lectureid', 'starttime', 'endtime', 'description')) !== false;
$exam_id = Database::lastInsertId();
foreach ($locationids as $lid) {
@@ -251,8 +255,8 @@ class Page_Exams extends Page
}
/* update fields */
- $res = Database::exec("UPDATE exams SET starttime = :starttime, endtime = :endtime, description = :description WHERE examid = :examid",
- compact('starttime', 'endtime', 'description', 'examid')) !== false;
+ $res = Database::exec("UPDATE exams SET lectureid = :lectureid, starttime = :starttime, endtime = :endtime, description = :description WHERE examid = :examid",
+ compact('lectureid', 'starttime', 'endtime', 'description', 'examid')) !== false;
/* drop all connections and reconnect to rooms */
$res = $res && Database::exec("DELETE FROM exams_x_location WHERE examid = :examid", compact('examid')) !== false;
/* reconnect */
@@ -369,14 +373,17 @@ class Page_Exams extends Page
$baseLecture = Request::any('lectureid', false, 'string');
$locations = null;
if ($baseLecture !== false) {
- foreach ($this->lectures as $lecture) {
+ foreach ($this->lectures as &$lecture) {
if ($lecture['lectureid'] === $baseLecture) {
$data['exam'] = $this->makeEditFromArray($lecture);
$locations = explode(',', $lecture['lids']);
+ $lecture['selected'] = 'selected';
break;
}
}
+ unset($lecture);
}
+ $data['lectures'] = $this->lectures;
$this->readLocations($locations);
$data['locations'] = $this->locations;
Render::addTemplate('page-add-edit-exam', $data);
@@ -385,7 +392,12 @@ class Page_Exams extends Page
Render::setTitle(Dictionary::translate('title_edit-exam'));
$exam = $this->makeEditFromArray($this->currentExam);
- Render::addTemplate('page-add-edit-exam', ['exam' => $exam, 'locations' => $this->locations]);
+ foreach ($this->lectures as &$lecture) {
+ if ($lecture['lectureid'] === $this->currentExam['lectureid']) {
+ $lecture['selected'] = 'selected';
+ }
+ }
+ Render::addTemplate('page-add-edit-exam', ['exam' => $exam, 'locations' => $this->locations, 'lectures' => $this->lectures]);
}
}
diff --git a/modules-available/exams/templates/page-add-edit-exam.html b/modules-available/exams/templates/page-add-edit-exam.html
index 3f0ef372..744aad29 100644
--- a/modules-available/exams/templates/page-add-edit-exam.html
+++ b/modules-available/exams/templates/page-add-edit-exam.html
@@ -12,6 +12,7 @@
<div class="form-group">
<div>
<label for="locations">{{lang_location}}</label>
+ <p><i>{{lang_locationInfo}}</i></p>
</div>
<select id="locations" multiple name="locations[]">
{{#locations}}
@@ -76,6 +77,27 @@
<div class="row form-group">
<div class="form-group col-xs-12">
+ <label for="description">{{lang_autoStartLecture}}</label>
+ <p><i>{{lang_autoStartInfo}}</i></p>
+ <div class="input-group">
+ <span class="input-group-addon">
+ <span class="glyphicon glyphicon-pencil"></span>
+ </span>
+ <select class="form-control" id="lecturelist" name="lectureid">
+ <option value="">{{lang_none}}</option>
+ {{#lectures}}
+ <option data-from="{{starttime}}" data-to="{{endtime}}" value="{{lectureid}}" {{selected}} >{{displayname}}</option>
+ {{/lectures}}
+ </select>
+ </div>
+ </div>
+ <div class="col-xs-12" id="lecture-info">
+ bla
+ </div>
+ </div>
+
+ <div class="row form-group">
+ <div class="form-group col-xs-12">
<label for="description">{{lang_description}}</label>
<textarea class="form-control" type="textarea" name="description" id="description">{{exam.description}}</textarea>
</div>
@@ -112,7 +134,7 @@ document.addEventListener("DOMContentLoaded", function () {
$('.datepicker').datepicker(dateSettings);
$('.timepicker2').timepicker(timeSettings);
- showDuration();
+ startEndChanged();
});
$('#locations').multiselect({numberDisplayed: 1});
@@ -137,7 +159,7 @@ document.addEventListener("DOMContentLoaded", function () {
}
});
- var showDuration = function () {
+ var startEndChanged = function () {
var sd = slxMoment(start_date.val() + ' ' + start_time.val(), 'YYYY-MM-DD H:mm');
var ed = slxMoment(end_date.val() + ' ' + end_time.val(), 'YYYY-MM-DD H:mm');
if (!sd.isValid() || !ed.isValid()) {
@@ -145,12 +167,40 @@ document.addEventListener("DOMContentLoaded", function () {
return;
}
rspan.text(slxMoment.duration(ed.diff(sd)).humanize());
+ // Lecture selection
+ $('#lecturelist option').each(function (idx, elem) {
+ var e = $(elem);
+ var from = e.data('from');
+ var to = e.data('to');
+ if (!from || !to)
+ return;
+ from = slxMoment(from);
+ to = slxMoment(to);
+ if (from.isBefore(sd) || to.isAfter(ed)) {
+ e.css('color', '#999');
+ e.data('inrange', false)
+ } else {
+ e.css('color', '');
+ e.data('inrange', true);
+ }
+ });
+ updateLectureInfo();
+ }
+
+ var updateLectureInfo = function() {
+ var sel = $('#lecturelist option:selected');
+ if (sel.val() === '' || sel.data('inrange')) {
+ $('#lecture-info').text('-');
+ } else {
+ $('#lecture-info').text('{{lang_lectureOutOfRange}} (' + slxMoment(sel.data('from')).format('YYYY-MM-DD H:mm') + ' - ' + slxMoment(sel.data('to')).format('YYYY-MM-DD H:mm') + ')');
+ }
}
- start_date.change(showDuration);
- start_time.change(showDuration);
- end_date.change(showDuration);
- end_time.change(showDuration);
+ start_date.change(startEndChanged);
+ start_time.change(startEndChanged);
+ end_date.change(startEndChanged);
+ end_time.change(startEndChanged);
+ $('#lecturelist').change(updateLectureInfo);
}, false);
// --></script>
diff --git a/modules-available/exams/templates/page-exams.html b/modules-available/exams/templates/page-exams.html
index 184a69e3..fc88e4f4 100644
--- a/modules-available/exams/templates/page-exams.html
+++ b/modules-available/exams/templates/page-exams.html
@@ -17,6 +17,11 @@
{{^locationnames}}
<i>{{lang_global}}</i>
{{/locationnames}}
+ {{#lecturename}}
+ <div>
+ <b>{{lang_autostart}}</b>: {{lecturename}}
+ </div>
+ {{/lecturename}}
<div class="small">
{{description}}
{{^description}}
@@ -24,9 +29,9 @@
{{/description}}
</div>
</td>
- <td class="slx-nowrap">{{starttime_s}}</td>
- <td class="slx-nowrap">{{endtime_s}}</td>
- <td class="slx-nowrap">
+ <td class="text-nowrap">{{starttime_s}}</td>
+ <td class="text-nowrap">{{endtime_s}}</td>
+ <td class="text-nowrap text-right">
<form method="POST" action="?do=exams&action=delete" {{^liesInPast}}onsubmit="return confirm('{{lang_deleteConfirmation}}');"{{/liesInPast}} >
{{^liesInPast}}
<a onclick="slxShow({{starttime}}, {{endtime}})" class="btn btn-default btn-sm"><span class="glyphicon glyphicon-eye-open"></span></a>