';
@@ -306,7 +304,7 @@ public function edit_question($questionid) {
/**
* Loads the quiz questions from the database, ordered by slot.
*/
- public function refresh_questions() {
+ public function refresh_questions(): void {
global $DB;
$this->questions = [];
$questions = $DB->get_records('jazzquiz_questions', ['jazzquizid' => $this->data->id], 'slot');
@@ -321,35 +319,36 @@ public function refresh_questions() {
}
/**
+ * Get a JazzQuiz question by id.
+ *
* @param int $jazzquizquestionid
- * @return jazzquiz_question|bool
+ * @return ?jazzquiz_question
*/
- public function get_question_by_id($jazzquizquestionid) {
+ public function get_question_by_id(int $jazzquizquestionid): ?jazzquiz_question {
foreach ($this->questions as $question) {
if ($question->data->id == $jazzquizquestionid) {
return $question;
}
}
- return false;
+ return null;
}
/**
- * Quick function for whether or not the current user is the instructor/can control the quiz
+ * Check if the current user is an instructor in this quiz.
+ *
* @return bool
*/
- public function is_instructor() : bool {
- if (is_null($this->isinstructor)) {
- $this->isinstructor = has_capability('mod/jazzquiz:control', $this->context);
- }
- return $this->isinstructor;
+ public function is_instructor(): bool {
+ return has_capability('mod/jazzquiz:control', $this->context);
}
/**
- * Get all sessions for this jazzquiz
+ * Get all sessions for this jazzquiz.
+ *
* @param array $conditions
- * @return \stdClass[]
+ * @return stdClass[]
*/
- public function get_sessions(array $conditions = []) : array {
+ public function get_sessions(array $conditions = []): array {
global $DB;
$conditions = array_merge(['jazzquizid' => $this->data->id], $conditions);
return $DB->get_records('jazzquiz_sessions', $conditions);
diff --git a/classes/jazzquiz_attempt.php b/classes/jazzquiz_attempt.php
index f0ad7cb..133c020 100755
--- a/classes/jazzquiz_attempt.php
+++ b/classes/jazzquiz_attempt.php
@@ -16,7 +16,12 @@
namespace mod_jazzquiz;
-defined('MOODLE_INTERNAL') || die();
+use context_module;
+use core\context\module;
+use question_bank;
+use question_engine;
+use question_usage_by_activity;
+use stdClass;
/**
* An attempt for the quiz. Maps to individual question attempts.
@@ -29,61 +34,101 @@
*/
class jazzquiz_attempt {
- /** Constants for the status of the attempt */
+ /** The attempt has not started. */
const NOTSTARTED = 0;
+
+ /** The attempt is in progress. */
const INPROGRESS = 10;
+
+ /** The attempt is only for preview. */
const PREVIEW = 20;
+
+ /** The attempt is finished. */
const FINISHED = 30;
- /** @var \stdClass */
- public $data;
+ /** @var int The jazzquiz attempt id */
+ public int $id;
+
+ /** @var int The jazzquiz session id */
+ public int $sessionid;
+
+ /** @var int|null The user id */
+ public ?int $userid;
+
+ /** @var int The question usage by activity id */
+ public int $questionengid;
+
+ /** @var string|null The guest session key */
+ public ?string $guestsession;
- /** @var \question_usage_by_activity $quba the question usage by activity for this attempt */
- public $quba;
+ /** @var int Current status of this attempt */
+ public int $status;
+
+ /** @var int|null Response status for the current question */
+ public ?int $responded;
+
+ /** @var int When this quiz attempt started */
+ public int $timestart;
+
+ /** @var int|null When this quiz attempt finished */
+ public ?int $timefinish;
+
+ /** @var int When this quiz attempt was last modified */
+ public int $timemodified;
+
+ /** @var question_usage_by_activity The question usage by activity for this attempt */
+ public question_usage_by_activity $quba;
/**
- * Construct the class. If data is passed in we set it, otherwise initialize empty class
- * @param \context_module $context
- * @param \stdClass $data
+ * Constructor.
+ *
+ * @param stdClass $record
*/
- public function __construct(\context_module $context, \stdClass $data = null) {
- if (empty($data)) {
- // Create new attempt.
- $this->data = new \stdClass();
- // Create a new quba since we're creating a new attempt.
- $this->quba = \question_engine::make_questions_usage_by_activity('mod_jazzquiz', $context);
- $this->quba->set_preferred_behaviour('immediatefeedback');
- } else {
- // Load it up in this class instance.
- $this->data = $data;
- $this->quba = \question_engine::load_questions_usage_by_activity($this->data->questionengid);
- }
+ private function __construct(stdClass $record) {
+ $this->id = $record->id;
+ $this->sessionid = $record->sessionid;
+ $this->userid = $record->userid;
+ $this->questionengid = $record->questionengid;
+ $this->guestsession = $record->guestsession;
+ $this->status = $record->status;
+ $this->responded = $record->responded;
+ $this->timestart = $record->timestart;
+ $this->timefinish = $record->timefinish;
+ $this->timemodified = $record->timemodified;
+ $this->quba = question_engine::load_questions_usage_by_activity($this->questionengid);
}
- public function belongs_to_current_user() {
+ /**
+ * Check if the attempt belongs to the current user.
+ *
+ * @return bool
+ */
+ public function belongs_to_current_user(): bool {
global $USER;
- return $this->data->userid == $USER->id || $this->data->guestsession == $USER->sesskey;
+ return $this->userid == $USER->id || $this->guestsession === $USER->sesskey;
}
/**
* Check if this attempt is currently in progress.
+ *
* @return bool
*/
- public function is_active() {
- switch ($this->data->status) {
- case self::INPROGRESS:
- case self::PREVIEW:
- return true;
- default:
- return false;
- }
+ public function is_active(): bool {
+ return match ($this->status) {
+ self::INPROGRESS, self::PREVIEW => true,
+ default => false,
+ };
}
/**
+ * Create missing question attempts.
+ *
+ * This is necessary when new questions have been added by the teacher during the quiz.
+ *
* @param jazzquiz_session $session
* @return bool false if invalid question id
*/
- public function create_missing_attempts(jazzquiz_session $session) {
+ public function create_missing_attempts(jazzquiz_session $session): bool {
foreach ($session->questions as $slot => $question) {
if ($this->quba->next_slot_number() > $slot) {
continue;
@@ -93,22 +138,24 @@ public function create_missing_attempts(jazzquiz_session $session) {
if (!$questiondefinition) {
return false;
}
- $question = \question_bank::make_question($questiondefinition);
+ $question = question_bank::make_question($questiondefinition);
$slot = $this->quba->add_question($question);
$this->quba->start_question($slot);
- $this->data->responded = 0;
+ $this->responded = 0;
}
return true;
}
/**
* Anonymize all the question attempt steps for this quiz attempt.
+ *
* It will be impossible to identify which user answered all questions linked to this question usage.
- * @throws \dml_exception
+ *
+ * @return void
*/
- public function anonymize_answers() {
+ public function anonymize_answers(): void {
global $DB;
- $attempts = $DB->get_records('question_attempts', ['questionusageid' => $this->data->questionengid]);
+ $attempts = $DB->get_records('question_attempts', ['questionusageid' => $this->questionengid]);
foreach ($attempts as $attempt) {
$steps = $DB->get_records('question_attempt_steps', ['questionattemptid' => $attempt->id]);
foreach ($steps as $step) {
@@ -116,67 +163,123 @@ public function anonymize_answers() {
$DB->update_record('question_attempt_steps', $step);
}
}
- $this->data->userid = null;
+ $this->userid = null;
$this->save();
}
/**
- * Saves the current attempt.
- * @return bool
+ * Helper function to properly create a new attempt for a JazzQuiz session.
+ *
+ * @param jazzquiz_session $session
+ * @return jazzquiz_attempt
*/
- public function save() {
+ public static function create(jazzquiz_session $session): jazzquiz_attempt {
+ global $DB, $USER;
+ $quba = question_engine::make_questions_usage_by_activity('mod_jazzquiz', $session->jazzquiz->context);
+ $quba->set_preferred_behaviour('immediatefeedback');
+ // TODO: Don't suppress the error if it becomes possible to save QUBAs without slots.
+ @question_engine::save_questions_usage_by_activity($quba);
+ $id = $DB->insert_record('jazzquiz_attempts', [
+ 'sessionid' => $session->data->id,
+ 'userid' => isguestuser($USER->id) ? null : $USER->id,
+ 'questionengid' => $quba->get_id(),
+ 'guestsession' => isguestuser($USER->id) ? $USER->sesskey : null,
+ 'status' => self::NOTSTARTED,
+ 'responded' => null,
+ 'timestart' => time(),
+ 'timefinish' => null,
+ 'timemodified' => time(),
+ ]);
+ $attempt = self::get_by_id($id);
+ $attempt->create_missing_attempts($session);
+ return $attempt;
+ }
+
+ /**
+ * Helper function to properly load a JazzQuiz attempt by its ID.
+ *
+ * @param int $id
+ * @return jazzquiz_attempt
+ */
+ public static function get_by_id(int $id): jazzquiz_attempt {
global $DB;
+ $record = $DB->get_record('jazzquiz_attempts', ['id' => $id], '*', MUST_EXIST);
+ return new jazzquiz_attempt($record);
+ }
- // Save the question usage by activity object.
- if ($this->quba->question_count() > 0) {
- \question_engine::save_questions_usage_by_activity($this->quba);
- } else {
- // TODO: Don't suppress the error if it becomes possible to save QUBAs without slots.
- @\question_engine::save_questions_usage_by_activity($this->quba);
+ /**
+ * Helper function to properly load a JazzQuiz attempt for the current user in a session.
+ *
+ * @param jazzquiz_session $session
+ * @return jazzquiz_attempt
+ */
+ public static function get_by_session_for_current_user(jazzquiz_session $session): jazzquiz_attempt {
+ global $DB, $USER;
+ $sql = 'SELECT *
+ FROM {jazzquiz_attempts}
+ WHERE sessionid = :sessionid
+ AND (userid = :userid OR guestsession = :sesskey)';
+ $record = $DB->get_record_sql($sql, [
+ 'sessionid' => $session->data->id,
+ 'userid' => $USER->id,
+ 'sesskey' => $USER->sesskey,
+ ]);
+ if (empty($record)) {
+ return self::create($session);
}
+ return new jazzquiz_attempt($record);
+ }
- // Add the quba id as the questionengid.
- // This is here because for new usages there is no id until we save it.
- $this->data->questionengid = $this->quba->get_id();
- $this->data->timemodified = time();
- try {
- if (isset($this->data->id)) {
- $DB->update_record('jazzquiz_attempts', $this->data);
- } else {
- $this->data->id = $DB->insert_record('jazzquiz_attempts', $this->data);
- }
- } catch (\Exception $e) {
- return false;
+ /**
+ * Save attempt.
+ */
+ public function save(): void {
+ global $DB;
+ if ($this->quba->question_count() > 0) {
+ question_engine::save_questions_usage_by_activity($this->quba);
}
- return true;
+ $this->timemodified = time();
+ $DB->update_record('jazzquiz_attempts', [
+ 'id' => $this->id,
+ 'sessionid' => $this->sessionid,
+ 'userid' => $this->userid,
+ 'questionengid' => $this->questionengid,
+ 'guestsession' => $this->guestsession,
+ 'status' => $this->status,
+ 'responded' => $this->responded,
+ 'timestart' => $this->timestart,
+ 'timefinish' => $this->timefinish,
+ 'timemodified' => $this->timemodified,
+ ]);
}
/**
- * Saves a question attempt from the jazzquiz question
+ * Saves a question attempt from the jazzquiz question.
+ *
* @param int $slot
*/
- public function save_question($slot) {
+ public function save_question(int $slot): void {
global $DB;
$transaction = $DB->start_delegated_transaction();
$this->quba->process_all_actions();
$this->quba->finish_question($slot, time());
- $this->data->timemodified = time();
- $this->data->responded = 1;
+ $this->timemodified = time();
+ $this->responded = 1;
$this->save();
$transaction->allow_commit();
}
/**
- * Gets the feedback for the specified question slot
+ * Gets the feedback for the specified question slot.
*
* If no slot is defined, we attempt to get that from the slots param passed
- * back from the form submission
+ * back from the form submission.
*
* @param jazzquiz $jazzquiz
* @param int $slot The slot for which we want to get feedback
* @return string HTML fragment of the feedback
*/
- public function get_question_feedback(jazzquiz $jazzquiz, $slot = -1) {
+ public function get_question_feedback(jazzquiz $jazzquiz, int $slot = -1): string {
global $PAGE;
if ($slot === -1) {
// Attempt to get it from the slots param sent back from a question processing.
@@ -191,21 +294,23 @@ public function get_question_feedback(jazzquiz $jazzquiz, $slot = -1) {
}
/**
- * Returns whether current user has responded
+ * Returns whether current user has responded.
+ *
* @param int $slot
* @return bool
*/
- public function has_responded($slot) {
- $response = $this->quba->get_question_attempt($slot)->get_response_summary();
- return $response !== null && $response !== '';
+ public function has_responded(int $slot): bool {
+ $questionattempt = $this->quba->get_question_attempt($slot);
+ return !empty($questionattempt->get_response_summary());
}
/**
- * Returns response data as an array
+ * Returns response data as an array.
+ *
* @param int $slot
* @return string[]
*/
- public function get_response_data($slot) {
+ public function get_response_data(int $slot): array {
$questionattempt = $this->quba->get_question_attempt($slot);
$response = $questionattempt->get_response_summary();
if ($response === null || $response === '') {
@@ -227,20 +332,26 @@ public function get_response_data($slot) {
}
/**
- * Closes the attempt
+ * Closes the attempt.
+ *
* @param jazzquiz $jazzquiz
*/
- public function close_attempt(jazzquiz $jazzquiz) {
+ public function close_attempt(jazzquiz $jazzquiz): void {
$this->quba->finish_all_questions(time());
// We want the instructor to remain in preview mode.
if (!$jazzquiz->is_instructor()) {
- $this->data->status = self::FINISHED;
+ $this->status = self::FINISHED;
}
- $this->data->timefinish = time();
+ $this->timefinish = time();
$this->save();
}
- public function total_answers() : int {
+ /**
+ * Get total answers.
+ *
+ * @return int
+ */
+ public function total_answers(): int {
$count = 0;
foreach ($this->quba->get_slots() as $slot) {
if ($this->has_responded($slot)) {
diff --git a/classes/jazzquiz_question.php b/classes/jazzquiz_question.php
index b1b3364..c50d84a 100755
--- a/classes/jazzquiz_question.php
+++ b/classes/jazzquiz_question.php
@@ -16,9 +16,11 @@
namespace mod_jazzquiz;
-defined('MOODLE_INTERNAL') || die();
+use stdClass;
/**
+ * A question slot in a JazzQuiz.
+ *
* @package mod_jazzquiz
* @author Sebastian S. Gundersen
* @copyright 2018 NTNU
@@ -26,23 +28,30 @@
*/
class jazzquiz_question {
- /** @var \stdClass $data */
- public $data;
+ /** @var stdClass */
+ public stdClass $data;
- /** @var \stdClass $question Question definition data */
- public $question;
+ /** @var ?stdClass Question definition data */
+ public ?stdClass $question;
/**
- * @param \stdClass $data jazzquiz_question
+ * Constructor.
+ *
+ * @param stdClass $data jazzquiz_question
*/
- public function __construct(\stdClass $data) {
+ public function __construct(stdClass $data) {
global $DB;
$this->data = $data;
- $this->question = $DB->get_record('question', ['id' => $data->questionid]);
+ $this->question = $DB->get_record('question', ['id' => $data->questionid]) ?: null;
}
- public function is_valid() {
- return $this->question !== false;
+ /**
+ * Check if the question exists.
+ *
+ * @return bool
+ */
+ public function is_valid(): bool {
+ return $this->question !== null;
}
}
diff --git a/classes/jazzquiz_session.php b/classes/jazzquiz_session.php
index b2bbe27..4e69472 100755
--- a/classes/jazzquiz_session.php
+++ b/classes/jazzquiz_session.php
@@ -16,9 +16,13 @@
namespace mod_jazzquiz;
-defined('MOODLE_INTERNAL') || die();
+use qubaid_join;
+use question_engine;
+use stdClass;
/**
+ * A session.
+ *
* @package mod_jazzquiz
* @author Sebastian S. Gundersen
* @copyright 2014 University of Wisconsin - Madison
@@ -28,42 +32,44 @@
class jazzquiz_session {
/** @var jazzquiz $jazzquiz */
- public $jazzquiz;
+ public jazzquiz $jazzquiz;
- /** @var \stdClass $data The jazzquiz_session database table row */
- public $data;
+ /** @var stdClass $data The jazzquiz_session database table row */
+ public stdClass $data;
/** @var jazzquiz_attempt[] */
- public $attempts;
+ public array $attempts;
- /** @var jazzquiz_attempt|false $attempt The current user's quiz attempt. False if not loaded. */
- public $attempt;
+ /** @var ?jazzquiz_attempt The current user's quiz attempt */
+ public ?jazzquiz_attempt $myattempt;
- /** @var \stdClass[] jazzquiz_session_questions */
- public $questions;
+ /** @var stdClass[] Questions in this session */
+ public array $questions;
/**
* Constructor.
+ *
* @param jazzquiz $jazzquiz
* @param int $sessionid
*/
- public function __construct(jazzquiz $jazzquiz, $sessionid) {
+ public function __construct(jazzquiz $jazzquiz, int $sessionid) {
global $DB;
$this->jazzquiz = $jazzquiz;
$this->attempts = [];
- $this->attempt = false;
+ $this->myattempt = null;
$this->questions = [];
$this->data = $DB->get_record('jazzquiz_sessions', [
'jazzquizid' => $this->jazzquiz->data->id,
- 'id' => $sessionid
+ 'id' => $sessionid,
], '*', MUST_EXIST);
}
/**
* Get array of unasked slots.
+ *
* @return int[] question slots.
*/
- public function get_unasked_slots() : array {
+ public function get_unasked_slots(): array {
$slots = [];
foreach ($this->jazzquiz->questions as $question) {
$asked = false;
@@ -80,57 +86,61 @@ public function get_unasked_slots() : array {
return $slots;
}
- private function requires_anonymous_answers() {
+ /**
+ * Check if this session requires anonymous answers.
+ *
+ * @return bool
+ */
+ private function requires_anonymous_answers(): bool {
return $this->data->anonymity != 3;
}
- private function requires_anonymous_attendance() {
+ /**
+ * Check if this session requires anonymous attendance.
+ *
+ * @return bool
+ */
+ private function requires_anonymous_attendance(): bool {
return $this->data->anonymity == 2;
}
/**
- * Saves the session object to the database
- * @return bool
+ * Saves the session object to the database.
*/
- public function save() {
+ public function save(): void {
global $DB;
- // Update if we already have a session, otherwise create it.
if (isset($this->data->id)) {
- try {
- $DB->update_record('jazzquiz_sessions', $this->data);
- } catch (\Exception $e) {
- return false;
- }
+ $DB->update_record('jazzquiz_sessions', $this->data);
} else {
- try {
- $this->data->id = $DB->insert_record('jazzquiz_sessions', $this->data);
- } catch (\Exception $e) {
- return false;
- }
+ $this->data->id = $DB->insert_record('jazzquiz_sessions', $this->data);
}
- return true;
}
/**
* Deletes the specified session, as well as the attempts.
+ *
* @param int $sessionid
- * @return bool
*/
- public static function delete($sessionid) {
+ public static function delete(int $sessionid): void {
global $DB;
// Delete all attempt quba ids, then all JazzQuiz attempts, and then finally itself.
- $condition = new \qubaid_join('{jazzquiz_attempts} jqa', 'jqa.questionengid', 'jqa.sessionid = :sessionid', [
- 'sessionid' => $sessionid
+ $condition = new qubaid_join('{jazzquiz_attempts} jqa', 'jqa.questionengid', 'jqa.sessionid = :sessionid', [
+ 'sessionid' => $sessionid,
]);
- \question_engine::delete_questions_usage_by_activities($condition);
+ question_engine::delete_questions_usage_by_activities($condition);
$DB->delete_records('jazzquiz_attempts', ['sessionid' => $sessionid]);
$DB->delete_records('jazzquiz_session_questions', ['sessionid' => $sessionid]);
$DB->delete_records('jazzquiz_votes', ['sessionid' => $sessionid]);
$DB->delete_records('jazzquiz_sessions', ['id' => $sessionid]);
- return true;
}
- public function user_name_for_answer($userid) {
+ /**
+ * Get appropriate display name linked to a question attempt.
+ *
+ * @param ?int $userid
+ * @return string
+ */
+ public function user_name_for_answer(?int $userid): string {
global $DB;
if ($this->requires_anonymous_answers() || is_null($userid)) {
return get_string('anonymous', 'jazzquiz');
@@ -142,7 +152,13 @@ public function user_name_for_answer($userid) {
return $user->lastname . ', ' . $user->firstname;
}
- public function user_name_for_attendance($userid) {
+ /**
+ * Get appropriate display name linked to session attendance.
+ *
+ * @param ?int $userid
+ * @return string
+ */
+ public function user_name_for_attendance(?int $userid): string {
global $DB;
if ($this->requires_anonymous_attendance() || is_null($userid)) {
return get_string('anonymous', 'jazzquiz');
@@ -154,7 +170,13 @@ public function user_name_for_attendance($userid) {
return $user->lastname . ', ' . $user->firstname;
}
- public function user_idnumber_for_attendance($userid) {
+ /**
+ * Get user ID for attendance.
+ *
+ * @param ?int $userid
+ * @return string
+ */
+ public function user_idnumber_for_attendance(?int $userid): string {
global $DB;
if ($this->requires_anonymous_attendance() || is_null($userid)) {
return get_string('anonymous', 'jazzquiz');
@@ -170,7 +192,7 @@ public function user_idnumber_for_attendance($userid) {
* Anonymize attendance, making it unknown how many questions each user has answered.
* Only makes sense to do this along with anonymizing answers. This should be called first.
*/
- private function anonymize_attendance() {
+ private function anonymize_attendance(): void {
global $DB;
$attendances = $DB->get_records('jazzquiz_attendance', ['sessionid' => $this->data->id]);
foreach ($attendances as $attendance) {
@@ -179,11 +201,16 @@ private function anonymize_attendance() {
}
}
- private function anonymize_users() {
+ /**
+ * Anonymize the attempts of users who have attended this session.
+ *
+ * @return void
+ */
+ private function anonymize_users(): void {
if ($this->requires_anonymous_attendance()) {
$this->anonymize_attendance();
}
- foreach ($this->attempts as &$attempt) {
+ foreach ($this->attempts as $attempt) {
if ($this->requires_anonymous_answers()) {
$attempt->anonymize_answers();
}
@@ -192,9 +219,8 @@ private function anonymize_users() {
/**
* Closes the attempts and ends the session.
- * @return bool Whether or not this was successful
*/
- public function end_session() {
+ public function end_session(): void {
$this->anonymize_users();
$this->data->status = 'notrunning';
$this->data->sessionopen = 0;
@@ -203,23 +229,24 @@ public function end_session() {
foreach ($this->attempts as $attempt) {
$attempt->close_attempt($this->jazzquiz);
}
- return $this->save();
+ $this->save();
}
/**
* Merge responses with 'from' to 'into'
+ *
* @param int $slot Session question slot
* @param string $from Original response text
* @param string $into Merged response text
*/
- public function merge_responses($slot, string $from, string $into) {
+ public function merge_responses(int $slot, string $from, string $into): void {
global $DB;
- $merge = new \stdClass();
+ $merge = new stdClass();
$merge->sessionid = $this->data->id;
$merge->slot = $slot;
$merge->ordernum = count($DB->get_records('jazzquiz_merges', [
'sessionid' => $this->data->id,
- 'slot' => $slot
+ 'slot' => $slot,
]));
$merge->original = $from;
$merge->merged = $into;
@@ -228,13 +255,14 @@ public function merge_responses($slot, string $from, string $into) {
/**
* Undo the last merge of the specified question.
+ *
* @param int $slot Session question slot
*/
- public function undo_merge($slot) {
+ public function undo_merge(int $slot): void {
global $DB;
$merge = $DB->get_records('jazzquiz_merges', [
'sessionid' => $this->data->id,
- 'slot' => $slot
+ 'slot' => $slot,
], 'ordernum desc', '*', 0, 1);
if (count($merge) > 0) {
$merge = reset($merge);
@@ -244,15 +272,16 @@ public function undo_merge($slot) {
/**
* Get the merged responses.
+ *
* @param int $slot Session question slot
- * @param string[]['response'] $responses Original responses
- * @return string[]['response'], int Merged responses and count of merges.
+ * @param array[] $responses 'response' contains original response
+ * @return int[]|string[] Merged responses and count of merges.
*/
- public function get_merged_responses($slot, array $responses) : array {
+ public function get_merged_responses(int $slot, array $responses): array {
global $DB;
$merges = $DB->get_records('jazzquiz_merges', [
'sessionid' => $this->data->id,
- 'slot' => $slot
+ 'slot' => $slot,
]);
$count = 0;
foreach ($merges as $merge) {
@@ -267,17 +296,17 @@ public function get_merged_responses($slot, array $responses) : array {
}
/**
- * Tells the session to go to the specified question number
- * That jazzquiz_question is then returned
+ * Go to the specified question number.
+ *
* @param int $questionid (from question bank)
* @param int $questiontime in seconds ("<0" => no time, "0" => default)
- * @return mixed[] $success, $question_time
+ * @return array $success, $question_time
*/
- public function start_question($questionid, $questiontime) {
+ public function start_question(int $questionid, int $questiontime): array {
global $DB;
$transaction = $DB->start_delegated_transaction();
- $sessionquestion = new \stdClass();
+ $sessionquestion = new stdClass();
$sessionquestion->sessionid = $this->data->id;
$sessionquestion->questionid = $questionid;
$sessionquestion->questiontime = $questiontime;
@@ -285,7 +314,7 @@ public function start_question($questionid, $questiontime) {
$sessionquestion->id = $DB->insert_record('jazzquiz_session_questions', $sessionquestion);
$this->questions[$sessionquestion->slot] = $sessionquestion;
- foreach ($this->attempts as &$attempt) {
+ foreach ($this->attempts as $attempt) {
$attempt->create_missing_attempts($this);
$attempt->save();
}
@@ -301,52 +330,44 @@ public function start_question($questionid, $questiontime) {
/**
* Create a quiz attempt for the current user.
*/
- public function initialize_attempt() {
+ public function initialize_attempt(): void {
global $USER;
// Check if this user has already joined the quiz.
- foreach ($this->attempts as &$attempt) {
- if ($attempt->data->userid == $USER->id) {
+ foreach ($this->attempts as $attempt) {
+ if ($attempt->userid == $USER->id) {
$attempt->create_missing_attempts($this);
$attempt->save();
- $this->attempt = $attempt;
+ $this->myattempt = $attempt;
return;
}
}
// For users who have not yet joined the quiz.
- $this->attempt = new jazzquiz_attempt($this->jazzquiz->context);
- $this->attempt->data->sessionid = $this->data->id;
- if (isguestuser($USER->id)) {
- $this->attempt->data->guestsession = $USER->sesskey;
- } else {
- $this->attempt->data->userid = $USER->id;
- }
- $this->attempt->data->status = jazzquiz_attempt::NOTSTARTED;
- $this->attempt->data->timemodified = time();
- $this->attempt->data->timestart = time();
- $this->attempt->data->responded = null;
- $this->attempt->data->timefinish = null;
- $this->attempt->create_missing_attempts($this);
- $this->attempt->save();
+ $this->myattempt = jazzquiz_attempt::create($this);
}
- public function update_attendance_for_current_user() {
+ /**
+ * Update attendance for the current user.
+ *
+ * @return void
+ */
+ public function update_attendance_for_current_user(): void {
global $DB, $USER;
if (isguestuser($USER->id)) {
return;
}
- $numresponses = $this->attempt->total_answers();
+ $numresponses = $this->myattempt->total_answers();
if ($numresponses === 0) {
return;
}
$attendance = $DB->get_record('jazzquiz_attendance', [
'sessionid' => $this->data->id,
- 'userid' => $USER->id
+ 'userid' => $USER->id,
]);
if ($attendance) {
$attendance->numresponses = $numresponses;
$DB->update_record('jazzquiz_attendance', $attendance);
} else {
- $attendance = new \stdClass();
+ $attendance = new stdClass();
$attendance->sessionid = $this->data->id;
$attendance->userid = $USER->id;
$attendance->numresponses = $numresponses;
@@ -357,40 +378,25 @@ public function update_attendance_for_current_user() {
/**
* Load all the attempts for this session.
*/
- public function load_attempts() {
+ public function load_attempts(): void {
global $DB;
$this->attempts = [];
- $attempts = $DB->get_records('jazzquiz_attempts', ['sessionid' => $this->data->id]);
- foreach ($attempts as $attempt) {
- $this->attempts[$attempt->id] = new jazzquiz_attempt($this->jazzquiz->context, $attempt);
+ foreach ($DB->get_records('jazzquiz_attempts', ['sessionid' => $this->data->id]) as $attempt) {
+ $this->attempts[$attempt->id] = jazzquiz_attempt::get_by_id($attempt->id);
}
}
/**
* Load the current attempt for the user.
*/
- public function load_attempt() {
- global $DB, $USER;
- $sql = 'SELECT *
- FROM {jazzquiz_attempts}
- WHERE sessionid = :sessionid
- AND (userid = :userid OR guestsession = :sesskey)';
- $attempt = $DB->get_record_sql($sql, [
- 'sessionid' => $this->data->id,
- 'userid' => $USER->id,
- 'sesskey' => $USER->sesskey
- ]);
- if (!$attempt) {
- $this->attempt = false;
- return;
- }
- $this->attempt = new jazzquiz_attempt($this->jazzquiz->context, $attempt);
+ public function load_my_attempt(): void {
+ $this->myattempt = jazzquiz_attempt::get_by_session_for_current_user($this);
}
/**
* Load all the session questions.
*/
- public function load_session_questions() {
+ public function load_session_questions(): void {
global $DB;
$this->questions = $DB->get_records('jazzquiz_session_questions', ['sessionid' => $this->data->id], 'slot');
foreach ($this->questions as $question) {
@@ -400,15 +406,16 @@ public function load_session_questions() {
}
/**
- * Get the user IDs for who have attempted this session
+ * Get the user IDs for who have attempted this session.
+ *
* @return int[] user IDs that have attempted this session
*/
- public function get_users() {
+ public function get_users(): array {
$users = [];
foreach ($this->attempts as $attempt) {
// Preview attempt means it's an instructor.
- if ($attempt->data->status != jazzquiz_attempt::PREVIEW) {
- $users[] = isguestuser($attempt->data->userid) ? null : $attempt->data->userid;
+ if ($attempt->status != jazzquiz_attempt::PREVIEW) {
+ $users[] = isguestuser($attempt->userid) ? null : $attempt->userid;
}
}
return $users;
@@ -416,9 +423,10 @@ public function get_users() {
/**
* Get the total number of students participating in the quiz.
+ *
* @return int
*/
- public function get_student_count() {
+ public function get_student_count(): int {
$count = count($this->attempts);
if ($count > 0) {
$count--; // The instructor also has an attempt.
@@ -430,19 +438,20 @@ public function get_student_count() {
/**
* Get the correct answer rendered in HTML.
+ *
* @return string HTML
*/
- public function get_question_right_response() {
+ public function get_question_right_response(): string {
// Use the current user's attempt to render the question with the right response.
- $quba = $this->attempt->quba;
+ $quba = $this->myattempt->quba;
$slot = count($this->questions);
$correctresponse = $quba->get_correct_response($slot);
if (is_null($correctresponse)) {
return 'No correct response';
}
$quba->process_action($slot, $correctresponse);
- $this->attempt->save();
- $reviewoptions = new \stdClass();
+ $this->myattempt->save();
+ $reviewoptions = new stdClass();
$reviewoptions->rightanswer = 1;
$reviewoptions->correctness = 1;
$reviewoptions->specificfeedback = 1;
@@ -450,21 +459,22 @@ public function get_question_right_response() {
/** @var output\renderer $renderer */
$renderer = $this->jazzquiz->renderer;
ob_start();
- $html = $renderer->render_question($this->jazzquiz, $this->attempt->quba, $slot, true, $reviewoptions);
+ $html = $renderer->render_question($this->jazzquiz, $this->myattempt->quba, $slot, true, $reviewoptions);
$htmlechoed = ob_get_clean();
return $html . $htmlechoed;
}
/**
- * Gets the results of the current question as an array
+ * Gets the results of the current question as an array.
+ *
* @param int $slot
* @return array
*/
- public function get_question_results_list($slot) {
+ public function get_question_results_list(int $slot): array {
$responses = [];
$responded = 0;
foreach ($this->attempts as $attempt) {
- if ($attempt->data->responded != 1) {
+ if ($attempt->responded != 1) {
continue;
}
$attemptresponses = $attempt->get_response_data($slot);
@@ -477,11 +487,16 @@ public function get_question_results_list($slot) {
return [
'responses' => $responses,
'responded' => $responded,
- 'student_count' => $this->get_student_count()
+ 'student_count' => $this->get_student_count(),
];
}
- public function get_attendances() : array {
+ /**
+ * Get attendances for this session.
+ *
+ * @return array
+ */
+ public function get_attendances(): array {
global $DB;
$attendances = [];
$records = $DB->get_records('jazzquiz_attendance', ['sessionid' => $this->data->id]);
@@ -489,14 +504,14 @@ public function get_attendances() : array {
$attendances[] = [
'idnumber' => $this->user_idnumber_for_attendance($record->userid),
'name' => $this->user_name_for_attendance($record->userid),
- 'count' => $record->numresponses
+ 'count' => $record->numresponses,
];
}
foreach ($this->attempts as $attempt) {
- if (!$attempt->data->userid && $attempt->data->guestsession) {
+ if (!$attempt->userid && $attempt->guestsession) {
$attendances[] = [
'name' => get_string('anonymous', 'jazzquiz'),
- 'count' => $attempt->total_answers()
+ 'count' => $attempt->total_answers(),
];
}
}
@@ -504,11 +519,12 @@ public function get_attendances() : array {
}
/**
- * @todo Temporary function. Should be removed at a later time.
+ * Get the question type for the specified slot.
+ *
* @param int $slot
* @return string
*/
- public function get_question_type_by_slot($slot) : string {
+ public function get_question_type_by_slot(int $slot): string {
global $DB;
$id = $this->questions[$slot]->questionid;
$question = $DB->get_record('question', ['id' => $id], 'qtype');
diff --git a/classes/jazzquiz_vote.php b/classes/jazzquiz_vote.php
index d8d7ee0..6b6275c 100755
--- a/classes/jazzquiz_vote.php
+++ b/classes/jazzquiz_vote.php
@@ -16,9 +16,11 @@
namespace mod_jazzquiz;
-defined('MOODLE_INTERNAL') || die();
+use stdClass;
/**
+ * A vote.
+ *
* @package mod_jazzquiz
* @author Sebastian S. Gundersen
* @copyright 2018 NTNU
@@ -27,39 +29,41 @@
class jazzquiz_vote {
/** @var int $sessionid */
- protected $sessionid;
+ protected int $sessionid;
/** @var int $slot */
- protected $slot;
+ protected int $slot;
/**
* Constructor.
+ *
* @param int $sessionid
* @param int $slot
*/
- public function __construct($sessionid, $slot = 0) {
+ public function __construct(int $sessionid, int $slot = 0) {
$this->sessionid = $sessionid;
$this->slot = $slot;
}
/**
* Get the results for the vote.
+ *
* @return array
*/
- public function get_results() {
+ public function get_results(): array {
global $DB;
- $votes = $DB->get_records('jazzquiz_votes', [
+ return $DB->get_records('jazzquiz_votes', [
'sessionid' => $this->sessionid,
- 'slot' => $this->slot
+ 'slot' => $this->slot,
]);
- return $votes;
}
/**
* Check whether a user has voted or not.
+ *
* @return bool
*/
- public function has_user_voted() {
+ public function has_user_voted(): bool {
global $DB, $USER;
$allvotes = $DB->get_records('jazzquiz_votes', ['sessionid' => $this->sessionid]);
if (!$allvotes) {
@@ -81,10 +85,11 @@ public function has_user_voted() {
/**
* Save the vote for a user.
+ *
* @param int $voteid
* @return bool
*/
- public function save_vote($voteid) {
+ public function save_vote(int $voteid): bool {
global $DB, $USER;
if ($this->has_user_voted()) {
return false;
@@ -109,12 +114,13 @@ public function save_vote($voteid) {
/**
* Insert the options for the vote.
+ *
* @param int $jazzquizid
* @param string $qtype
* @param array $options
* @param int $slot
*/
- public function prepare_options($jazzquizid, string $qtype, array $options, $slot) {
+ public function prepare_options(int $jazzquizid, string $qtype, array $options, int $slot): void {
global $DB;
// Delete previous voting options for this session.
@@ -122,7 +128,7 @@ public function prepare_options($jazzquizid, string $qtype, array $options, $slo
// Add to database.
foreach ($options as $option) {
- $vote = new \stdClass();
+ $vote = new stdClass();
$vote->jazzquizid = $jazzquizid;
$vote->sessionid = $this->sessionid;
$vote->attempt = $option['text'];
diff --git a/classes/local/page_requirements_diff.php b/classes/local/page_requirements_diff.php
new file mode 100644
index 0000000..48bcf65
--- /dev/null
+++ b/classes/local/page_requirements_diff.php
@@ -0,0 +1,80 @@
+.
+
+namespace mod_jazzquiz\local;
+
+use page_requirements_manager;
+
+/**
+ * Handles new page requirements without needing to refresh the page.
+ *
+ * To load a question without refreshing the page, we need the JavaScript for the question.
+ * Moodle stores this in page_requirements_manager, but there is no way to read the JS that is required.
+ * This class takes in the manager and keeps the JS for when we want to get a diff.
+ * NOTE: This class is placed here because it will only ever be used by renderer::render_question_form()
+ * TODO: Look into removing this class in the future.
+ *
+ * @package mod_jazzquiz
+ * @author Sebastian S. Gundersen
+ * @copyright 2018 NTNU
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class page_requirements_diff extends page_requirements_manager {
+
+ /** @var array */
+ private array $beforeinitjs;
+
+ /** @var array */
+ private array $beforeamdjs;
+
+ /** @var array */
+ private array $beforecss;
+
+ /**
+ * Constructor.
+ *
+ * @param page_requirements_manager $manager
+ */
+ public function __construct(page_requirements_manager $manager) {
+ $this->beforeinitjs = $manager->jsinitcode;
+ $this->beforeamdjs = $manager->amdjscode;
+ $this->beforecss = $manager->cssurls;
+ }
+
+ /**
+ * Run an array_diff on the required JavaScript when this
+ * was constructed and the one passed to this function.
+ *
+ * @param page_requirements_manager $manager
+ * @return array the JavaScript that was added in-between constructor and this call.
+ */
+ public function get_js_diff(page_requirements_manager $manager): array {
+ $jsinitcode = array_diff($manager->jsinitcode, $this->beforeinitjs);
+ $amdjscode = array_diff($manager->amdjscode, $this->beforeamdjs);
+ return array_merge($jsinitcode, $amdjscode);
+ }
+
+ /**
+ * Run an array_diff on the required CSS when this was constructed and the one passed to this function.
+ *
+ * @param page_requirements_manager $manager
+ * @return array the CSS that was added in-between constructor and this call.
+ */
+ public function get_css_diff(page_requirements_manager $manager): array {
+ return array_keys(array_diff($manager->cssurls, $this->beforecss));
+ }
+
+}
diff --git a/classes/output/renderer.php b/classes/output/renderer.php
index cc91f67..39a6f40 100755
--- a/classes/output/renderer.php
+++ b/classes/output/renderer.php
@@ -16,71 +16,21 @@
namespace mod_jazzquiz\output;
+use html_writer;
use mod_jazzquiz\forms\view\student_start_form;
use mod_jazzquiz\jazzquiz;
use mod_jazzquiz\jazzquiz_attempt;
use mod_jazzquiz\jazzquiz_session;
+use mod_jazzquiz\local\page_requirements_diff;
+use moodle_url;
+use moodleform;
+use question_usage_by_activity;
+use stdClass;
defined('MOODLE_INTERNAL') || die;
require_once($CFG->libdir . '/questionlib.php');
-/**
- * To load a question without refreshing the page, we need the JavaScript for the question.
- * Moodle stores this in page_requirements_manager, but there is no way to read the JS that is required.
- * This class takes in the manager and keeps the JS for when we want to get a diff.
- * NOTE: This class is placed here because it will only ever be used by renderer::render_question_form()
- * TODO: Look into removing this class in the future.
- * @package mod_jazzquiz\output
- * @author Sebastian S. Gundersen
- * @copyright 2018 NTNU
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-class page_requirements_diff extends \page_requirements_manager {
-
- /** @var array $beforeinitjs */
- private $beforeinitjs;
-
- /** @var array $beforeamdjs */
- private $beforeamdjs;
-
- /** @var array $beforecss */
- private $beforecss;
-
- /**
- * Constructor.
- * @param \page_requirements_manager $manager
- */
- public function __construct(\page_requirements_manager $manager) {
- $this->beforeinitjs = $manager->jsinitcode;
- $this->beforeamdjs = $manager->amdjscode;
- $this->beforecss = $manager->cssurls;
- }
-
- /**
- * Run an array_diff on the required JavaScript when this
- * was constructed and the one passed to this function.
- * @param \page_requirements_manager $manager
- * @return array the JavaScript that was added in-between constructor and this call.
- */
- public function get_js_diff(\page_requirements_manager $manager) : array {
- $jsinitcode = array_diff($manager->jsinitcode, $this->beforeinitjs);
- $amdjscode = array_diff($manager->amdjscode, $this->beforeamdjs);
- return array_merge($jsinitcode, $amdjscode);
- }
-
- /**
- * Run an array_diff on the required CSS when this
- * was constructed and the one passed to this function.
- * @param \page_requirements_manager $manager
- * @return array the CSS that was added in-between constructor and this call.
- */
- public function get_css_diff(\page_requirements_manager $manager) : array {
- return array_keys(array_diff($manager->cssurls, $this->beforecss));
- }
-
-}
-
/**
* Quiz renderer
*
@@ -94,10 +44,11 @@ class renderer extends \plugin_renderer_base {
/**
* Render the header for the page.
+ *
* @param jazzquiz $jazzquiz
* @param string $tab The active tab on the page
*/
- public function header(jazzquiz $jazzquiz, string $tab) {
+ public function header(jazzquiz $jazzquiz, string $tab): void {
echo $this->output->header();
echo jazzquiz_view_tabs($jazzquiz, $tab);
}
@@ -105,75 +56,72 @@ public function header(jazzquiz $jazzquiz, string $tab) {
/**
* Render the footer for the page.
*/
- public function footer() {
+ public function footer(): void {
echo $this->output->footer();
}
/**
* For instructors.
- * @param \moodleform $sessionform
+ *
+ * @param moodleform $sessionform
*/
- public function start_session_form(\moodleform $sessionform) {
+ public function start_session_form(moodleform $sessionform): void {
echo $this->render_from_template('jazzquiz/start_session', ['form' => $sessionform->render()]);
}
/**
* For instructors.
+ *
* @param jazzquiz $jazzquiz
*/
- public function continue_session_form(jazzquiz $jazzquiz) {
+ public function continue_session_form(jazzquiz $jazzquiz): void {
$cmid = $jazzquiz->cm->id;
$id = $jazzquiz->data->id;
echo $this->render_from_template('jazzquiz/continue_session', [
- 'path' => $this->page->url->get_path() . "?id=$cmid&quizid=$id&action=quizstart"
+ 'path' => $this->page->url->get_path() . "?id=$cmid&quizid=$id&action=quizstart",
]);
}
/**
* Show the "join quiz" form for students.
+ *
* @param student_start_form $form
* @param jazzquiz_session $session
- * @throws \moodle_exception
*/
- public function join_quiz_form(student_start_form $form, jazzquiz_session $session) {
+ public function join_quiz_form(student_start_form $form, jazzquiz_session $session): void {
$anonstr = ['', 'anonymous_answers_info', 'fully_anonymous_info', 'nonanonymous_session_info'];
echo $this->render_from_template('jazzquiz/join_session', [
'name' => $session->data->name,
- 'started' => ($session->attempt !== false),
+ 'started' => $session->myattempt !== false,
'anonymity_info' => get_string($anonstr[$session->data->anonymity], 'jazzquiz'),
- 'form' => $form->render()
+ 'form' => $form->render(),
]);
}
/**
* Show the "quiz not running" page for students.
+ *
* @param int $cmid the course module id for the quiz
- * @throws \moodle_exception
*/
- public function quiz_not_running($cmid) {
+ public function quiz_not_running(int $cmid): void {
echo $this->render_from_template('jazzquiz/no_session', [
- 'reload' => $this->page->url->get_path() . '?id=' . $cmid
+ 'reload' => $this->page->url->get_path() . "?id=$cmid",
]);
}
-
/**
- * Shows the "guests not allowed" page when trying to access a
- * quiz which does not allow guests in guest mode.
- * @throws \moodle_exception
+ * Shows the "guests not allowed" page when trying to access a quiz which does not allow guests in guest mode.
*/
- public function guests_not_allowed() {
+ public function guests_not_allowed(): void {
echo $this->render_from_template('jazzquiz/guests_not_allowed', []);
}
-
-
/**
- * Renders the quiz to the page
+ * Renders the quiz to the page.
+ *
* @param jazzquiz_session $session
- * @throws \moodle_exception
*/
- public function render_quiz(jazzquiz_session $session) {
+ public function render_quiz(jazzquiz_session $session): void {
$this->require_quiz($session);
$buttons = function($buttons) {
$result = [];
@@ -181,7 +129,7 @@ public function render_quiz(jazzquiz_session $session) {
$result[] = [
'icon' => $button[0],
'id' => $button[1],
- 'text' => get_string($button[1], 'jazzquiz')
+ 'text' => get_string($button[1], 'jazzquiz'),
];
}
return $result;
@@ -198,38 +146,40 @@ public function render_quiz(jazzquiz_session $session) {
['expand', 'fullscreen'],
['window-close', 'quit'],
['square-o', 'responses'],
- ['square-o', 'answer']
+ ['square-o', 'answer'],
]),
- 'instructor' => $session->jazzquiz->is_instructor()
+ 'instructor' => $session->jazzquiz->is_instructor(),
]);
}
/**
- * Render the question specified by slot
+ * Render the question specified by slot.
+ *
* @param jazzquiz $jazzquiz
- * @param \question_usage_by_activity $quba
+ * @param question_usage_by_activity $quba
* @param int $slot
- * @param bool $review Whether or not we're reviewing the attempt
- * @param string|\stdClass $reviewoptions Can be string for overall actions like "edit" or an object of review options
+ * @param bool $review Are we reviewing the attempt?
+ * @param string|stdClass $reviewoptions Review options as either string or object
* @return string the HTML fragment for the question
*/
- public function render_question(jazzquiz $jazzquiz, $quba, $slot, bool $review, $reviewoptions) : string {
+ public function render_question(jazzquiz $jazzquiz, question_usage_by_activity $quba, int $slot, bool $review,
+ string|stdClass $reviewoptions): string {
$displayoptions = $jazzquiz->get_display_options($review, $reviewoptions);
$quba->render_question_head_html($slot);
return $quba->render_question($slot, $displayoptions, $slot);
}
/**
- * Render a specific question in its own form so it can be submitted
- * independently of the rest of the questions
+ * Render a specific question in its own form, so it can be submitted
+ * independently of the rest of the questions.
+ *
* @param int $slot the id of the question we're rendering
* @param jazzquiz_attempt $attempt
* @param jazzquiz $jazzquiz
* @param bool $instructor
* @return string[] html, javascript, css
- * @throws \moodle_exception
*/
- public function render_question_form($slot, jazzquiz_attempt $attempt, jazzquiz $jazzquiz, bool $instructor) : array {
+ public function render_question_form(int $slot, jazzquiz_attempt $attempt, jazzquiz $jazzquiz, bool $instructor): array {
$differ = new page_requirements_diff($this->page->requires);
ob_start();
$questionhtml = $this->render_question($jazzquiz, $attempt->quba, $slot, false, '');
@@ -239,25 +189,23 @@ public function render_question_form($slot, jazzquiz_attempt $attempt, jazzquiz
$output = $this->render_from_template('jazzquiz/question', [
'instructor' => $instructor,
'question' => $questionhtml . $questionhtmlechoed,
- 'slot' => $slot
+ 'slot' => $slot,
]);
return [$output, $js, $css];
}
/**
- * Renders and echos the home page for the responses section
- * @param \moodle_url $url
- * @param \stdClass[] $sessions
+ * Renders and echos the home page for the responses section.
+ *
+ * @param moodle_url $url
+ * @param stdClass[] $sessions
* @param int $selectedid
* @return array
- * @throws \coding_exception
*/
- public function get_select_session_context(\moodle_url $url, array $sessions, $selectedid) : array {
+ public function get_select_session_context(moodle_url $url, array $sessions, int $selectedid): array {
$selecturl = clone($url);
$selecturl->param('action', 'view');
- usort($sessions, function ($a, $b) {
- return strcmp(strtolower($a->name), strtolower($b->name));
- });
+ usort($sessions, fn(stdClass $a, stdClass $b) => strcmp(strtolower($a->name), strtolower($b->name)));
return [
'method' => 'get',
'action' => $selecturl->out_omit_querystring(),
@@ -268,28 +216,28 @@ public function get_select_session_context(\moodle_url $url, array $sessions, $s
return [
'name' => $session->name,
'value' => $session->id,
- 'selected' => intval($selectedid) === intval($session->id),
- 'optgroup' => false
+ 'selected' => $selectedid === (int)$session->id,
+ 'optgroup' => false,
];
}, $sessions),
'params' => array_map(function ($key, $value) {
return [
'name' => $key,
- 'value' => $value
+ 'value' => $value,
];
}, array_keys($selecturl->params()), $selecturl->params()),
];
}
/**
- * Render the list questions view for the edit page
+ * Render the list questions view for the edit page.
+ *
* @param jazzquiz $jazzquiz
* @param array $questions Array of questions
* @param string $questionbankview HTML for the question bank view
- * @param \moodle_url $url
- * @throws \moodle_exception
+ * @param moodle_url $url
*/
- public function list_questions(jazzquiz $jazzquiz, array $questions, string $questionbankview, \moodle_url $url) {
+ public function list_questions(jazzquiz $jazzquiz, array $questions, string $questionbankview, moodle_url $url): void {
$slot = 1;
$list = [];
foreach ($questions as $question) {
@@ -303,28 +251,34 @@ public function list_questions(jazzquiz $jazzquiz, array $questions, string $que
'last' => $slot === count($questions),
'slot' => $slot,
'editurl' => $editurl,
- 'icon' => print_question_icon($question->question)
+ 'icon' => print_question_icon($question->question),
];
$slot++;
}
echo $this->render_from_template('jazzquiz/edit_question_list', [
'questions' => $list,
- 'qbank' => $questionbankview
+ 'qbank' => $questionbankview,
]);
$this->require_edit($jazzquiz->cm->id);
}
- public function session_is_open_error() {
- echo \html_writer::tag('h3', get_string('edit_page_open_session_error', 'jazzquiz'));
+ /**
+ * Display header stating the session is open.
+ *
+ * @return void
+ */
+ public function session_is_open_error(): void {
+ echo html_writer::tag('h3', get_string('edit_page_open_session_error', 'jazzquiz'));
}
/**
+ * View session report.
+ *
* @param jazzquiz_session $session
- * @param \moodle_url $url
- * @return mixed[]
- * @throws \coding_exception
+ * @param moodle_url $url
+ * @return array
*/
- public function view_session_report(jazzquiz_session $session, \moodle_url $url) : array {
+ public function view_session_report(jazzquiz_session $session, moodle_url $url): array {
$attempt = reset($session->attempts);
if (!$attempt) {
$strnoattempts = get_string('no_attempts_found', 'jazzquiz');
@@ -342,7 +296,7 @@ public function view_session_report(jazzquiz_session $session, \moodle_url $url)
'name' => str_replace('{IMPROV}', '', $question->name),
'type' => $attempt->quba->get_question_attempt($qubaslot)->get_question()->get_type_name(),
'description' => $question->questiontext,
- 'responses' => $results['responses']
+ 'responses' => $results['responses'],
];
}
@@ -362,43 +316,34 @@ public function view_session_report(jazzquiz_session $session, \moodle_url $url)
'count_answered' => count($attendances),
'cmid' => $jazzquiz->cm->id,
'quizid' => $jazzquiz->data->id,
- 'id' => $session->data->id
- ]
+ 'id' => $session->data->id,
+ ],
];
}
/**
+ * Require the core javascript.
+ *
* @param jazzquiz_session $session
*/
- public function require_core(jazzquiz_session $session) {
+ public function require_core(jazzquiz_session $session): void {
$this->page->requires->js_call_amd('mod_jazzquiz/core', 'initialize', [
$session->jazzquiz->cm->id,
$session->jazzquiz->data->id,
$session->data->id,
- $session->attempt ? $session->attempt->data->id : 0,
- sesskey()
+ $session->myattempt?->id ?? 0,
+ sesskey(),
]);
}
/**
+ * Require the quiz javascript based on the current user's role.
+ *
* @param jazzquiz_session $session
*/
- public function require_quiz(jazzquiz_session $session) {
+ public function require_quiz(jazzquiz_session $session): void {
$this->require_core($session);
-
- // question/qengine.js is deprecated for Moodle versions after 401.
- // Checks moodle version in order to determine which question engine
- // to use, making the jazzquiz independent of the Moodle version.
- global $CFG;
- include $CFG->dirroot.'/version.php';
- $branch = $CFG->branch;
-
- if ( (int) $branch <= 401 ) {
- $this->page->requires->js('/question/qengine.js');
- } else {
- $this->page->requires->js_call_amd('core_question/question_engine', 'initialize');
- }
-
+ $this->page->requires->js_call_amd('core_question/question_engine', 'initSubmitButton');
if ($session->jazzquiz->is_instructor()) {
$count = count($session->jazzquiz->questions);
$params = [$count, false, []];
@@ -409,18 +354,22 @@ public function require_quiz(jazzquiz_session $session) {
}
/**
+ * Require the edit javascript for the instructor.
+ *
* @param int $cmid
*/
- public function require_edit($cmid) {
+ public function require_edit(int $cmid): void {
$this->page->requires->js('/mod/jazzquiz/js/sortable.min.js');
$this->page->requires->js_call_amd('mod_jazzquiz/edit', 'initialize', [$cmid]);
}
/**
+ * Require the review javascript for the instructor.
+ *
* @param jazzquiz_session $session
* @param array $slots
*/
- public function require_review(jazzquiz_session $session, array $slots) {
+ public function require_review(jazzquiz_session $session, array $slots): void {
$this->require_core($session);
$count = count($session->jazzquiz->questions);
$params = [$count, true, $slots];
diff --git a/classes/privacy/provider.php b/classes/privacy/provider.php
index 2a67ae0..c18123e 100644
--- a/classes/privacy/provider.php
+++ b/classes/privacy/provider.php
@@ -26,14 +26,15 @@
namespace mod_jazzquiz\privacy;
+use context;
+use context_module;
use core_privacy\local\metadata\collection;
use core_privacy\local\request\approved_contextlist;
use core_privacy\local\request\contextlist;
use core_privacy\local\request\helper;
use core_privacy\local\request\transform;
use core_privacy\local\request\writer;
-
-defined('MOODLE_INTERNAL') || die();
+use stdClass;
/**
* Privacy Subsystem implementation for mod_jazzquiz.
@@ -51,11 +52,12 @@ class provider implements
\core_privacy\local\request\plugin\provider {
/**
- * Returns meta data about this system.
- * @param collection $items The initialised collection to add metadata to.
- * @return collection A listing of user data stored through this system.
+ * Returns metadata about this system.
+ *
+ * @param collection $items The initialised collection to add metadata to.
+ * @return collection A listing of user data stored through this system.
*/
- public static function get_metadata(collection $items) : collection {
+ public static function get_metadata(collection $items): collection {
// The table 'jazzquiz' stores a record for each JazzQuiz.
// It does not contain user personal data, but data is returned from it for contextual requirements.
@@ -66,7 +68,7 @@ public static function get_metadata(collection $items) : collection {
'responded' => 'privacy:metadata:jazzquiz_attempts:responded',
'timestart' => 'privacy:metadata:jazzquiz_attempts:timestart',
'timefinish' => 'privacy:metadata:jazzquiz_attempts:timefinish',
- 'timemodified' => 'privacy:metadata:jazzquiz_attempts:timemodified'
+ 'timemodified' => 'privacy:metadata:jazzquiz_attempts:timemodified',
], 'privacy:metadata:jazzquiz_attempts');
// The 'jazzquiz_merges' table is used to merge one question attempt into another in a JazzQuiz session.
@@ -92,10 +94,10 @@ public static function get_metadata(collection $items) : collection {
/**
* Get the list of contexts where the specified user has attempted a JazzQuiz.
*
- * @param int $userid The user to search.
- * @return contextlist $contextlist The contextlist containing the list of contexts used in this plugin.
+ * @param int $userid The user to search.
+ * @return contextlist $contextlist The contextlist containing the list of contexts used in this plugin.
*/
- public static function get_contexts_for_userid(int $userid) : contextlist {
+ public static function get_contexts_for_userid(int $userid): contextlist {
$sql = 'SELECT cx.id
FROM {context} cx
JOIN {course_modules} cm
@@ -115,24 +117,18 @@ public static function get_contexts_for_userid(int $userid) : contextlist {
$contextlist->add_from_sql($sql, [
'contextlevel' => CONTEXT_MODULE,
'modname' => 'jazzquiz',
- 'userid' => $userid
+ 'userid' => $userid,
]);
return $contextlist;
}
/**
- * Export all user data for the specified user, in the specified contexts.
+ * Export all user data for the specified user in the specified contexts.
*
- * @param approved_contextlist $contextlist The approved contexts to export information for.
- * @throws \coding_exception
- * @throws \dml_exception
- * @throws \moodle_exception
+ * @param approved_contextlist $contextlist The approved contexts to export information for.
*/
- public static function export_user_data(approved_contextlist $contextlist) {
+ public static function export_user_data(approved_contextlist $contextlist): void {
global $DB;
- if (empty($contextlist)) {
- return;
- }
$user = $contextlist->get_user();
list($contextsql, $contextparams) = $DB->get_in_or_equal($contextlist->get_contextids(), SQL_PARAMS_NAMED);
$sql = "SELECT cm.id AS cmid
@@ -161,7 +157,7 @@ public static function export_user_data(approved_contextlist $contextlist) {
// Fetch the individual quizzes.
$quizzes = $DB->get_recordset_sql($sql, $params);
foreach ($quizzes as $quiz) {
- $context = \context_module::instance($quiz->cmid);
+ $context = context_module::instance($quiz->cmid);
$data = helper::get_context_data($context, $user);
helper::export_context_files($context, $user);
writer::with_context($context)->export_data([], $data);
@@ -170,7 +166,13 @@ public static function export_user_data(approved_contextlist $contextlist) {
static::export_quiz_attempts($contextlist);
}
- protected static function export_quiz_attempts(approved_contextlist $contextlist) {
+ /**
+ * Export all quiz attempts for the specified user in the specified contexts.
+ *
+ * @param approved_contextlist $contextlist
+ * @return void
+ */
+ protected static function export_quiz_attempts(approved_contextlist $contextlist): void {
global $DB;
$userid = $contextlist->get_user()->id;
$sql = "SELECT cx.id AS contextid,
@@ -198,12 +200,12 @@ protected static function export_quiz_attempts(approved_contextlist $contextlist
$params = [
'contextlevel' => CONTEXT_MODULE,
'userid' => $userid,
- 'modname' => 'jazzquiz'
+ 'modname' => 'jazzquiz',
];
$attempts = $DB->get_recordset_sql($sql, $params);
foreach ($attempts as $attempt) {
$options = new \question_display_options();
- $options->context = \context_module::instance($attempt->cmid);
+ $options->context = context_module::instance($attempt->cmid);
$attemptsubcontext = [$attempt->sessionname . ' ' . $attempt->sessionid . ' ' . $attempt->id];
// This attempt was made by the user. They 'own' all data on it. Store the question usage data.
\core_question\privacy\provider::export_question_usage(
@@ -212,10 +214,10 @@ protected static function export_quiz_attempts(approved_contextlist $contextlist
$attemptsubcontext,
$attempt->qubaid,
$options,
- true
+ true,
);
// Store the quiz attempt data.
- $data = new \stdClass();
+ $data = new stdClass();
$data->responded = $attempt->responded;
$data->timestart = transform::datetime($attempt->timestart);
$data->timefinish = transform::datetime($attempt->timefinish);
@@ -228,9 +230,9 @@ protected static function export_quiz_attempts(approved_contextlist $contextlist
/**
* Delete all data for all users in the specified context.
*
- * @param \context $context The specific context to delete data for.
+ * @param context $context The specific context to delete data for.
*/
- public static function delete_data_for_all_users_in_context(\context $context) {
+ public static function delete_data_for_all_users_in_context(context $context): void {
global $DB;
if ($context->contextlevel != CONTEXT_MODULE) {
return;
@@ -249,9 +251,9 @@ public static function delete_data_for_all_users_in_context(\context $context) {
/**
* Delete all user data for the specified user, in the specified contexts.
*
- * @param approved_contextlist $contextlist The approved contexts and user information to delete information for.
+ * @param approved_contextlist $contextlist Approved contexts and user information to delete information for.
*/
- public static function delete_data_for_user(approved_contextlist $contextlist) {
+ public static function delete_data_for_user(approved_contextlist $contextlist): void {
global $DB;
if (empty($contextlist->count())) {
return;
diff --git a/db/access.php b/db/access.php
index 4a32cf9..e6a1e0d 100755
--- a/db/access.php
+++ b/db/access.php
@@ -14,94 +14,70 @@
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see .
-defined('MOODLE_INTERNAL') || die();
-
-/* Capability definitions for the jazzquiz module.
- *
- * The capabilities are loaded into the database table when the module is
- * installed or updated. Whenever the capability definitions are updated,
- * the module version number should be bumped up.
- *
- * The system has four possible values for a capability:
- * CAP_ALLOW, CAP_PREVENT, CAP_PROHIBIT, and inherit (not set).
- *
- * CAPABILITY NAMING CONVENTION
- *
- * It is important that capability names are unique. The naming convention
- * Capabilities specific to modules and blocks is as follows:
- * [mod/block]/:
- *
- * component_name should be the same as the directory name of the mod or block.
+/**
+ * Capability definitions for the jazzquiz module.
*
- * Core moodle capabilities are defined thus:
- * moodle/:
- *
- * Examples:
- * mod/forum:viewpost
- * block/recent_activity:view
- * moodle/site:deleteuser
- *
- * The variable name for the capability definitions array follows the format:
- * $__capabilities
- *
- * For the core capabilities, the variable is $moodle_capabilities.
+ * @package mod_jazzquiz
+ * @copyright 2024 NTNU
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
+defined('MOODLE_INTERNAL') || die();
+
$capabilities = [
// Can start a quiz and move on to the next question.
// NB: must have 'attempt' as well to be able to see the questions.
'mod/jazzquiz:control' => [
- 'captype' => 'write',
+ 'captype' => 'write',
'contextlevel' => CONTEXT_MODULE,
- 'legacy' => [
- 'teacher' => CAP_ALLOW,
+ 'legacy' => [
+ 'teacher' => CAP_ALLOW,
'editingteacher' => CAP_ALLOW,
- 'manager' => CAP_ALLOW
- ]
+ 'manager' => CAP_ALLOW,
+ ],
],
// Can try to answer the quiz.
'mod/jazzquiz:attempt' => [
- 'captype' => 'write',
+ 'captype' => 'write',
'contextlevel' => CONTEXT_MODULE,
- 'legacy' => [
- 'student' => CAP_ALLOW,
- 'teacher' => CAP_ALLOW,
+ 'legacy' => [
+ 'student' => CAP_ALLOW,
+ 'teacher' => CAP_ALLOW,
'editingteacher' => CAP_ALLOW,
- 'manager' => CAP_ALLOW
- ]
+ 'manager' => CAP_ALLOW,
+ ],
],
// Can see who gave what answer.
'mod/jazzquiz:seeresponses' => [
- 'captype' => 'read',
+ 'captype' => 'read',
'contextlevel' => CONTEXT_MODULE,
- 'legacy' => [
- 'teacher' => CAP_ALLOW,
+ 'legacy' => [
+ 'teacher' => CAP_ALLOW,
'editingteacher' => CAP_ALLOW,
- 'manager' => CAP_ALLOW
- ]
+ 'manager' => CAP_ALLOW,
+ ],
],
// Can add / delete / update questions.
'mod/jazzquiz:editquestions' => [
- 'captype' => 'write',
+ 'captype' => 'write',
'contextlevel' => CONTEXT_MODULE,
- 'legacy' => [
+ 'legacy' => [
'editingteacher' => CAP_ALLOW,
- 'manager' => CAP_ALLOW
- ]
+ 'manager' => CAP_ALLOW,
+ ],
],
// Can add an instance of this module to a course.
'mod/jazzquiz:addinstance' => [
- 'captype' => 'write',
+ 'captype' => 'write',
'contextlevel' => CONTEXT_COURSE,
- 'legacy' => [
+ 'legacy' => [
'editingteacher' => CAP_ALLOW,
- 'coursecreator' => CAP_ALLOW,
- 'manager' => CAP_ALLOW
- ]
+ 'coursecreator' => CAP_ALLOW,
+ 'manager' => CAP_ALLOW,
+ ],
],
];
-
diff --git a/db/upgrade.php b/db/upgrade.php
index 4b1d59f..28461ea 100755
--- a/db/upgrade.php
+++ b/db/upgrade.php
@@ -14,9 +14,21 @@
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see .
-defined('MOODLE_INTERNAL') || die();
+/**
+ * Upgrade script for JazzQuiz.
+ *
+ * @package mod_jazzquiz
+ * @copyright 2024 NTNU
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
-function xmldb_jazzquiz_upgrade($oldversion) {
+/**
+ * The upgrade script for JazzQuiz.
+ *
+ * @package mod_jazzquiz
+ * @param int $oldversion
+ */
+function xmldb_jazzquiz_upgrade(int $oldversion): bool {
global $DB;
$dbman = $DB->get_manager();
if ($oldversion < 2019061911) {
diff --git a/edit.php b/edit.php
index 17475cd..eb89321 100755
--- a/edit.php
+++ b/edit.php
@@ -26,6 +26,10 @@
namespace mod_jazzquiz;
+use core_question\local\bank\question_edit_contexts;
+use mod_jazzquiz\bank\add_questions_bank_view;
+use moodle_url;
+
require_once('../../config.php');
require_once($CFG->dirroot . '/mod/jazzquiz/lib.php');
require_once($CFG->dirroot . '/mod/jazzquiz/locallib.php');
@@ -35,83 +39,53 @@
/**
* Check if this JazzQuiz has an open session.
+ *
* @param int $jazzquizid
* @return bool
- * @throws \dml_exception
*/
-function jazzquiz_session_open($jazzquizid) {
+function jazzquiz_session_open(int $jazzquizid): bool {
global $DB;
$sessions = $DB->get_records('jazzquiz_sessions', [
'jazzquizid' => $jazzquizid,
- 'sessionopen' => 1
+ 'sessionopen' => 1,
]);
return count($sessions) > 0;
}
/**
- * Gets the question bank view based on the options passed in at the page setup.
- * @param \core_question\local\bank\question_edit_contexts $contexts
+ * Outputs the list of questions using the renderer for jazzquiz.
+ *
+ * @param question_edit_contexts $contexts
* @param jazzquiz $jazzquiz
- * @param \moodle_url $url
+ * @param moodle_url $url
* @param array $pagevars
- * @return string
- * @throws \coding_exception
*/
-function get_qbank_view(
- \core_question\local\bank\question_edit_contexts $contexts,
- jazzquiz $jazzquiz, \moodle_url $url, array $pagevars) {
-
- $qperpage = optional_param('qperpage', 10, PARAM_INT);
- $qpage = optional_param('qpage', 0, PARAM_INT);
- $newpagevars = [
- 'qpage' => $qpage,
- 'qperpage' => $qperpage,
- 'cat' => $pagevars['cat'],
- 'recurse' => $pagevars['recurse'],
- 'showhidden' => $pagevars['showhidden'],
- 'qbshowtext' => $pagevars['qbshowtext']
- ];
- // Capture question bank display in buffer to have the renderer render output.
+function list_questions(question_edit_contexts $contexts, jazzquiz $jazzquiz, moodle_url $url, array $pagevars): void {
ob_start();
- $questionbank = new bank\jazzquiz_question_bank_view($contexts, $url, $jazzquiz->course, $jazzquiz->cm);
- $questionbank->display($newpagevars, 'editq');
- return ob_get_clean();
-}
-
-/**
- * Echos the list of questions using the renderer for jazzquiz.
- * @param \core_question\local\bank\question_edit_contexts $contexts
- * @param jazzquiz $jazzquiz
- * @param \moodle_url $url
- * @param array $pagevars
- * @throws \coding_exception
- * @throws \moodle_exception
- */
-function list_questions(
- \core_question\local\bank\question_edit_contexts $contexts,
- jazzquiz $jazzquiz, \moodle_url $url, array $pagevars) {
-
- $qbankview = get_qbank_view($contexts, $jazzquiz, $url, $pagevars);
+ $questionbank = new add_questions_bank_view($contexts, $url, $jazzquiz->course, $jazzquiz->cm, $pagevars);
+ $questionbank->display();
+ $qbankview = ob_get_clean();
$jazzquiz->renderer->list_questions($jazzquiz, $jazzquiz->questions, $qbankview, $url);
}
/**
+ * Edit question order.
+ *
* @param jazzquiz $jazzquiz
- * @throws \coding_exception
*/
-function jazzquiz_edit_order(jazzquiz $jazzquiz) {
+function jazzquiz_edit_order(jazzquiz $jazzquiz): void {
$order = required_param('order', PARAM_RAW);
$order = json_decode($order);
$jazzquiz->set_question_order($order);
}
/**
+ * Add a question to the quiz.
+ *
* @param jazzquiz $jazzquiz
- * @param \moodle_url $url
- * @throws \coding_exception
- * @throws \moodle_exception
+ * @param moodle_url $url
*/
-function jazzquiz_edit_add_question(jazzquiz $jazzquiz, \moodle_url $url) {
+function jazzquiz_edit_add_question(jazzquiz $jazzquiz, moodle_url $url): void {
$questionids = required_param('questionids', PARAM_TEXT);
$questionids = explode(',', $questionids);
foreach ($questionids as $questionid) {
@@ -123,26 +97,24 @@ function jazzquiz_edit_add_question(jazzquiz $jazzquiz, \moodle_url $url) {
}
/**
+ * Edit a question.
+ *
* @param jazzquiz $jazzquiz
- * @throws \coding_exception
*/
-function jazzquiz_edit_edit_question(jazzquiz $jazzquiz) {
+function jazzquiz_edit_edit_question(jazzquiz $jazzquiz): void {
$questionid = required_param('questionid', PARAM_INT);
$jazzquiz->edit_question($questionid);
}
/**
+ * Show list of questions.
+ *
* @param jazzquiz $jazzquiz
- * @param \core_question\local\bank\question_edit_contexts $contexts
- * @param \moodle_url $url
- * @param $pagevars
- * @throws \coding_exception
- * @throws \moodle_exception
+ * @param question_edit_contexts $contexts
+ * @param moodle_url $url
+ * @param array $pagevars
*/
-function jazzquiz_edit_qlist(
- jazzquiz $jazzquiz, \core_question\local\bank\question_edit_contexts $contexts,
- \moodle_url $url, array $pagevars) {
-
+function jazzquiz_edit_qlist(jazzquiz $jazzquiz, question_edit_contexts $contexts, moodle_url $url, array $pagevars): void {
$jazzquiz->renderer->header($jazzquiz, 'edit');
list_questions($contexts, $jazzquiz, $url, $pagevars);
$jazzquiz->renderer->footer();
@@ -151,7 +123,7 @@ function jazzquiz_edit_qlist(
/**
* View edit page.
*/
-function jazzquiz_edit() {
+function jazzquiz_edit(): void {
global $PAGE, $COURSE;
$action = optional_param('action', 'listquestions', PARAM_ALPHA);
diff --git a/index.php b/index.php
index f73473e..f4754f7 100755
--- a/index.php
+++ b/index.php
@@ -26,11 +26,8 @@
require_once('../../config.php');
require_once('lib.php');
-$id = required_param('id', PARAM_INT); // Course ID.
-$course = $DB->get_record('course', ['id' => $id]);
-if (!$course) {
- error('Course ID is incorrect');
-}
+$courseid = required_param('id', PARAM_INT);
+$course = $DB->get_record('course', ['id' => $courseid], '*', MUST_EXIST);
$PAGE->set_url(new moodle_url('/mod/jazzquiz/index.php', ['id' => $course->id]));
require_course_login($course);
@@ -72,9 +69,7 @@
}
foreach ($jazzquizzes as $jazzquiz) {
- $url = new moodle_url('/mod/jazzquiz/view.php', [
- 'cmid' => $jazzquiz->coursemodule
- ]);
+ $url = new moodle_url('/mod/jazzquiz/view.php', ['cmid' => $jazzquiz->coursemodule]);
if (!$jazzquiz->visible) {
// Show dimmed if the mod is hidden.
$link = '' . $jazzquiz->name . '';
@@ -91,4 +86,3 @@
echo html_writer::table($table);
echo $OUTPUT->footer();
-
diff --git a/lang/en/jazzquiz.php b/lang/en/jazzquiz.php
index 0c0f145..dff8398 100755
--- a/lang/en/jazzquiz.php
+++ b/lang/en/jazzquiz.php
@@ -166,7 +166,6 @@
$string['no_attempts_found'] = 'No attempts found.';
$string['student'] = 'Student';
-// Problem: $string['student_id'] = 'StudentID'; //not working in report.mustache, not sure why
$string['select_session'] = 'Select session to review:';
$string['attendance_list'] = 'Attendance list';
$string['download_report'] = 'Download report';
@@ -177,8 +176,7 @@
// Instructions.
$string['instructions_for_student'] = 'Please wait for the instructor to start the quiz.
';
-$string['instructions_for_instructor'] = '
- Please make sure to read the instructions:
+$string['instructions_for_instructor'] = 'Please make sure to read the instructions:
There are hotkeys available, which can be used when an input field is not focused.
diff --git a/lib.php b/lib.php
index 75f85bb..bf824f5 100755
--- a/lib.php
+++ b/lib.php
@@ -15,7 +15,7 @@
// along with Moodle. If not, see .
/**
- * Library of functions and constants for module jazzquiz
+ * Library of functions and constants for module jazzquiz.
*
* @package mod_jazzquiz
* @author John Hoopes
@@ -23,19 +23,15 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
-defined('MOODLE_INTERNAL') || die();
+use mod_jazzquiz\jazzquiz_session;
/**
- * Given an object containing all the necessary data,
- * (defined by the form in mod.html) this function
- * will create a new instance and return the id number
- * of the new instance.
+ * Create a new JazzQuiz instance.
*
- * @param \stdClass $jazzquiz An object from the form in mod.html
+ * @param stdClass $jazzquiz An object from the form in mod.html
* @return int The id of the newly inserted jazzquiz record
- * @throws dml_exception
*/
-function jazzquiz_add_instance(\stdClass $jazzquiz) {
+function jazzquiz_add_instance(stdClass $jazzquiz): int {
global $DB;
$jazzquiz->timemodified = time();
$jazzquiz->timecreated = time();
@@ -44,15 +40,12 @@ function jazzquiz_add_instance(\stdClass $jazzquiz) {
}
/**
- * Given an object containing all the necessary data,
- * (defined by the form in mod.html) this function
- * will update an existing instance with new data.
+ * Update JazzQuiz instance with new data.
*
- * @param \stdClass $jazzquiz An object from the form in mod.html
- * @return boolean Success/Fail
- * @throws dml_exception
+ * @param stdClass $jazzquiz An object from the form in mod.html
+ * @return bool Success/Fail
*/
-function jazzquiz_update_instance(\stdClass $jazzquiz) {
+function jazzquiz_update_instance(stdClass $jazzquiz): bool {
global $DB;
$jazzquiz->timemodified = time();
$jazzquiz->id = $jazzquiz->instance;
@@ -61,45 +54,35 @@ function jazzquiz_update_instance(\stdClass $jazzquiz) {
}
/**
- * Given an ID of an instance of this module,
- * this function will permanently delete the instance and any data that depends on it.
+ * Permanently delete a JazzQuiz instance and any data that depends on it.
*
- * @param int $id Id of the module instance
- * @return boolean Success/Failure
+ * @param int $id Module instance ID
+ * @return bool Success/Failure
**/
-function jazzquiz_delete_instance($id) {
+function jazzquiz_delete_instance(int $id): bool {
global $DB, $CFG;
require_once($CFG->dirroot . '/mod/jazzquiz/locallib.php');
require_once($CFG->libdir . '/questionlib.php');
require_once($CFG->dirroot . '/question/editlib.php');
- try {
- $jazzquiz = $DB->get_record('jazzquiz', ['id' => $id], '*', MUST_EXIST);
- // Go through each session and then delete them (also deletes all attempts for them).
- $sessions = $DB->get_records('jazzquiz_sessions', ['jazzquizid' => $jazzquiz->id]);
- foreach ($sessions as $session) {
- \mod_jazzquiz\jazzquiz_session::delete($session->id);
- }
- // Delete all questions for this quiz.
- $DB->delete_records('jazzquiz_questions', ['jazzquizid' => $jazzquiz->id]);
- // Finally delete the jazzquiz object.
- $DB->delete_records('jazzquiz', ['id' => $jazzquiz->id]);
- } catch (Exception $e) {
- return false;
+ $jazzquiz = $DB->get_record('jazzquiz', ['id' => $id], '*', MUST_EXIST);
+ // Go through each session and then delete them (also deletes all attempts for them).
+ $sessions = $DB->get_records('jazzquiz_sessions', ['jazzquizid' => $jazzquiz->id]);
+ foreach ($sessions as $session) {
+ jazzquiz_session::delete($session->id);
}
+ $DB->delete_records('jazzquiz_questions', ['jazzquizid' => $jazzquiz->id]);
+ $DB->delete_records('jazzquiz', ['id' => $jazzquiz->id]);
return true;
}
/**
- * Function to be run periodically according to the moodle cron
- * This function searches for things that need to be done, such
- * as sending out mail, toggling flags etc ...
+ * Function to be run periodically according to the moodle cron.
*
- * @uses $CFG
- * @return boolean
- **/
-function jazzquiz_cron() {
+ * @return bool
+ */
+function jazzquiz_cron(): bool {
return true;
}
@@ -110,10 +93,9 @@ function jazzquiz_cron() {
* @param navigation_node $jazzquiznode
* @return void
*/
-function jazzquiz_extend_settings_navigation($settings, $jazzquiznode) {
+function jazzquiz_extend_settings_navigation(settings_navigation $settings, navigation_node $jazzquiznode): void {
global $PAGE, $CFG;
- // Require {@link questionlib.php}
// Included here as we only ever want to include this file if we really need to.
require_once($CFG->libdir . '/questionlib.php');
@@ -121,18 +103,18 @@ function jazzquiz_extend_settings_navigation($settings, $jazzquiznode) {
}
/**
- * @param \stdClass|int $course
- * @param \stdClass $cm
- * @param \context $context
+ * Plugin file callback for JazzQuiz.
+ *
+ * @param stdClass|int $course
+ * @param stdClass $cm
+ * @param context $context
* @param string $filearea
* @param array $args
* @param mixed $forcedownload
* @param array $options
* @return bool
- * @throws coding_exception
- * @throws dml_exception
*/
-function jazzquiz_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload, $options = []) {
+function jazzquiz_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload, $options = []): bool {
global $DB;
if ($context->contextlevel != CONTEXT_MODULE) {
return false;
@@ -149,7 +131,7 @@ function jazzquiz_pluginfile($course, $cm, $context, $filearea, $args, $forcedow
}
$question = $DB->get_record('jazzquiz_question', [
'id' => $questionid,
- 'quizid' => $cm->instance
+ 'quizid' => $cm->instance,
]);
if (!$question) {
return false;
@@ -157,7 +139,8 @@ function jazzquiz_pluginfile($course, $cm, $context, $filearea, $args, $forcedow
$fs = get_file_storage();
$relative = implode('/', $args);
$fullpath = "/$context->id/mod_jazzquiz/$filearea/$questionid/$relative";
- if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) {
+ $file = $fs->get_file_by_hash(sha1($fullpath));
+ if (!$file || $file->is_directory()) {
return false;
}
send_stored_file($file);
@@ -165,11 +148,10 @@ function jazzquiz_pluginfile($course, $cm, $context, $filearea, $args, $forcedow
}
/**
- * Called via pluginfile.php -> question_pluginfile to serve files belonging to
- * a question in a question_attempt when that attempt is a quiz attempt.
+ * Serve files belonging to a question in a question_attempt when that attempt is a quiz attempt.
+ *
+ * Called via pluginfile.php -> question_pluginfile.
*
- * @package mod_jazzquiz
- * @category files
* @param stdClass $course course settings object
* @param stdClass $context context object
* @param string $component the name of the component we are serving files for.
@@ -179,13 +161,16 @@ function jazzquiz_pluginfile($course, $cm, $context, $filearea, $args, $forcedow
* @param array $args the remaining bits of the file path.
* @param bool $forcedownload whether the user must be forced to download the file.
* @param array $options additional options affecting the file serving
+ * @package mod_jazzquiz
+ * @category files
*/
function mod_jazzquiz_question_pluginfile($course, $context, $component, $filearea, $qubaid, $slot,
- $args, $forcedownload, $options = []) {
+ $args, $forcedownload, $options = []): void {
$fs = get_file_storage();
$relative = implode('/', $args);
$full = "/$context->id/$component/$filearea/$relative";
- if (!$file = $fs->get_file_by_hash(sha1($full)) or $file->is_directory()) {
+ $file = $fs->get_file_by_hash(sha1($full));
+ if (!$file || $file->is_directory()) {
send_file_not_found();
}
send_stored_file($file, 0, 0, $forcedownload, $options);
@@ -193,17 +178,16 @@ function mod_jazzquiz_question_pluginfile($course, $context, $component, $filear
/**
* Check whether JazzQuiz supports a certain feature or not.
+ *
* @param string $feature
* @return bool
*/
-function jazzquiz_supports(string $feature) : bool {
- switch ($feature) {
- case FEATURE_MOD_INTRO:
- case FEATURE_BACKUP_MOODLE2:
- case FEATURE_SHOW_DESCRIPTION:
- case FEATURE_USES_QUESTIONS:
- return true;
- default:
- return false;
- }
+function jazzquiz_supports(string $feature): bool {
+ return match ($feature) {
+ FEATURE_MOD_INTRO,
+ FEATURE_BACKUP_MOODLE2,
+ FEATURE_SHOW_DESCRIPTION,
+ FEATURE_USES_QUESTIONS => true,
+ default => false,
+ };
}
diff --git a/locallib.php b/locallib.php
index 5913336..586f6bb 100755
--- a/locallib.php
+++ b/locallib.php
@@ -15,7 +15,7 @@
// along with Moodle. If not, see .
/**
- * Local lib
+ * Local lib.
*
* @package mod_jazzquiz
* @author John Hoopes
@@ -25,18 +25,16 @@
use mod_jazzquiz\jazzquiz;
-defined('MOODLE_INTERNAL') || die();
-
/**
+ * View tab.
+ *
* @param jazzquiz $jazzquiz
* @param int $id
* @param array $row
* @param string $capability
* @param string $name
- * @throws coding_exception
- * @throws moodle_exception
*/
-function jazzquiz_view_tab(jazzquiz $jazzquiz, int $id, array &$row, string $capability, string $name) {
+function jazzquiz_view_tab(jazzquiz $jazzquiz, int $id, array &$row, string $capability, string $name): void {
if (has_capability($capability, $jazzquiz->context)) {
$url = new moodle_url("/mod/jazzquiz/$name.php", ['id' => $id]);
$row[] = new tabobject($name, $url, get_string($name, 'jazzquiz'));
@@ -45,13 +43,12 @@ function jazzquiz_view_tab(jazzquiz $jazzquiz, int $id, array &$row, string $cap
/**
* Prints tabs for instructor.
+ *
* @param jazzquiz $jazzquiz
* @param string $tab
* @return string HTML string of the tabs
- * @throws coding_exception
- * @throws moodle_exception
*/
-function jazzquiz_view_tabs(jazzquiz $jazzquiz, string $tab) : string {
+function jazzquiz_view_tabs(jazzquiz $jazzquiz, string $tab): string {
$tabs = [];
$row = [];
$inactive = [];
diff --git a/mod_form.php b/mod_form.php
index 88d2f43..80e415f 100755
--- a/mod_form.php
+++ b/mod_form.php
@@ -15,7 +15,7 @@
// along with Moodle. If not, see .
/**
- * The main configuration form
+ * The main configuration form.
*
* @package mod_jazzquiz
* @author John Hoopes
@@ -28,9 +28,17 @@
require_once($CFG->dirroot . '/course/moodleform_mod.php');
+/**
+ * Module settings form.
+ */
class mod_jazzquiz_mod_form extends moodleform_mod {
- public function definition() {
+ /**
+ * Create form definition.
+ *
+ * @return void
+ */
+ public function definition(): void {
$mform =& $this->_form;
// Adding the "general" field set, where all the common settings are showed.
diff --git a/reports.php b/reports.php
index 79e25a2..a895397 100755
--- a/reports.php
+++ b/reports.php
@@ -15,9 +15,7 @@
// along with Moodle. If not, see .
/**
- * The reports page
- *
- * This handles displaying results
+ * The reports page.
*
* @package mod_jazzquiz
* @author Sebastian S. Gundersen
@@ -28,6 +26,8 @@
namespace mod_jazzquiz;
+use moodle_url;
+
require_once("../../config.php");
require_once($CFG->libdir . '/questionlib.php');
require_once($CFG->dirroot . '/mod/jazzquiz/locallib.php');
@@ -38,20 +38,17 @@
require_login();
/**
+ * View session report.
+ *
* @param jazzquiz $jazzquiz
- * @param \moodle_url $url
+ * @param moodle_url $url
* @param int $sessionid
- * @throws \coding_exception
- * @throws \dml_exception
- * @throws \moodle_exception
*/
-function jazzquiz_view_session_report(jazzquiz $jazzquiz, \moodle_url $url, int $sessionid) {
+function jazzquiz_view_session_report(jazzquiz $jazzquiz, moodle_url $url, int $sessionid): void {
+ global $DB;
if ($sessionid === 0) {
// If no session id is specified, we try to load the first one.
- global $DB;
- $sessions = $DB->get_records('jazzquiz_sessions', [
- 'jazzquizid' => $jazzquiz->data->id
- ]);
+ $sessions = $DB->get_records('jazzquiz_sessions', ['jazzquizid' => $jazzquiz->data->id]);
if (count($sessions) === 0) {
echo get_string('no_sessions_exist', 'jazzquiz');
return;
@@ -66,10 +63,11 @@ function jazzquiz_view_session_report(jazzquiz $jazzquiz, \moodle_url $url, int
}
/**
+ * Export session report.
+ *
* @param jazzquiz $jazzquiz
- * @throws \coding_exception
*/
-function jazzquiz_export_session_report(jazzquiz $jazzquiz) {
+function jazzquiz_export_session_report(jazzquiz $jazzquiz): void {
$what = required_param('what', PARAM_ALPHANUM);
$sessionid = required_param('sessionid', PARAM_INT);
$session = new jazzquiz_session($jazzquiz, $sessionid);
@@ -96,7 +94,13 @@ function jazzquiz_export_session_report(jazzquiz $jazzquiz) {
}
}
-function jazzquiz_delete_session_report(int $sessionid) {
+/**
+ * Delete a session report.
+ *
+ * @param int $sessionid
+ * @return void
+ */
+function jazzquiz_delete_session_report(int $sessionid): void {
if ($sessionid !== 0) {
jazzquiz_session::delete($sessionid);
}
@@ -105,20 +109,17 @@ function jazzquiz_delete_session_report(int $sessionid) {
/**
* Entry point for viewing reports.
*/
-function jazzquiz_reports() {
+function jazzquiz_reports(): void {
global $PAGE;
$cmid = optional_param('id', false, PARAM_INT);
if (!$cmid) {
- // Probably a login redirect that doesn't include any ID.
- // Go back to the main Moodle page, because we have no info.
- header('Location: /');
- exit;
+ redirect(new moodle_url('/'));
}
$jazzquiz = new jazzquiz($cmid);
require_capability('mod/jazzquiz:seeresponses', $jazzquiz->context);
$action = optional_param('action', '', PARAM_ALPHANUM);
- $url = new \moodle_url('/mod/jazzquiz/reports.php');
+ $url = new moodle_url('/mod/jazzquiz/reports.php');
$url->param('id', $cmid);
$url->param('quizid', $jazzquiz->data->id);
$url->param('action', $action);
@@ -136,7 +137,7 @@ function jazzquiz_reports() {
if (!$isdownload) {
$jazzquiz->renderer->header($jazzquiz, 'reports');
}
- $sessionid = optional_param('sessionid', 0, PARAM_INT);
+ $sessionid = optional_param('sessionid', 0, PARAM_INT);
switch ($action) {
case 'view':
jazzquiz_view_session_report($jazzquiz, $url, $sessionid);
diff --git a/styles.css b/styles.css
index ce2d008..12c94bb 100755
--- a/styles.css
+++ b/styles.css
@@ -5,23 +5,6 @@
padding: 20px;
}
-.jazzquiz-box .row {
- margin: 5px;
-}
-
-.jazzquiz-box .inline-block {
- display: inline-block;
-}
-
-.jazzquiz-box .span6 {
- vertical-align: top;
- width: 49.5%;
-}
-
-.jazzquiz-box .row .span6 {
- padding: 5px;
-}
-
.jazzquiz-save-question {
height: 30px;
}
@@ -345,44 +328,24 @@
margin-left: 16px;
}
-.jazzquiz-box .questionlist .dragquestion {
- width: 10%;
+.dragquestion {
cursor: move;
}
-.jazzquiz-box .questionlist .icon {
- vertical-align: middle;
- height: auto;
-}
-
-.jazzquiz-box .questionlist .name {
- width: calc(100% - 256px);
- vertical-align: middle;
-}
-
.jazzquiz-box .questionlist .name p {
margin: 0;
}
-.jazzquiz-box .questionlist .controls {
- width: 100%;
- vertical-align: middle;
-}
-
.jazzquiz-box .questionlist li {
- min-height: 30px;
margin: 4px;
padding: 10px;
border: 1px solid #ddd;
background: #eee;
}
-.jazzquiz-box .questionlist li div {
- display: inline-block;
-}
-
-.jazzquiz-box .questionlist li:hover {
- background: #ddd;
+.jazzquiz-box .questionlist .controls {
+ display: grid;
+ grid-template-columns: 32px 32px auto 32px 32px 32px 32px;
}
.jazzquiz-box .questionlist li a {
@@ -474,6 +437,6 @@
.start-question-menu .MathJax_Display,
.questionlist li .controls .name .MathJax_Display {
- text-align: left ;
- margin: 0 ;
+ text-align: left;
+ margin: 0;
}
diff --git a/templates/continue_session.mustache b/templates/continue_session.mustache
index ff98e84..437f2e4 100755
--- a/templates/continue_session.mustache
+++ b/templates/continue_session.mustache
@@ -1,15 +1,32 @@
{{!
- @template continue_session
+ This file is part of Moodle - http://moodle.org/
+
+ Moodle 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.
+
+ Moodle 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 Moodle. If not, see .
+}}
+{{!
+ @template mod_jazzquiz/continue_session
+
+ Link to continue session.
Example context (json):
{
- "str": "Continue session...",
- "path": "https://example.com/"
+ "path": "/mod/jazzquiz/view.php?id=1&quizid=1&action=quizstart"
}
}}
\ No newline at end of file
+
diff --git a/templates/edit_question_list.mustache b/templates/edit_question_list.mustache
index 3c6768d..a76d1d9 100755
--- a/templates/edit_question_list.mustache
+++ b/templates/edit_question_list.mustache
@@ -1,48 +1,84 @@
{{!
- @template edit_question_list
+ This file is part of Moodle - http://moodle.org/
+
+ Moodle 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.
+
+ Moodle 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 Moodle. If not, see .
}}
+{{!
+ @template mod_jazzquiz/edit_question_list
+
+ Edit the questions used for a quiz.
+
+ Example context (json):
+ {
+ "questions": [
+ {
+ "id": 713,
+ "name": "Example question",
+ "first": true,
+ "last": false,
+ "slot": 1,
+ "editurl": "/mod/jazzquiz/edit.php?questionid=713&action=editquestion",
+ "icon": ""
+ },
+ {
+ "id": 509,
+ "name": "Another question",
+ "first": false,
+ "last": true,
+ "slot": 2,
+ "editurl": "/mod/jazzquiz/edit.php?questionid=509&action=editquestion",
+ "icon": ""
+ }
+ ],
+ "qbank": ""
+ }
+}}
+
+
{{#str}}questions, jazzquiz{{/str}}
+
+ {{#questions}}
+ -
+
+
{{#pix}}i/dragdrop, core{{/pix}}
+
{{{icon}}}
+
+ {{{name}}}
+
+ {{#first}}{{#pix}}spacer, core{{/pix}}{{/first}}
+ {{^first}}
+
+ {{#pix}}t/up, core, {{#str}}question_move_up, jazzquiz, {{slot}}{{/str}}{{/pix}}
+
+ {{/first}}
+ {{#last}}{{#pix}}spacer, core{{/pix}}{{/last}}
+ {{^last}}
+
+ {{#pix}}t/down, core, {{#str}}question_move_down, jazzquiz, {{slot}}{{/str}}{{/pix}}
+
+ {{/last}}
+
{{#pix}} t/edit, core, {{#str}}edit_question, jazzquiz{{/str}}{{/pix}}
+
+ {{#pix}}t/delete, core, {{#str}}delete_question, jazzquiz, {{slot}}{{/str}}{{/pix}}
+
+
+
+ {{/questions}}
+
+
+
+
+
-
-
-
{{# str }} questions, jazzquiz {{/ str }}
-
- {{# questions }}
- -
-
-
- {{# pix }} i/dragdrop, core {{/ pix }}
-
-
- {{{ icon }}}
-
-
-
- {{{ name }}}
-
-
- {{# first }}{{# pix }} spacer, core {{/ pix }}{{/ first }}
- {{^ first }}
-
- {{# pix }} t/up, core, {{# str }} question_move_up, jazzquiz, {{ slot }} {{/ str }} {{/ pix }}
-
- {{/ first }}
- {{# last }}{{# pix }} spacer, core {{/ pix }}{{/ last }}
- {{^ last }}
-
- {{# pix }} t/down, core, {{# str }} question_move_down, jazzquiz, {{ slot }} {{/ str }} {{/ pix }}
-
- {{/ last }}
-
{{# pix }} t/edit, core, {{# str }} edit_question, jazzquiz {{/ str }} {{/ pix }}
-
- {{# pix }} t/delete, core, {{# str }} delete_question, jazzquiz, {{ slot }} {{/ str }} {{/ pix }}
-
-
-
- {{/ questions }}
-
-
-
- {{{ qbank }}}
-
-
-
\ No newline at end of file
+ {{{qbank}}}
+
diff --git a/templates/guests_not_allowed.mustache b/templates/guests_not_allowed.mustache
index 0110232..de93c38 100644
--- a/templates/guests_not_allowed.mustache
+++ b/templates/guests_not_allowed.mustache
@@ -1,8 +1,30 @@
{{!
- @template guests_not_allowed
+ This file is part of Moodle - http://moodle.org/
+
+ Moodle 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.
+
+ Moodle 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 Moodle. If not, see .
+}}
+{{!
+ @template mod_jazzquiz/guests_not_allowed
+
+ Guests are not allowed to access this quiz.
+
+ Example context (json):
+ {
+ }
}}
-
{{# str }} guest_login, jazzquiz {{/ str }}
-
{{# str }} no_guests, jazzquiz {{/ str }}
-
{{# str }} ask_teacher, jazzquiz {{/ str }}
+
{{#str}}guest_login, jazzquiz{{/str}}
+
{{#str}}no_guests, jazzquiz{{/str}}
+
{{#str}}ask_teacher, jazzquiz{{/str}}
diff --git a/templates/join_session.mustache b/templates/join_session.mustache
index 1d747c7..5023fd8 100755
--- a/templates/join_session.mustache
+++ b/templates/join_session.mustache
@@ -1,14 +1,36 @@
{{!
- @template join_session
+ This file is part of Moodle - http://moodle.org/
+
+ Moodle 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.
+
+ Moodle 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 Moodle. If not, see .
+}}
+{{!
+ @template mod_jazzquiz/join_session
+
+ Show button to enter an ongoing JazzQuiz session.
+
+ Example context (json):
+ {
+ "name": "Example questions",
+ "anonymity_info": "Guests are allowed",
+ "started": true,
+ "form": ""
+ }
}}
-
{{# str }} join_quiz_instructions, jazzquiz {{/ str }}
-
- {{# str }} session, jazzquiz {{/ str }}: {{ name }}
-
-
{{ anonymity_info }}
- {{# started }}
-
{{# str }} attempt_started, jazzquiz {{/ str }}
- {{/ started }}
- {{{ form }}}
-
\ No newline at end of file
+ {{#str}}join_quiz_instructions, jazzquiz{{/str}}
+ {{#str}}session, jazzquiz{{/str}}: {{name}}
+ {{anonymity_info}}
+ {{#started}}{{#str}}attempt_started, jazzquiz{{/str}}
{{/started}}
+ {{{form}}}
+
diff --git a/templates/no_session.mustache b/templates/no_session.mustache
index 3bb497f..da808c4 100755
--- a/templates/no_session.mustache
+++ b/templates/no_session.mustache
@@ -1,9 +1,32 @@
{{!
- @template no_session
+ This file is part of Moodle - http://moodle.org/
+
+ Moodle 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.
+
+ Moodle 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 Moodle. If not, see .
+}}
+{{!
+ @template mod_jazzquiz/no_session
+
+ There is no session ongoing. Display a button to refresh the page to check again.
+
+ Example context (json):
+ {
+ "reload": "/mod/jazzquiz/view.php?id=1"
+ }
}}
\ No newline at end of file
+
diff --git a/templates/question.mustache b/templates/question.mustache
index 9a16d63..08f7c1a 100755
--- a/templates/question.mustache
+++ b/templates/question.mustache
@@ -1,16 +1,41 @@
{{!
- @template question
+ This file is part of Moodle - http://moodle.org/
+
+ Moodle 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.
+
+ Moodle 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 Moodle. If not, see .
}}
-
diff --git a/templates/quiz.mustache b/templates/quiz.mustache
index 2ff9728..e1e4d84 100755
--- a/templates/quiz.mustache
+++ b/templates/quiz.mustache
@@ -1,25 +1,57 @@
{{!
- @template quiz
+ This file is part of Moodle - http://moodle.org/
+
+ Moodle 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.
+
+ Moodle 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 Moodle. If not, see .
+}}
+{{!
+ @template mod_jazzquiz/quiz
+
+ Main wrapper for a JazzQuiz session.
+
+ Example context (json):
+ {
+ "instructor": true,
+ "buttons": [
+ {
+ "id": "improvise",
+ "icon": "edit",
+ "text": "Improvise"
+ }
+ ]
+ }
}}
- {{# instructor }}
+ {{#instructor}}
@@ -37,18 +69,18 @@
- {{/ instructor }}
- {{^ instructor }}
+ {{/instructor}}
+ {{^instructor}}
- {{/ instructor }}
+ {{/instructor}}
- {{# instructor }}
+ {{#instructor}}
- {{/ instructor }}
-
\ No newline at end of file
+ {{/instructor}}
+
diff --git a/templates/report.mustache b/templates/report.mustache
index 7b59063..2cbb5b0 100755
--- a/templates/report.mustache
+++ b/templates/report.mustache
@@ -1,73 +1,154 @@
{{!
- @template report
+ This file is part of Moodle - http://moodle.org/
+
+ Moodle 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.
+
+ Moodle 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 Moodle. If not, see .
+}}
+{{!
+ @template mod_jazzquiz/report
+
+ Reports for JazzQuiz sessions.
+
+ Example context (json):
+ {
+ "select_session": {
+ "method": "get",
+ "action": "/mod/jazzquiz/reports.php",
+ "formid": "jazzquiz_select_session_form",
+ "id": "jazzquiz_select_session",
+ "name": "sessionid",
+ "options": [
+ {
+ "name": "First session",
+ "value": 1,
+ "selected": true,
+ "optgroup": false
+ }
+ ],
+ "params": [
+ {
+ "name": "id",
+ "value": 1
+ },
+ {
+ "name": "action",
+ "value": "view"
+ }
+ ]
+ },
+ "session": {
+ "slots": [
+ {
+ "num": 1,
+ "name": "Example question",
+ "type": "multichoice",
+ "description": "Description for this question",
+ "responses": [
+ {
+ "response": "42"
+ },
+ {
+ "response": "I don't know"
+ }
+ ]
+ }
+ ],
+ "students": [
+ {
+ "idnumber": 1,
+ "name": "Student",
+ "count": 1
+ },
+ {
+ "name": "Guest",
+ "count": 1
+ }
+ ],
+ "count_total": 2,
+ "count_answered": 2,
+ "cmid": 1,
+ "quizid": 1,
+ "id": 1
+ }
+ }
}}
- {{# select_session }}
+ {{#select_session}}
-
{{# str }} select_session, jazzquiz {{/ str }}
+
{{#str}}select_session, jazzquiz{{/str}}
- {{> core/single_select }}
+ {{>core/single_select}}
- {{/ select_session }}
- {{# session }}
+ {{/select_session}}
+ {{#session}}
- {{# slots }}
+ {{#slots}}
- {{/ slots }}
+ {{/slots}}
-
{{# str }} attendance_list, jazzquiz {{/str}}
+
{{#str}}attendance_list, jazzquiz{{/str}}
- Student ID |
- {{# str }} student, jazzquiz {{/str}} |
- {{# str }} responses, jazzquiz {{/ str }} |
+ Student ID |
+ {{#str}}student, jazzquiz{{/str}} |
+ {{#str}}responses, jazzquiz{{/str}} |
- {{# students }}
+ {{#students}}
- {{ idnumber }} |
- {{ name }} |
- {{# str }} a_responses, jazzquiz, {{ count }} {{/ str }} |
+ {{idnumber}} |
+ {{name}} |
+ {{#str}}a_responses, jazzquiz, {{count}}{{/str}} |
- {{/ students }}
+ {{/students}}
-
{{# str }} a_students_joined_quiz, jazzquiz, {{ count_total }} {{/ str }}
-
{{# str }} a_students_answered, jazzquiz, {{ count_answered }} {{/ str }}
+
{{#str}}a_students_joined_quiz, jazzquiz, {{count_total}}{{/str}}
+
{{#str}}a_students_answered, jazzquiz, {{count_answered}}{{/str}}
-
- {{# str }} download_attendance_list, jazzquiz {{/ str }}
+
+ {{#str}}download_attendance_list, jazzquiz{{/str}}
- {{/ session }}
+ {{/session}}
diff --git a/templates/start_session.mustache b/templates/start_session.mustache
index 2f03678..2a992f2 100755
--- a/templates/start_session.mustache
+++ b/templates/start_session.mustache
@@ -1,8 +1,31 @@
{{!
- @template start_session
+ This file is part of Moodle - http://moodle.org/
+
+ Moodle 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.
+
+ Moodle 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 Moodle. If not, see .
+}}
+{{!
+ @template mod_jazzquiz/start_session
+
+ Show form to start a new session.
+
+ Example context (json):
+ {
+ "form": ""
+ }
}}
-
{{# str }} teacher_start_instructions, jazzquiz {{/ str }}
+
{{#str}}teacher_start_instructions, jazzquiz{{/str}}
- {{{ form }}}
-
\ No newline at end of file
+ {{{form}}}
+
diff --git a/version.php b/version.php
index 28e96bb..60588eb 100755
--- a/version.php
+++ b/version.php
@@ -15,6 +15,8 @@
// along with Moodle. If not, see .
/**
+ * JazzQuiz version information.
+ *
* @package mod_jazzquiz
* @author Sebastian S. Gundersen
* @author André Storhaug
diff --git a/view.php b/view.php
index a14822b..6f39778 100755
--- a/view.php
+++ b/view.php
@@ -25,7 +25,9 @@
*/
namespace mod_jazzquiz;
-use Exception;
+
+use moodle_url;
+use required_capability_exception;
require_once("../../config.php");
require_once($CFG->dirroot . '/mod/jazzquiz/lib.php');
@@ -37,11 +39,10 @@
/**
* View the quiz page.
+ *
* @param jazzquiz $jazzquiz
- * @throws \dml_exception
- * @throws \moodle_exception
*/
-function jazzquiz_view_start_quiz(jazzquiz $jazzquiz) {
+function jazzquiz_view_start_quiz(jazzquiz $jazzquiz): void {
global $PAGE;
// Set the quiz view page to the base layout for 1 column layout.
$PAGE->set_pagelayout('base');
@@ -55,11 +56,11 @@ function jazzquiz_view_start_quiz(jazzquiz $jazzquiz) {
$session->load_attempts();
$session->initialize_attempt();
if ($jazzquiz->is_instructor()) {
- $session->attempt->data->status = jazzquiz_attempt::PREVIEW;
+ $session->myattempt->status = jazzquiz_attempt::PREVIEW;
} else {
- $session->attempt->data->status = jazzquiz_attempt::INPROGRESS;
+ $session->myattempt->status = jazzquiz_attempt::INPROGRESS;
}
- $session->attempt->save();
+ $session->myattempt->save();
// Initialize JavaScript for the question engine.
// TODO: Not certain if this is needed. Should be checked further.
@@ -73,35 +74,23 @@ function jazzquiz_view_start_quiz(jazzquiz $jazzquiz) {
/**
* View the "Continue session" or "Start session" form.
+ *
* @param jazzquiz $jazzquiz
- * @throws \dml_exception
- * @throws \moodle_exception
*/
-function jazzquiz_view_default_instructor(jazzquiz $jazzquiz) {
- global $PAGE, $DB;
+function jazzquiz_view_default_instructor(jazzquiz $jazzquiz): void {
+ global $PAGE;
$startsessionform = new forms\view\start_session($PAGE->url, ['jazzquiz' => $jazzquiz]);
$data = $startsessionform->get_data();
if ($data) {
- $sessions = $DB->get_records('jazzquiz_sessions', [
- 'jazzquizid' => $jazzquiz->data->id,
- 'sessionopen' => 1
- ]);
- // Only create session if not already open.
- if (empty($sessions)) {
- $allowguests = isset($data->allowguests) ? 1 : 0;
- $sessionid = $jazzquiz->create_session($data->session_name, $data->anonymity, $allowguests);
- if ($sessionid === false) {
- return;
- }
- } else {
+ if ($jazzquiz->is_session_open()) {
redirect($PAGE->url, 'A session is already open.', 0);
- // Note: Redirect exits.
+ } else {
+ $jazzquiz->create_session($data->session_name, $data->anonymity, isset($data->allowguests));
}
// Redirect to the quiz start.
$quizstarturl = clone($PAGE->url);
$quizstarturl->param('action', 'quizstart');
redirect($quizstarturl, null, 0);
- // Note: Redirect exits.
}
$renderer = $jazzquiz->renderer;
$renderer->header($jazzquiz, 'view');
@@ -115,10 +104,10 @@ function jazzquiz_view_default_instructor(jazzquiz $jazzquiz) {
/**
* View the "Join quiz" or "Quiz not running" form.
+ *
* @param jazzquiz $jazzquiz
- * @throws \moodle_exception
*/
-function jazzquiz_view_default_student(jazzquiz $jazzquiz) {
+function jazzquiz_view_default_student(jazzquiz $jazzquiz): void {
global $PAGE;
$studentstartform = new forms\view\student_start_form($PAGE->url);
$data = $studentstartform->get_data();
@@ -126,7 +115,6 @@ function jazzquiz_view_default_student(jazzquiz $jazzquiz) {
$quizstarturl = clone($PAGE->url);
$quizstarturl->param('action', 'quizstart');
redirect($quizstarturl, null, 0);
- // Note: Redirect exits.
}
/** @var output\renderer $renderer */
@@ -143,11 +131,10 @@ function jazzquiz_view_default_student(jazzquiz $jazzquiz) {
/**
* View appropriate form based on role and session state.
+ *
* @param jazzquiz $jazzquiz
- * @throws \dml_exception
- * @throws \moodle_exception
*/
-function jazzquiz_view_default(jazzquiz $jazzquiz) {
+function jazzquiz_view_default(jazzquiz $jazzquiz): void {
if ($jazzquiz->is_instructor()) {
// Show "Start quiz" form.
jazzquiz_view_default_instructor($jazzquiz);
@@ -157,18 +144,14 @@ function jazzquiz_view_default(jazzquiz $jazzquiz) {
}
}
-
/**
* Entry point for viewing a quiz.
*/
-function jazzquiz_view() {
+function jazzquiz_view(): void {
global $PAGE;
- $cmid = optional_param('id', false, PARAM_INT);
- if (!$cmid) {
- // Probably a login redirect that doesn't include any ID.
- // Go back to the main Moodle page, because we have no info.
- header('Location: /');
- exit;
+ $cmid = optional_param('id', 0, PARAM_INT);
+ if ($cmid === 0) {
+ redirect(new moodle_url('/'));
}
$action = optional_param('action', '', PARAM_ALPHANUM);
@@ -177,14 +160,12 @@ function jazzquiz_view() {
$iscapable = true;
/*
- * Checks that the user is authorised for he quiz.
- * access or not.
+ * Checks that the user is authorised for the quiz access or not.
* The require_capability() method checks this for students
* and teacher, but it cannot handle the case where guest
- * access is allowed. Hence, if guests are allowed, no
- * further check is made.
+ * access is allowed. Hence, if guests are allowed, no further check is made.
*/
- if (!$session || $session->data->allowguests != 1) {
+ if ($session === null || $session->data->allowguests != 1) {
try {
/*
* require_capability() throws an exception if the user does not
@@ -192,7 +173,7 @@ function jazzquiz_view() {
* or teacher is not enrolled on the course.
*/
require_capability('mod/jazzquiz:attempt', $jazzquiz->context);
- } catch (Exception $e) {
+ } catch (required_capability_exception) {
// Indicates that the guest user is not allowed to access this session.
$iscapable = false;
}
@@ -202,10 +183,10 @@ function jazzquiz_view() {
$PAGE->set_context($jazzquiz->context);
$PAGE->set_cm($jazzquiz->cm);
$modname = get_string('modulename', 'jazzquiz');
- $quizname = format_string($jazzquiz->data->name, true);
+ $quizname = format_string($jazzquiz->data->name);
$PAGE->set_title(strip_tags($jazzquiz->course->shortname . ': ' . $modname . ': ' . $quizname));
$PAGE->set_heading($jazzquiz->course->fullname);
- $url = new \moodle_url('/mod/jazzquiz/view.php');
+ $url = new moodle_url('/mod/jazzquiz/view.php');
$url->param('id', $cmid);
$url->param('quizid', $jazzquiz->data->id);
$url->param('action', $action);