diff --git a/backup/moodle2/backup_moodleoverflow_stepslib.php b/backup/moodle2/backup_moodleoverflow_stepslib.php index 8c803d438c..aa56787799 100644 --- a/backup/moodle2/backup_moodleoverflow_stepslib.php +++ b/backup/moodle2/backup_moodleoverflow_stepslib.php @@ -39,16 +39,14 @@ class backup_moodleoverflow_activity_structure_step extends backup_activity_stru * @return backup_nested_element */ protected function define_structure() { - // To know if we are including userinfo. $userinfo = $this->get_setting_value('userinfo'); // Define the root element describing the moodleoverflow instance. $moodleoverflow = new backup_nested_element('moodleoverflow', ['id'], [ - 'name', 'intro', 'introformat', 'maxbytes', 'maxattachments', 'timecreated', 'timemodified', - 'forcesubscribe', 'trackingtype', 'ratingpreference', 'coursewidereputation', 'allowrating', - 'allowreputation', 'allownegativereputation', 'grademaxgrade', 'gradescalefactor', 'gradecat', - 'anonymous', 'allowmultiplemarks', ]); + 'name', 'intro', 'introformat', 'maxbytes', 'maxattachments', 'timecreated', 'timemodified', 'forcesubscribe', + 'trackingtype', 'ratingpreference', 'coursewidereputation', 'allowrating', 'allowreputation', 'allownegativereputation', + 'grademaxgrade', 'gradescalefactor', 'gradecat', 'anonymous', 'allowmultiplemarks', ]); // Define each element separated. $discussions = new backup_nested_element('discussions'); @@ -56,24 +54,20 @@ protected function define_structure() { 'name', 'firstpost', 'userid', 'timestart', 'timemodified', 'usermodified', ]); $posts = new backup_nested_element('posts'); - $post = new backup_nested_element('post', ['id'], [ - 'parent', 'userid', 'created', 'modified', - 'message', 'messageformat', 'attachment', 'mailed', 'reviewed', 'timereviewed', ]); + $post = new backup_nested_element('post', ['id'], ['parent', 'userid', 'created', 'modified', 'message', + 'messageformat', 'attachment', 'mailed', 'reviewed', 'timereviewed', ]); $ratings = new backup_nested_element('ratings'); - $rating = new backup_nested_element('rating', ['id'], [ - 'userid', 'rating', 'firstrated', 'lastchanged', ]); + $rating = new backup_nested_element('rating', ['id'], ['userid', 'rating', 'firstrated', 'lastchanged']); $discussionsubs = new backup_nested_element('discuss_subs'); - $discussionsub = new backup_nested_element('discuss_sub', ['id'], [ - 'userid', 'preference', ]); + $discussionsub = new backup_nested_element('discuss_sub', ['id'], ['userid', 'preference']); $subscriptions = new backup_nested_element('subscriptions'); $subscription = new backup_nested_element('subscription', ['id'], ['userid']); $readposts = new backup_nested_element('readposts'); - $read = new backup_nested_element('read', ['id'], [ - 'userid', 'discussionid', 'postid', 'firstread', 'lastread', ]); + $read = new backup_nested_element('read', ['id'], ['userid', 'discussionid', 'postid', 'firstread', 'lastread']); $grades = new backup_nested_element('grades'); $grade = new backup_nested_element('grade', ['id'], ['userid', 'grade']); @@ -100,6 +94,9 @@ protected function define_structure() { $moodleoverflow->add_child($readposts); $readposts->add_child($read); + $moodleoverflow->add_child($grades); + $grades->add_child($grade); + $moodleoverflow->add_child($tracking); $tracking->add_child($track); diff --git a/classes/manager/mail_manager.php b/classes/manager/mail_manager.php index 9fc7118b0a..e822a01719 100644 --- a/classes/manager/mail_manager.php +++ b/classes/manager/mail_manager.php @@ -65,7 +65,7 @@ class mail_manager { * @return bool */ public static function moodleoverflow_send_mails(): bool { - global $DB, $CFG, $PAGE; + global $CFG, $DB, $PAGE; // Get the course object of the top level site. $site = get_site(); @@ -86,10 +86,8 @@ public static function moodleoverflow_send_mails(): bool { $moodleoverflows = []; $courses = []; $coursemodules = []; - $subscribedusers = []; - // Posts older than x days will not be mailed. - // This will avoid problems with the cron not ran for a long time. + // Posts older than x days will not be mailed. This will avoid problems with the cron not ran for a long time. $timenow = time(); $endtime = $timenow - get_config('moodleoverflow', 'maxeditingtime'); $starttime = $endtime - (get_config('moodleoverflow', 'maxmailingtime') * 60 * 60); @@ -102,7 +100,6 @@ public static function moodleoverflow_send_mails(): bool { mtrace('Errors occurred while trying to mark some posts as being mailed.'); return false; } - // Loop through all posts to be mailed. foreach ($posts as $postid => $post) { self::check_post($post, $mailcount, $users, $discussions, $errorcount, $posts, $postid, @@ -126,10 +123,10 @@ public static function moodleoverflow_send_mails(): bool { $userto->markposts = []; // Cache the capabilities of the user. - cron_setup_user($userto); + $CFG->branch >= 402 ? \core\cron::setup_user($userto) : cron_setup_user($userto); // Reset the caches. - foreach ($coursemodules as $moodleoverflowid => $unused) { + foreach ($coursemodules as $moodleoverflowid) { $coursemodules[$moodleoverflowid]->cache = new stdClass(); $coursemodules[$moodleoverflowid]->cache->caps = []; unset($coursemodules[$moodleoverflowid]->uservisible); @@ -137,7 +134,6 @@ public static function moodleoverflow_send_mails(): bool { // Loop through all posts of this users. foreach ($posts as $post) { - self::send_post($userto, $post, $coursemodules, $errorcount, $discussions, $moodleoverflows, $courses, $mailcount, $users, $site, $textout, $htmlout); } @@ -148,18 +144,13 @@ public static function moodleoverflow_send_mails(): bool { } // Check for all posts whether errors occurred. - if ($posts) { - - // Loop through all posts. - foreach ($posts as $post) { - - // Tracing information. - mtrace($mailcount[$post->id] . " users were sent post $post->id"); + foreach ($posts as $post) { + // Tracing information. + mtrace($mailcount[$post->id] . " users were sent post $post->id"); - // Mark the posts with errors in the database. - if ($errorcount[$post->id]) { - $DB->set_field('moodleoverflow_posts', 'mailed', self::MOODLEOVERFLOW_MAILED_ERROR, ['id' => $post->id]); - } + // Mark the posts with errors in the database. + if ($errorcount[$post->id]) { + $DB->set_field('moodleoverflow_posts', 'mailed', self::MOODLEOVERFLOW_MAILED_ERROR, ['id' => $post->id]); } } @@ -232,7 +223,6 @@ public static function moodleoverflow_mark_old_posts_as_mailed($endtime) { * @param stdClass $user */ public static function moodleoverflow_minimise_user_record(stdClass $user) { - // Remove all information for the mail generation that are not needed. unset($user->institution); unset($user->department); @@ -268,61 +258,31 @@ public static function moodleoverflow_minimise_user_record(stdClass $user) { private static function check_post($post, array &$mailcount, array &$users, array &$discussions, array &$errorcount, array &$posts, int $postid, array &$moodleoverflows, array &$courses, array &$coursemodules) { - global $DB; // Check the cache if the discussion exists. $discussionid = $post->discussion; - if (!isset($discussions[$discussionid])) { - // Retrieve the discussion from the database. - $discussion = $DB->get_record('moodleoverflow_discussions', ['id' => $post->discussion]); - - // If there is a record, update the cache. Else ignore the post. - if ($discussion) { - $discussions[$discussionid] = $discussion; - subscriptions::fill_subscription_cache($discussion->moodleoverflow); - subscriptions::fill_discussion_subscription_cache($discussion->moodleoverflow); - } else { - mtrace('Could not find discussion ' . $discussionid); - unset($posts[$postid]); - return; - } + if (!self::cache_record('moodleoverflow_discussions', $discussionid, $discussions, + 'Could not find discussion ', $posts, $postid, true)) { + return; } // Retrieve the connected moodleoverflow instance from the database. $moodleoverflowid = $discussions[$discussionid]->moodleoverflow; - if (!isset($moodleoverflows[$moodleoverflowid])) { - - // Retrieve the record from the database and update the cache. - $moodleoverflow = $DB->get_record('moodleoverflow', ['id' => $moodleoverflowid]); - if ($moodleoverflow) { - $moodleoverflows[$moodleoverflowid] = $moodleoverflow; - } else { - mtrace('Could not find moodleoverflow ' . $moodleoverflowid); - unset($posts[$postid]); - return; - } + if (!self::cache_record('moodleoverflow', $moodleoverflowid, $moodleoverflows, + 'Could not find moodleoverflow ', $posts, $postid, false)) { + return; } // Retrieve the connected courses from the database. $courseid = $moodleoverflows[$moodleoverflowid]->course; - if (!isset($courses[$courseid])) { - - // Retrieve the record from the database and update the cache. - $course = $DB->get_record('course', ['id' => $courseid]); - if ($course) { - $courses[$courseid] = $course; - } else { - mtrace('Could not find course ' . $courseid); - unset($posts[$postid]); - return; - } + if (!self::cache_record('course', $courseid, $courses, + 'Could not find course ', $posts, $postid, false)) { + return; } // Retrieve the connected course modules from the database. if (!isset($coursemodules[$moodleoverflowid])) { - // Retrieve the coursemodule and update the cache. - $cm = get_coursemodule_from_instance('moodleoverflow', $moodleoverflowid, $courseid); - if ($cm) { + if ($cm = get_coursemodule_from_instance('moodleoverflow', $moodleoverflowid, $courseid)) { $coursemodules[$moodleoverflowid] = $cm; } else { mtrace('Could not find course module for moodleoverflow ' . $moodleoverflowid); @@ -333,14 +293,12 @@ private static function check_post($post, array &$mailcount, array &$users, arra // Cache subscribed users of each moodleoverflow. if (!isset($subscribedusers[$moodleoverflowid])) { - // Retrieve the context module. $modulecontext = context_module::instance($coursemodules[$moodleoverflowid]->id); // Retrieve all subscribed users. $mid = $moodleoverflows[$moodleoverflowid]; - $subusers = subscriptions::get_subscribed_users($mid, $modulecontext, 'u.*', true); - if ($subusers) { + if ($subusers = subscriptions::get_subscribed_users($mid, $modulecontext, 'u.*', true)) { // Loop through all subscribed users. foreach ($subusers as $postuser) { // Save the user into the cache. @@ -361,6 +319,39 @@ private static function check_post($post, array &$mailcount, array &$users, arra $errorcount[$postid] = 0; } + /** + * Helper function for check_post(). Caches the a record exists in the database and caches the record if needed. + * @param string $table + * @param int $id + * @param array $cache + * @param string $errorMessage + * @param array $posts + * @param int $postid + * @param bool $fillsubscache If the subscription cache is being filled (only when checking discussion cache) + * @return bool + * @throws \dml_exception + */ + private static function cache_record($table, $id, &$cache, $errormessage, &$posts, $postid, $fillsubscache) { + global $DB; + // Check if cache if an record exists already in the cache. + if (!isset($cache[$id])) { + // If there is a record in the database, update the cache. Else ignore the post. + if ($record = $DB->get_record($table, ['id' => $id])) { + $cache[$id] = $record; + if ($fillsubscache) { + subscriptions::fill_subscription_cache($record->moodleoverflow); + subscriptions::fill_discussion_subscription_cache($record->moodleoverflow); + } + } else { + mtrace($errormessage . $id); + unset($posts[$postid]); + return false; + } + } + return true; + } + + /** * Send the Mail with information of the post depending on theinformation available. * E.g. anonymous post do not include names, users who want resumes do not get single mails. @@ -427,11 +418,8 @@ private static function send_post($userto, $post, array &$coursemodules, array & } // Check whether the user is subscribed to the discussion. - $iscm = $coursemodules[$moodleoverflow->id]; $uid = $userto->id; - $did = $post->discussion; - $issubscribed = subscriptions::is_subscribed($uid, $moodleoverflow, $modulecontext, $did); - if (!$issubscribed) { + if (!subscriptions::is_subscribed($uid, $moodleoverflow, $modulecontext, $post->discussion)) { return; } @@ -464,7 +452,7 @@ private static function send_post($userto, $post, array &$coursemodules, array & } // Setup roles and languages. - cron_setup_user($userto, $course); + $CFG->branch >= 402 ? \core\cron::setup_user($userto, $course) : cron_setup_user($userto, $course); // Cache the users capability to view full names. if (!isset($userto->viewfullnames[$moodleoverflow->id])) { @@ -522,16 +510,7 @@ private static function send_post($userto, $post, array &$coursemodules, array & } // Format the data. - $data = new moodleoverflow_email( - $course, - $cm, - $moodleoverflow, - $discussion, - $post, - $userfrom, - $userto, - $canreply - ); + $data = new moodleoverflow_email($course, $cm, $moodleoverflow, $discussion, $post, $userfrom, $userto, $canreply); // Retrieve the unsubscribe-link. $userfrom->customheaders[] = sprintf('List-Unsubscribe: <%s>', $data->get_unsubscribediscussionlink()); @@ -557,7 +536,6 @@ private static function send_post($userto, $post, array &$coursemodules, array & // Check whether the post is a reply. if ($post->parent) { - // Add a reply header. $parentid = generate_email_messageid(hash('sha256', $post->parent . 'to' . $userto->id)); $userfrom->customheaders[] = "In-Reply-To: $parentid"; diff --git a/classes/ratings.php b/classes/ratings.php index 8756545d21..f664aa735d 100644 --- a/classes/ratings.php +++ b/classes/ratings.php @@ -42,40 +42,29 @@ class ratings { * @param int $postid * @param int $rating * @param object $cm - * @param null $userid + * @param int $userid * * @return bool|int */ - public static function moodleoverflow_add_rating($moodleoverflow, $postid, $rating, $cm, $userid = null) { - global $DB, $USER, $SESSION; - - // Has a user been submitted? - if (!isset($userid)) { - $userid = $USER->id; - } + public static function moodleoverflow_add_rating($moodleoverflow, $postid, $rating, $cm, $userid) { + global $DB; // Is the submitted rating valid? $possibleratings = [RATING_NEUTRAL, RATING_DOWNVOTE, RATING_UPVOTE, RATING_SOLVED, RATING_HELPFUL, RATING_REMOVE_DOWNVOTE, RATING_REMOVE_UPVOTE, RATING_REMOVE_SOLVED, RATING_REMOVE_HELPFUL, ]; - if (!in_array($rating, $possibleratings)) { - throw new moodle_exception('invalidratingid', 'moodleoverflow'); - } + moodleoverflow_throw_exception_with_check(!in_array($rating, $possibleratings), 'invalidratingid'); - // Get the related discussion. - if (!$post = $DB->get_record('moodleoverflow_posts', ['id' => $postid])) { - throw new moodle_exception('invalidparentpostid', 'moodleoverflow'); - } + // Get the related post. + $post = moodleoverflow_get_record_or_exception('moodleoverflow_posts', ['id' => $postid], 'invalidparentpostid'); // Check if the post belongs to a discussion. - if (!$discussion = $DB->get_record('moodleoverflow_discussions', ['id' => $post->discussion])) { - throw new moodle_exception('notpartofdiscussion', 'moodleoverflow'); - } + $discussion = moodleoverflow_get_record_or_exception('moodleoverflow_discussions', ['id' => $post->discussion], + 'notpartofdiscussion'); // Get the related course. - if (!$course = $DB->get_record('course', ['id' => $moodleoverflow->course])) { - throw new moodle_exception('invalidcourseid'); - } + $course = moodleoverflow_get_record_or_exception('course', ['id' => $moodleoverflow->course], + 'invalidcourseid', '*', true); // Are multiple marks allowed? $markssetting = $DB->get_record('moodleoverflow', ['id' => $moodleoverflow->id], 'allowmultiplemarks'); @@ -86,39 +75,25 @@ public static function moodleoverflow_add_rating($moodleoverflow, $postid, $rati $coursecontext = \context_course::instance($course->id); // Redirect the user if capabilities are missing. - $canrate = self::moodleoverflow_user_can_rate($post, $modulecontext, $userid); - if (!$canrate) { + if (!self::moodleoverflow_user_can_rate($post, $modulecontext, $userid)) { // Catch unenrolled users. - if (!isguestuser() && !is_enrolled($coursecontext)) { - $SESSION->wantsurl = qualified_me(); - $SESSION->enrolcancel = get_local_referer(false); - redirect(new \moodle_url('/enrol/index.php', [ - 'id' => $course->id, - 'returnurl' => '/mod/moodleoverflow/view.php?m' . $moodleoverflow->id, - ]), get_string('youneedtoenrol')); - } + $returnurl = '/mod/moodleoverflow/view.php?m' . $moodleoverflow->id; + moodleoverflow_catch_unenrolled_user($coursecontext, $course->id, $returnurl); // Notify the user, that he can not post a new discussion. throw new moodle_exception('noratemoodleoverflow', 'moodleoverflow'); } // Make sure post author != current user, unless they have permission. - if (($post->userid == $userid) && ! - (($rating == RATING_SOLVED || $rating == RATING_REMOVE_SOLVED) && - has_capability('mod/moodleoverflow:marksolved', $modulecontext)) - ) { - throw new moodle_exception('rateownpost', 'moodleoverflow'); - } + $authorcheck = ($post->userid == $userid) && !(($rating == RATING_SOLVED || $rating == RATING_REMOVE_SOLVED) && + has_capability('mod/moodleoverflow:marksolved', $modulecontext)); + moodleoverflow_throw_exception_with_check($authorcheck, 'rateownpost'); // Check if we are removing a mark. if (in_array($rating / 10, $possibleratings)) { - - if (!get_config('moodleoverflow', 'allowratingchange')) { - throw new moodle_exception('noratingchangeallowed', 'moodleoverflow'); - - return false; - } + moodleoverflow_get_config_or_exception('moodleoverflow', 'allowratingchange', + 'noratingchangeallowed', 'moodleoverflow'); // Delete the rating. return self::moodleoverflow_remove_rating($postid, $rating / 10, $userid, $modulecontext); @@ -129,16 +104,13 @@ public static function moodleoverflow_add_rating($moodleoverflow, $postid, $rati // Mark a post as solution or as helpful. if ($rating == RATING_SOLVED || $rating == RATING_HELPFUL) { + // Make sure that a helpful mark is made by the user who started the discussion. + $isnotstartuser = $rating == RATING_HELPFUL && $userid != $discussion->userid; + moodleoverflow_throw_exception_with_check($isnotstartuser, 'nostartuser'); - // Check if the current user is the startuser. - if ($rating == RATING_HELPFUL && $userid != $discussion->userid) { - throw new moodle_exception('notstartuser', 'moodleoverflow'); - } - - // Check if the current user is a teacher. - if ($rating == RATING_SOLVED && !has_capability('mod/moodleoverflow:marksolved', $modulecontext)) { - throw new moodle_exception('notteacher', 'moodleoverflow'); - } + // Make sure that a solution mark is made by a teacher (or someone with the right capability). + $isnotteacher = $rating == RATING_SOLVED && !has_capability('mod/moodleoverflow:marksolved', $modulecontext); + moodleoverflow_throw_exception_with_check($isnotteacher, 'notteacher'); // Check if multiple marks are not enabled. if (!$multiplemarks) { @@ -154,27 +126,20 @@ public static function moodleoverflow_add_rating($moodleoverflow, $postid, $rati return self::moodleoverflow_update_rating_record($post->id, $rating, $userid, $otherrating->id, $modulecontext); } else { - $mid = $moodleoverflow->id; - - return self::moodleoverflow_add_rating_record($mid, $discussion->id, $post->id, + return self::moodleoverflow_add_rating_record($moodleoverflow->id, $discussion->id, $post->id, $rating, $userid, $modulecontext); } - } else { // If multiplemarks are allowed, only create a new rating. - $mid = $moodleoverflow->id; - return self::moodleoverflow_add_rating_record($mid, $discussion->id, $post->id, $rating, $userid, $modulecontext); + return self::moodleoverflow_add_rating_record($moodleoverflow->id, $discussion->id, $post->id, + $rating, $userid, $modulecontext); } } // Update an rating record. if ($oldrating['normal']) { - - if (!get_config('moodleoverflow', 'allowratingchange')) { - throw new moodle_exception('noratingchangeallowed', 'moodleoverflow'); - - return false; - } + moodleoverflow_get_config_or_exception('moodleoverflow', 'allowratingchange', + 'noratingchangeallowed', 'moodleoverflow'); // Check if the rating can still be changed. if (!self::moodleoverflow_can_be_changed($postid, $oldrating['normal']->rating, $userid)) { @@ -186,10 +151,8 @@ public static function moodleoverflow_add_rating($moodleoverflow, $postid, $rati } // Create a new rating record. - $mid = $moodleoverflow->id; - $did = $post->discussion; - - return self::moodleoverflow_add_rating_record($mid, $did, $postid, $rating, $userid, $modulecontext); + return self::moodleoverflow_add_rating_record($moodleoverflow->id, $post->discussion, $postid, + $rating, $userid, $modulecontext); } /** @@ -197,24 +160,16 @@ public static function moodleoverflow_add_rating($moodleoverflow, $postid, $rati * Whether within a course or an instance is decided by the settings. * * @param int $moodleoverflowid - * @param null $userid + * @param int $userid * @param bool $forcesinglerating If true you only get the reputation for the given $moodleoverflowid, * even if coursewidereputation = true * * @return int */ - public static function moodleoverflow_get_reputation($moodleoverflowid, $userid = null, $forcesinglerating = false) { - global $DB, $USER; - - // Get the user id. - if (!isset($userid)) { - $userid = $USER->id; - } - + public static function moodleoverflow_get_reputation($moodleoverflowid, $userid, $forcesinglerating = false) { // Check the moodleoverflow instance. - if (!$moodleoverflow = $DB->get_record('moodleoverflow', ['id' => $moodleoverflowid])) { - throw new moodle_exception('invalidmoodleoverflowid', 'moodleoverflow'); - } + $moodleoverflow = moodleoverflow_get_record_or_exception('moodleoverflow', ['id' => $moodleoverflowid], + 'invalidmoodleoverflowid'); // Check whether the reputation can be summed over the whole course. if ($moodleoverflow->coursewidereputation && !$forcesinglerating) { @@ -244,111 +199,43 @@ public static function moodleoverflow_sort_answers_by_ratings($posts) { if ($posts[array_key_first($posts)]->ratingpreference == 1) { $solutionspreferred = true; } + // Build array groups for different types of answers (solved and helpful, only solved/helpful, unmarked). + $solvedhelpfulposts = []; + $solvedposts = []; + $helpfulposts = []; + $unmarkedposts = []; - // Sort the answer posts by ratings. - // Build groups of different types of answers (Solved and helpful, only solved/helpful, other). + // Sort the answer posts by ratings.. // markedsolved == 1 means the post is marked as solved. // markedhelpful == 1 means the post is marked as helpful. - // If a group is complete, sort the group. - $index = 1; - $startsolvedandhelpful = 1; - $startsolved = 1; - $starthelpful = 1; - $startother = 1; - // Solved and helpful posts are first. + // Step 1: Iterate trough the answerposts and assign each post to a group. foreach ($answerposts as $post) { - if ($post->markedsolution > 0 && $post->markedhelpful > 0) { - $sortedposts[$index] = $post; - $index++; - } - } - // Update the indices and sort the group by votes. - if ($index > $startsolvedandhelpful) { - $startsolved = $index; - $starthelpful = $index; - $startother = $index; - self::moodleoverflow_quicksort_posts($sortedposts, $startsolvedandhelpful, $index - 1, 'votesdifference'); - self::moodleoverflow_check_equal_votes($sortedposts, $startsolvedandhelpful, $index - 1); - } - - // Check if solutions are preferred. - if ($solutionspreferred) { - - // Build the group of only solved posts. - foreach ($answerposts as $post) { - if ($post->markedsolution > 0 && $post->markedhelpful == 0) { - $sortedposts[$index] = $post; - $index++; - } - } - // Update the indices and sort the group by votes. - if ($index > $startsolved) { - $starthelpful = $index; - $startother = $index; - self::moodleoverflow_quicksort_posts($sortedposts, $startsolved, $index - 1, 'votesdifference'); - self::moodleoverflow_check_equal_votes($sortedposts, $startsolved, $index - 1); - } - - // Build the group of only helpful posts. - foreach ($answerposts as $post) { - if ($post->markedsolution == 0 && $post->markedhelpful > 0) { - $sortedposts[$index] = $post; - $index++; - } - } - // Update the indices and sort the group by votes. - if ($index > $starthelpful) { - $startother = $index; - self::moodleoverflow_quicksort_posts($sortedposts, $starthelpful, $index - 1, 'votesdifference'); - self::moodleoverflow_check_equal_votes($sortedposts, $starthelpful, $index - 1); - } - } else { - - // Build the group of only helpful posts. - foreach ($answerposts as $post) { - if ($post->markedsolution == 0 && $post->markedhelpful > 0) { - $sortedposts[$index] = $post; - $index++; + if ($post->markedsolution > 0) { + if ($post->markedhelpful > 0) { + $solvedhelpfulposts[] = $post; + } else { + $solvedposts[] = $post; } - } - // Update the indices and sort the group by votes. - if ($index > $starthelpful) { - $startsolved = $index; - $startother = $index; - self::moodleoverflow_quicksort_posts($sortedposts, $starthelpful, $index - 1, 'votesdifference'); - self::moodleoverflow_check_equal_votes($sortedposts, $starthelpful, $index - 1); - } - - // Build the group of only solved posts. - foreach ($answerposts as $post) { - if ($post->markedsolution > 0 && $post->markedhelpful == 0) { - $sortedposts[$index] = $post; - $index++; + } else { + if ($post->markedhelpful > 0) { + $helpfulposts[] = $post; + } else { + $unmarkedposts[] = $post; } } - // Update the indices and sort the group by votes. - if ($index > $startsolved) { - $startother = $index; - self::moodleoverflow_quicksort_posts($sortedposts, $startsolved, $index - 1, 'votesdifference'); - self::moodleoverflow_check_equal_votes($sortedposts, $startsolved, $index - 1); - } } - // Now build the group of posts without ratings like helpful/solved. - foreach ($answerposts as $post) { - if ($post->markedsolution == 0 && $post->markedhelpful == 0) { - $sortedposts[$index] = $post; - $index++; - } - } - // Update the indices and sort the group by votes. - if ($index > $startother) { - self::moodleoverflow_quicksort_posts($sortedposts, $startother, $index - 1, 'votesdifference'); - self::moodleoverflow_check_equal_votes($sortedposts, $startother, $index - 1); - } + // Step 2: Sort each group after their votes and eventually time modified. + self::moodleoverflow_sort_postgroup($solvedhelpfulposts, 0, count($solvedhelpfulposts) - 1); + self::moodleoverflow_sort_postgroup($solvedposts, 0, count($solvedposts) - 1); + self::moodleoverflow_sort_postgroup($helpfulposts, 0, count($helpfulposts) - 1); + self::moodleoverflow_sort_postgroup($unmarkedposts, 0, count($unmarkedposts) - 1); - // Rearrange the indices and return the sorted posts. + // Step 3: Put each group together in the right order depending on the rating preferences. + $temp = $solutionspreferred ? array_merge($solvedposts, $helpfulposts) : array_merge($helpfulposts, $solvedposts); + $sortedposts = array_merge($sortedposts, $solvedhelpfulposts, $temp, $unmarkedposts); + // Rearrange the indices and return the sorted posts. $neworder = []; foreach ($sortedposts as $post) { $neworder[$post->id] = $post; @@ -377,7 +264,7 @@ public static function moodleoverflow_user_rated($postid, $userid = null) { // Get the rating. $sql = "SELECT firstrated, rating FROM {moodleoverflow_ratings} - WHERE userid = ? AND postid = ? AND (rating = 1 OR rating = 2)"; + WHERE userid = ? AND postid = ? AND (rating = 1 OR rating = 2)"; return ($DB->get_record_sql($sql, [ $userid, $postid ])); } @@ -393,9 +280,7 @@ public static function moodleoverflow_get_rating($postid) { global $DB; // Retrieve the full post. - if (!$post = $DB->get_record('moodleoverflow_posts', ['id' => $postid])) { - throw new moodle_exception('postnotexist', 'moodleoverflow'); - } + $post = moodleoverflow_get_record_or_exception('moodleoverflow_posts', ['id' => $postid], 'postnotexist'); // Get the rating for this single post. return self::moodleoverflow_get_ratings_by_discussion($post->discussion, $postid); @@ -498,57 +383,37 @@ public static function moodleoverflow_get_reputation_instance($moodleoverflowid, // Initiate a variable. $reputation = 0; - - if ($moodleoverflow->anonymous != anonymous::EVERYTHING_ANONYMOUS) { - - // Get all posts of this user in this module. - // Do not count votes for own posts. - $sql = "SELECT r.id, r.postid as post, r.rating - FROM {moodleoverflow_posts} p - JOIN {moodleoverflow_ratings} r ON p.id = r.postid - WHERE p.userid = ? AND NOT r.userid = ? AND r.moodleoverflowid = ? "; - - if ($moodleoverflow->anonymous == anonymous::QUESTION_ANONYMOUS) { - $sql .= " AND p.parent <> 0 "; - } - - $sql .= "ORDER BY r.postid ASC"; - - $params = [$userid, $userid, $moodleoverflowid]; - $records = $DB->get_records_sql($sql, $params); - - // Check if there are results. - $records = (isset($records)) ? $records : []; - - // Iterate through all ratings. - foreach ($records as $record) { - - // The rating is a downvote. - if ($record->rating == RATING_DOWNVOTE) { + // Get all posts of this user in this module. + // Do not count votes for own posts. + $sql = "SELECT r.id, r.postid as post, r.rating + FROM {moodleoverflow_posts} p + JOIN {moodleoverflow_ratings} r ON p.id = r.postid + JOIN {moodleoverflow} m ON r.moodleoverflowid = m.id + WHERE p.userid = ? AND NOT r.userid = ? AND r.moodleoverflowid = ? AND m.anonymous <> ?"; + + if ($moodleoverflow->anonymous == anonymous::QUESTION_ANONYMOUS) { + $sql .= " AND p.parent <> 0 "; + } + + $sql .= "ORDER BY r.postid ASC"; + + $params = [$userid, $userid, $moodleoverflowid, anonymous::EVERYTHING_ANONYMOUS]; + $records = $DB->get_records_sql($sql, $params); + // Iterate through all ratings. + foreach ($records as $record) { + switch ($record->rating) { + case RATING_DOWNVOTE: $reputation += get_config('moodleoverflow', 'votescaledownvote'); - continue; - } - - // The rating is an upvote. - if ($record->rating == RATING_UPVOTE) { + break; + case RATING_UPVOTE: $reputation += get_config('moodleoverflow', 'votescaleupvote'); - continue; - } - - // The post has been marked as helpful by the question owner. - if ($record->rating == RATING_HELPFUL) { + break; + case RATING_HELPFUL: $reputation += get_config('moodleoverflow', 'votescalehelpful'); - continue; - } - - // The post has been marked as solved by a teacher. - if ($record->rating == RATING_SOLVED) { + break; + case RATING_SOLVED: $reputation += get_config('moodleoverflow', 'votescalesolved'); - continue; - } - - // Another rating should not exist. - continue; + break; } } @@ -556,7 +421,7 @@ public static function moodleoverflow_get_reputation_instance($moodleoverflowid, // Votes for own posts are not counting. $sql = "SELECT COUNT(id) as amount FROM {moodleoverflow_ratings} - WHERE userid = ? AND moodleoverflowid = ? AND (rating = 1 OR rating = 2)"; + WHERE userid = ? AND moodleoverflowid = ? AND (rating = 1 OR rating = 2)"; $params = [$userid, $moodleoverflowid]; $votes = $DB->get_record_sql($sql, $params); @@ -592,9 +457,7 @@ public static function moodleoverflow_get_reputation_course($courseid, $userid = $reputation = 0; // Check if the course exists. - if (!$course = $DB->get_record('course', ['id' => $courseid])) { - throw new moodle_exception('invalidcourseid'); - } + $course = moodleoverflow_get_record_or_exception('course', ['id' => $courseid], 'invalidcourseid', '*', true); // Get all moodleoverflow instances in this course. $sql = "SELECT id @@ -604,9 +467,6 @@ public static function moodleoverflow_get_reputation_course($courseid, $userid = $params = [$course->id]; $instances = $DB->get_records_sql($sql, $params); - // Check if there are instances in this course. - $instances = (isset($instances)) ? $instances : []; - // Sum the reputation of each individual instance. foreach ($instances as $instance) { $reputation += self::moodleoverflow_get_reputation_instance($instance->id, $userid); @@ -631,11 +491,11 @@ private static function moodleoverflow_check_old_rating($postid, $userid, $oldra // Initiate the array. $rating = []; - // Get the normal rating. $sql = "SELECT * - FROM {moodleoverflow_ratings} - WHERE userid = ? AND postid = ? AND (rating = 1 OR rating = 2)"; - $rating['normal'] = $DB->get_record_sql($sql, [ $userid, $postid ]); + FROM {moodleoverflow_ratings}"; + // Get the normal rating. + $condition = " WHERE userid = ? AND postid = ? AND (rating = 1 OR rating = 2)"; + $rating['normal'] = $DB->get_record_sql($sql . $condition, [$userid, $postid]); // Return the rating if it is requested. if ($oldrating == RATING_DOWNVOTE || $oldrating == RATING_UPVOTE) { @@ -643,10 +503,8 @@ private static function moodleoverflow_check_old_rating($postid, $userid, $oldra } // Get the solved rating. - $sql = "SELECT * - FROM {moodleoverflow_ratings} - WHERE postid = ? AND rating = 3"; - $rating['solved'] = $DB->get_record_sql($sql, [ $postid ]); + $condition = " WHERE postid = ? AND rating = 3"; + $rating['solved'] = $DB->get_record_sql($sql . $condition, [ $postid ]); // Return the rating if it is requested. if ($oldrating == RATING_SOLVED) { @@ -654,10 +512,8 @@ private static function moodleoverflow_check_old_rating($postid, $userid, $oldra } // Get the helpful rating. - $sql = "SELECT * - FROM {moodleoverflow_ratings} - WHERE postid = ? AND rating = 4"; - $rating['helpful'] = $DB->get_record_sql($sql, [ $postid ]); + $condition = " WHERE postid = ? AND rating = 4"; + $rating['helpful'] = $DB->get_record_sql($sql . $condition, [ $postid ]); // Return the rating if it is requested. if ($oldrating == RATING_HELPFUL) { @@ -678,8 +534,6 @@ private static function moodleoverflow_check_old_rating($postid, $userid, $oldra * @return bool */ private static function moodleoverflow_can_be_changed($postid, $rating, $userid) { - global $CFG; - // Check if the old read record exists. $old = self::moodleoverflow_check_old_rating($postid, $userid, $rating); if (!$old) { @@ -691,7 +545,6 @@ private static function moodleoverflow_can_be_changed($postid, $rating, $userid) /** * Removes a rating record. - * * @param int $postid * @param int $rating * @param int $userid @@ -711,11 +564,7 @@ private static function moodleoverflow_remove_rating($postid, $rating, $userid, $oldrecord = self::moodleoverflow_check_old_rating($postid, $userid, $rating); // Trigger an event. - $params = [ - 'objectid' => $oldrecord->id, - 'context' => $modulecontext, - ]; - $event = \mod_moodleoverflow\event\rating_deleted::create($params); + $event = \mod_moodleoverflow\event\rating_deleted::create(['objectid' => $oldrecord->id, 'context' => $modulecontext]); $event->add_record_snapshot('moodleoverflow_ratings', $oldrecord); $event->trigger(); @@ -818,65 +667,19 @@ public static function moodleoverflow_user_can_rate($post, $modulecontext, $user } /** - * Sorts answerposts of a discussion with quicksort algorithm - * @param array $posts the posts that are being sorted - * @param int $low the index from where the sorting begins - * @param int $high the index until the array is being sorted - * @param string $sortby the attribute by which the posts are being sorted, can be 'votesdifference' or 'modified' - */ - private static function moodleoverflow_quicksort_posts(array &$posts, $low, $high, $sortby): void { - if ($low >= $high) { - return; - } - $left = $low; - $right = $high; - $pivot = 0; - if ($sortby == 'votesdifference') { - $pivot = $posts[intval(($low + $high) / 2)]->votesdifference; - } else if ($sortby == 'modified') { - $pivot = $posts[intval(($low + $high) / 2)]->modified; - } - do { - if ($sortby == 'votesdifference') { - while ($posts[$left]->votesdifference > $pivot) { - $left++; - } - while ($posts[$right]->votesdifference < $pivot) { - $right--; - } - } else if ($sortby == 'modified') { - while ($posts[$left]->modified < $pivot) { - $left++; - } - while ($posts[$right]->modified > $pivot) { - $right--; - } - } - if ($left <= $right) { - $temp = $posts[$right]; - $posts[$right] = $posts[$left]; - $posts[$left] = $temp; - $right--; - $left++; - } - } while ($left <= $right); - if ($low < $right) { - self::moodleoverflow_quicksort_posts($posts, $low, $right, $sortby); - } - if ($high > $left ) { - self::moodleoverflow_quicksort_posts($posts, $left, $high, $sortby); - } - } - - /** - * Helper function for moodleoverflow_sort_answer_by_rating. For posts that have the same mark and votesdifference, - * the posts are sorted by time modified + * Helper function for moodleoverflow_sort_answer_by_rating. Sorts a group of posts (solved and helpful, only solved/helpful + * and other) after their votesdifference and if needed after their modified time. + * * @param array $posts The array that will be sorted * @param int $low Startindex from where equal votes will be checked * @param int $high Endindex until where equal votes will be checked * @return void */ - private static function moodleoverflow_check_equal_votes(&$posts, $low, $high) { + private static function moodleoverflow_sort_postgroup(&$posts, $low, $high) { + // First sort the array after their votesdifference. + moodleoverflow_quick_array_sort($posts, 0, $high, 'votesdifference', 'desc'); + + // Check if posts have the same votesdifference and sort them after their modified time if needed. while ($low < $high) { if ($posts[$low]->votesdifference == $posts[$low + 1]->votesdifference) { $tempstartindex = $low; @@ -885,7 +688,7 @@ private static function moodleoverflow_check_equal_votes(&$posts, $low, $high) { ($posts[$tempendindex]->votesdifference == $posts[$tempendindex + 1]->votesdifference)) { $tempendindex++; } - self::moodleoverflow_quicksort_posts($posts, $tempstartindex, $tempendindex, 'modified'); + moodleoverflow_quick_array_sort($posts, $tempstartindex, $tempendindex, 'modified', 'asc'); $low = $tempendindex + 1; } else { $low++; diff --git a/classes/readtracking.php b/classes/readtracking.php index 24d4530498..bc2b556e82 100644 --- a/classes/readtracking.php +++ b/classes/readtracking.php @@ -90,13 +90,8 @@ public static function moodleoverflow_is_tracked($moodleoverflow, $user = null) $user = $USER; } - // Guests cannot track a moodleoverflow. - if (isguestuser($USER) || empty($USER->id)) { - return false; - } - - // Check if the moodleoverflow can be generally tracked. - if (!self::moodleoverflow_can_track_moodleoverflows($moodleoverflow)) { + // Guests cannot track a moodleoverflow. The moodleoverflow should be generally trackable. + if (isguestuser($USER) || empty($USER->id) || !self::moodleoverflow_can_track_moodleoverflows($moodleoverflow)) { return false; } @@ -134,14 +129,10 @@ public static function moodleoverflow_mark_moodleoverflow_read($cm, $userid = nu $discussions = moodleoverflow_get_discussions_unread($cm); // Iterate through all of this discussions. - foreach ($discussions as $discussionid => $amount) { - + foreach ($discussions as $discussionid) { // Mark the discussion as read. - if (!self::moodleoverflow_mark_discussion_read($discussionid, context_module::instance($cm->id), $userid)) { - throw new moodle_exception('markreadfailed', 'moodleoverflow'); - - return false; - } + $markedcheck = self::moodleoverflow_mark_discussion_read($discussionid, context_module::instance($cm->id), $userid); + moodleoverflow_throw_exception_with_check($markedcheck !== true, 'markreadfailed'); } return true; @@ -174,11 +165,8 @@ public static function moodleoverflow_mark_discussion_read($discussionid, $modco } // Mark the post as read. - if (!self::moodleoverflow_mark_post_read($userid, $post)) { - throw new moodle_exception('markreadfailed', 'moodleoverflow'); - - return false; - } + $postreadcheck = self::moodleoverflow_mark_post_read($userid, $post); + moodleoverflow_throw_exception_with_check(!$postreadcheck, 'markreadfailed'); } // The discussion has been marked as read. diff --git a/classes/subscriptions.php b/classes/subscriptions.php index 83af4181d2..2063c067f1 100644 --- a/classes/subscriptions.php +++ b/classes/subscriptions.php @@ -216,7 +216,7 @@ public static function fill_subscription_cache($moodleoverflowid, $userid = null $subscriptions = $DB->get_recordset('moodleoverflow_subscriptions', $params, '', 'id, userid'); // Loop through the records. - foreach ($subscriptions as $id => $data) { + foreach ($subscriptions as $data) { // Create a new record if necessary. if (!isset(self::$moodleoverflowcache[$data->userid])) { @@ -985,14 +985,13 @@ public static function moodleoverflow_get_subscribe_link($moodleoverflow, $conte /** * Given a new post, subscribes the user to the thread the post was posted in. * - * @param object $fromform The submitted form * @param \stdClass $moodleoverflow The moodleoverflow record * @param \stdClass $discussion The discussion record * @param \context_module $modulecontext The context of the module * * @return bool */ - public static function moodleoverflow_post_subscription($fromform, $moodleoverflow, $discussion, $modulecontext) { + public static function moodleoverflow_post_subscription($moodleoverflow, $discussion, $modulecontext) { global $USER; // Check for some basic information. diff --git a/classes/tables/userstats_table.php b/classes/tables/userstats_table.php index 677dc7d081..d88fa7ce21 100644 --- a/classes/tables/userstats_table.php +++ b/classes/tables/userstats_table.php @@ -26,7 +26,9 @@ defined('MOODLE_INTERNAL') || die(); use mod_moodleoverflow\ratings; +global $CFG; require_once($CFG->dirroot . '/mod/moodleoverflow/lib.php'); +require_once($CFG->dirroot . '/mod/moodleoverflow/locallib.php'); require_once($CFG->libdir . '/tablelib.php'); /** @@ -69,13 +71,8 @@ public function __construct($uniqueid, $courseid, $moodleoverflow, $url) { $this->set_attribute('class', 'moodleoverflow-statistics-table'); $this->set_attribute('id', $uniqueid); - $this->define_columns(['username', - 'receivedupvotes', - 'receiveddownvotes', - 'forumactivity', - 'courseactivity', - 'forumreputation', - 'coursereputation', ]); + $this->define_columns(['username', 'receivedupvotes', 'receiveddownvotes', 'forumactivity', 'courseactivity', + 'forumreputation', 'coursereputation', ]); $this->define_baseurl($url); $this->define_headers([get_string('fullnameuser'), get_string('userstatsupvotes', 'moodleoverflow'), @@ -102,95 +99,17 @@ public function out() { $this->finish_output(); } - /** - * Method to sort the userstatsdata-table. - * - * @param array $sortorder The sort order array. - * - * @return void - */ - private function sort_table_data($sortorder) { - $key = $sortorder['sortby']; - // The index of each object in usertable is it's value of $key. - $length = count($this->userstatsdata); - if ($sortorder['sortorder'] == 4) { - // 4 means sort in ascending order. - $this->quick_usertable_sort(0, $length - 1, $key, 'asc'); - } else if ($sortorder['sortorder'] == 3) { - // 3 means sort in descending order. - $this->quick_usertable_sort(0, $length - 1, $key, 'desc'); - } - } - - /** - * Sorts userstatsdata with quicksort algorithm. - * - * @param int $low index for quicksort. - * @param int $high index for quicksort. - * @param int $key the column that is being sorted (upvotes, downvotes etc.). - * @param string $order sort in ascending or descending order. - * - * @return void - */ - private function quick_usertable_sort($low, $high, $key, $order) { - if ($low >= $high) { - return; - } - $left = $low; - $right = $high; - $pivot = $this->userstatsdata[intval(($low + $high) / 2)]; - $pivot = $pivot->$key; - do { - if ($order == 'asc') { - while ($this->userstatsdata[$left]->$key < $pivot) { - $left++; - } - while ($this->userstatsdata[$right]->$key > $pivot) { - $right--; - } - } else if ($order == 'desc') { - while ($this->userstatsdata[$left]->$key > $pivot) { - $left++; - } - while ($this->userstatsdata[$right]->$key < $pivot) { - $right--; - } - } - if ($left <= $right) { - $temp = $this->userstatsdata[$right]; - $this->userstatsdata[$right] = $this->userstatsdata[$left]; - $this->userstatsdata[$left] = $temp; - $right--; - $left++; - } - } while ($left <= $right); - if ($low < $right) { - if ($order == 'asc') { - $this->quick_usertable_sort($low, $right, $key, 'asc'); - } else if ($order == 'desc') { - $this->quick_usertable_sort($low, $right, $key, 'desc'); - } - } - if ($high > $left) { - if ($order == 'asc') { - $this->quick_usertable_sort($left, $high, $key, 'asc'); - } else if ($order == 'desc') { - $this->quick_usertable_sort($left, $high, $key, 'desc'); - } - } - } - /** * Method to collect all the data. * Method will collect all users from the given course and will determine the user statistics - * - * @return 2d-array with user statistic + * Builds an 2d-array with user statistic */ public function get_table_data() { // Get all userdata from a course. $context = \context_course::instance($this->courseid); $users = get_enrolled_users($context , '', 0, 'u.id, u.firstname, u.lastname'); + // Step 1.0: Build the datatable with all relevant information. $ratingdata = $this->get_rating_data(); // Step 2.0: Now collect the data for every user in the course. @@ -198,55 +117,26 @@ public function get_table_data() { $student = $this->createstudent($user); foreach ($ratingdata as $row) { - // Is the rating from or for the current student? - if ($row->postuserid !== $student->id && $row->rateuserid !== $student->id) { - continue; - } - // Did the student receive an up- or downvote? - // Only count if the discussion is not anonymous or if the user is not starter of the discussion. - if ($row->postuserid == $student->id && - (($row->anonymoussetting == 0) || ($row->anonymoussetting == 1 && $row->postuserid != $row->discussuserid))) { - if ($row->rating == RATING_UPVOTE) { - $student->receivedupvotes += 1; - } else if ($row->rating == RATING_DOWNVOTE) { - $student->receiveddownvotes += 1; - } + if ($row->postuserid == $student->id) { + $this->process_received_votes($student, $row); } // Did a student submit a rating? - // For solution marks: only count a solution if the discussion is not completely anonymous. - // For helpful marks: only count helpful marks if the discussion is not any kind of anonymous. - // Up and downvotes are always counted. - if ($row->rateuserid == $student->id && !array_key_exists($row->rateid, $student->ratedposts) && - (($row->rating == RATING_SOLVED && $row->anonymoussetting != 2) || - ($row->rating == RATING_HELPFUL && $row->anonymoussetting == 0) || - ($row->rating == RATING_UPVOTE) || - ($row->rating == RATING_DOWNVOTE))) { - - if ($row->moodleoverflowid == $this->moodleoverflowid) { - $student->forumactivity += 1; - } - $student->courseactivity += 1; - $student->ratedposts[$row->rateid] = $row->rateid; + if ($row->rateuserid == $student->id ) { + $this->process_submitted_ratings($student, $row); } - // Did the student write a post? Only count a written post if: the post is not in an anonymous discussion; - // or the post is in a partial anonymous discussion and the user is not the starter of the discussion. - if ($row->postuserid == $student->id && !array_key_exists($row->postid, $student->submittedposts) && - ($row->anonymoussetting == 0 || ($row->anonymoussetting == 1 && $row->postuserid != $row->discussuserid))) { - - if ($row->moodleoverflowid == $this->moodleoverflowid) { - $student->forumactivity += 1; - } - $student->courseactivity += 1; - $student->submittedposts[$row->postid] = $row->postid; + // Did the student write a post? + if ($row->postuserid == $student->id ) { + $this->process_written_posts($student, $row); } + } // Get the user reputation from the course. $student->forumreputation = ratings::moodleoverflow_get_reputation_instance($this->moodleoverflowid, $student->id); $student->coursereputation = ratings::moodleoverflow_get_reputation_course($this->courseid, $student->id); - array_push($this->userstatsdata, $student); + $this->userstatsdata[] = $student; } } @@ -268,16 +158,16 @@ public function set_helpactivity() { get_string('helpamountofactivity', 'moodleoverflow')); $this->helpactivity->class = 'helpactivityclass btn btn-link'; $this->helpactivity->iconattributes = ['role' => 'button', - 'data-container' => 'body', - 'data-toggle' => 'popover', - 'data-placement' => 'right', - 'data-action' => 'showhelpicon', - 'data-html' => 'true', - 'data-trigger' => 'focus', - 'tabindex' => '0', - 'data-content' => '

' . - get_string('helpamountofactivity', 'moodleoverflow') . - '

', ]; + 'data-container' => 'body', + 'data-toggle' => 'popover', + 'data-placement' => 'right', + 'data-action' => 'showhelpicon', + 'data-html' => 'true', + 'data-trigger' => 'focus', + 'tabindex' => '0', + 'data-content' => '

' . + get_string('helpamountofactivity', 'moodleoverflow') . + '

', ]; $this->helpactivity->object = \html_writer::span($this->helpactivity->icon, $this->helpactivity->class, @@ -350,7 +240,7 @@ public function col_coursereputation($row) { } /** - * Dependeng on the value display success or warning badge. + * Depending on the value display success or warning badge. * @param int $number * @return string */ @@ -363,6 +253,7 @@ private function badge_render($number) { $number . \html_writer::end_span()); } } + /** * error handling * @param object $colname @@ -372,6 +263,9 @@ private function badge_render($number) { public function other_cols($colname, $attempt) { return null; } + + // Helper functions. + /** * Return a student object. * @param \stdClass $user @@ -383,14 +277,14 @@ private function createstudent($user) { $student->name = $user->firstname . ' ' . $user->lastname; $linktostudent = new \moodle_url('/user/view.php', ['id' => $student->id, 'course' => $this->courseid]); $student->link = \html_writer::link($linktostudent->out(), $student->name); - $student->submittedposts = []; // Posts written by the student. Key = postid, Value = postid. - $student->ratedposts = []; // Posts that the student rated. Key = rateid, Value = rateid. + $student->submittedposts = []; // Posts written by the student. Key = postid, Value = postid. + $student->ratedposts = []; // Posts that the student rated. Key = rateid, Value = rateid. $student->receivedupvotes = 0; $student->receiveddownvotes = 0; - $student->forumactivity = 0; // Number of written posts and submitted ratings in the current moodleoverflow. - $student->courseactivity = 0; // Number of written posts and submitted ratings in the course. - $student->forumreputation = 0; // Reputation in the current moodleoverflow. - $student->coursereputation = 0; // Reputation in the course. + $student->forumactivity = 0; // Number of written posts and submitted ratings in the current moodleoverflow. + $student->courseactivity = 0; // Number of written posts and submitted ratings in the course. + $student->forumreputation = 0; // Reputation in the current moodleoverflow. + $student->coursereputation = 0; // Reputation in the course. return $student; } @@ -401,7 +295,6 @@ private function createstudent($user) { */ private function get_rating_data() { global $DB; - // Step 1.0: Build the datatable with all relevant Informations. $sqlquery = 'SELECT (ROW_NUMBER() OVER (ORDER BY ratings.id)) AS row_num, discuss.id AS discussid, discuss.userid AS discussuserid, @@ -420,4 +313,95 @@ private function get_rating_data() { WHERE discuss.course = ' . $this->courseid . ';'; return $DB->get_records_sql($sqlquery); } + + /** + * Process the received votes for a student. + * @param $student + * @param $row + * @return void + */ + private function process_received_votes(&$student, $row) { + // Only count received votes if the post is not anonymous (no anonymous setting or only questioner anonymous discussion). + if ((($row->anonymoussetting == 0) || ($row->anonymoussetting == 1 && $row->postuserid != $row->discussuserid))) { + if ($row->rating == RATING_UPVOTE) { + $student->receivedupvotes += 1; + } else if ($row->rating == RATING_DOWNVOTE) { + $student->receiveddownvotes += 1; + } + } + } + + /** + * Process the submitted ratings from a student. + * @param $student + * @param $row + * @return void + */ + private function process_submitted_ratings(&$student, $row) { + // For solution marks: only count a solution if the discussion is not completely anonymous. + // For helpful marks: only count helpful marks if the discussion is not any kind of anonymous. + // Up and downvotes are always counted. + $solvedcheck = ($row->rating == RATING_SOLVED && $row->anonymoussetting != 2); + $helpfulcheck = ($row->rating == RATING_HELPFUL && $row->anonymoussetting == 0); + $isvote = ($row->rating == RATING_UPVOTE || $row->rating == RATING_DOWNVOTE); + + if (!array_key_exists($row->rateid, $student->ratedposts)) { + if ($solvedcheck || $helpfulcheck || $isvote) { + $this->increment_forumactivity($student, $row); + $student->courseactivity++; + $student->ratedposts[$row->rateid] = $row->rateid; + } + } + } + + /** + * Process the written posts from a student for the activity. + * @param $student + * @param $row + * @return void + */ + private function process_written_posts(&$student, $row) { + // Only count a written post if: the post is not in an anonymous discussion: + // or the post is in a partial anonymous discussion and the user is not the starter of the discussion. + if (!array_key_exists($row->postid, $student->submittedposts) && + ($row->anonymoussetting == 0 || ($row->anonymoussetting == 1 && $row->postuserid != $row->discussuserid))) { + + $this->increment_forumactivity($student, $row); + $student->courseactivity += 1; + $student->submittedposts[$row->postid] = $row->postid; + } + } + + /** + * Increments the forum activity of a student. + * @param $row + * @param $moodleoverflowid + * @param $forumactivity + * @return void + */ + private function increment_forumactivity(&$student, $row) { + if ($row->moodleoverflowid == $this->moodleoverflowid) { + $student->forumactivity++; + } + } + + // Sort function. + + /** + * Method to sort the userstatsdata-table. + * @param array $sortorder The sort order array. + * @return void + */ + private function sort_table_data($sortorder) { + $key = $sortorder['sortby']; + // The index of each object in usertable is it's value of $key. + $length = count($this->userstatsdata); + if ($sortorder['sortorder'] == 4) { + // 4 means sort in ascending order. + moodleoverflow_quick_array_sort($this->userstatsdata, 0, $length - 1, $key, 'asc'); + } else if ($sortorder['sortorder'] == 3) { + // 3 means sort in descending order. + moodleoverflow_quick_array_sort($this->userstatsdata, 0, $length - 1, $key, 'desc'); + } + } } diff --git a/classes/task/send_mails.php b/classes/task/send_mails.php index 310bbc5f88..7991f55023 100644 --- a/classes/task/send_mails.php +++ b/classes/task/send_mails.php @@ -89,13 +89,10 @@ public function send_review_notifications() { } $course = null; - $moodleoverflow = null; $usersto = null; $cm = null; - $discussion = null; - $success = []; foreach ($postinfos as $postinfo) { @@ -135,16 +132,8 @@ public function send_review_notifications() { cron_setup_user($userto, $course); } - $maildata = new moodleoverflow_email( - $course, - $cm, - $moodleoverflow, - $discussion, - $post, - $userfrom, - $userto, - false - ); + $maildata = new moodleoverflow_email($course, $cm, $moodleoverflow, $discussion, + $post, $userfrom, $userto, false); $textcontext = $maildata->export_for_template($renderertext, true); $htmlcontext = $maildata->export_for_template($rendererhtml, false); diff --git a/discussion.php b/discussion.php index 295220bb08..bb0cfec030 100644 --- a/discussion.php +++ b/discussion.php @@ -24,6 +24,7 @@ // Include config and locallib. require_once('../../config.php'); +global $CFG, $DB, $PAGE, $USER, $SESSION, $OUTPUT; require_once($CFG->dirroot . '/mod/moodleoverflow/locallib.php'); // Declare optional parameters. @@ -39,19 +40,14 @@ $PAGE->add_body_class('limitedwidth'); // Check if the discussion is valid. -if (!$discussion = $DB->get_record('moodleoverflow_discussions', ['id' => $d])) { - throw new moodle_exception('invaliddiscussionid', 'moodleoverflow'); -} +$discussion = moodleoverflow_get_record_or_exception('moodleoverflow_discussions', ['id' => $d], 'invaliddiscussionid'); // Check if the related moodleoverflow instance is valid. -if (!$moodleoverflow = $DB->get_record('moodleoverflow', ['id' => $discussion->moodleoverflow])) { - throw new moodle_exception('invalidmoodleoverflowid', 'moodleoverflow'); -} +$moodleoverflow = moodleoverflow_get_record_or_exception('moodleoverflow', ['id' => $discussion->moodleoverflow], + 'invalidmoodleoverflowid'); // Check if the related moodleoverflow instance is valid. -if (!$course = $DB->get_record('course', ['id' => $discussion->course])) { - throw new moodle_exception('invalidcourseid'); -} +$course = moodleoverflow_get_record_or_exception('course', ['id' => $discussion->course], 'invalidcourseid', '*', true); // Save the allowmultiplemarks setting. $marksetting = $DB->get_record('moodleoverflow', ['id' => $moodleoverflow->id], 'allowmultiplemarks'); @@ -83,7 +79,7 @@ if (in_array($ratingid, [RATING_SOLVED, RATING_REMOVE_SOLVED, RATING_HELPFUL, RATING_REMOVE_HELPFUL])) { // Rate the post. - if (!\mod_moodleoverflow\ratings::moodleoverflow_add_rating($moodleoverflow, $ratedpost, $ratingid, $cm)) { + if (!\mod_moodleoverflow\ratings::moodleoverflow_add_rating($moodleoverflow, $ratedpost, $ratingid, $cm, $USER->id)) { throw new moodle_exception('ratingfailed', 'moodleoverflow'); } diff --git a/externallib.php b/externallib.php index 6427bbfcbb..8e148d368f 100644 --- a/externallib.php +++ b/externallib.php @@ -88,19 +88,15 @@ public static function record_vote($postid, $ratingid) { $post = $DB->get_record('moodleoverflow_posts', ['id' => $params['postid']], '*', MUST_EXIST); // Check if the discussion is valid. - if (!$discussion = $DB->get_record('moodleoverflow_discussions', ['id' => $post->discussion])) { - throw new moodle_exception('invaliddiscussionid', 'moodleoverflow'); - } + $discussion = moodleoverflow_get_record_or_exception('moodleoverflow_discussions', ['id' => $post->discussion], + 'invaliddiscussionid'); // Check if the related moodleoverflow instance is valid. - if (!$moodleoverflow = $DB->get_record('moodleoverflow', ['id' => $discussion->moodleoverflow])) { - throw new moodle_exception('invalidmoodleoverflowid', 'moodleoverflow'); - } + $moodleoverflow = moodleoverflow_get_record_or_exception('moodleoverflow', ['id' => $discussion->moodleoverflow], + 'invalidmoodleoverflowid'); // Check if the related moodleoverflow instance is valid. - if (!$course = $DB->get_record('course', ['id' => $discussion->course])) { - throw new moodle_exception('invalidcourseid'); - } + $course = moodleoverflow_get_record_or_exception('course', ['id' => $discussion->course], 'invalidcourseid', '*', true); // Get the related coursemodule and its context. if (!$cm = get_coursemodule_from_instance('moodleoverflow', $moodleoverflow->id, $course->id)) { @@ -114,7 +110,7 @@ public static function record_vote($postid, $ratingid) { // Rate the post. if (!\mod_moodleoverflow\ratings::moodleoverflow_add_rating($moodleoverflow, - $params['postid'], $params['ratingid'], $cm)) { + $params['postid'], $params['ratingid'], $cm, $USER->id)) { throw new moodle_exception('ratingfailed', 'moodleoverflow'); } diff --git a/index.php b/index.php index 979e43a7f1..733a3512c5 100644 --- a/index.php +++ b/index.php @@ -21,11 +21,15 @@ * @copyright 2017 Kennet Winter * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ +defined('MOODLE_INTERNAL') || die(); + +global $CFG, $DB, $PAGE, $USER, $SESSION, $OUTPUT; // Require needed files. use core\context\course; require_once(dirname(dirname(dirname(__FILE__))) . '/config.php'); +global $CFG, $DB, $PAGE, $USER, $SESSION, $OUTPUT; require_once(dirname(__FILE__) . '/locallib.php'); require_once($CFG->dirroot . '/course/lib.php'); @@ -46,9 +50,7 @@ $PAGE->set_url($url); // Check if the id is related to a valid course. -if (!$course = $DB->get_record('course', ['id' => $id])) { - throw new moodle_exception('invalidcourseid'); -} +$course = moodleoverflow_get_record_or_exception('course', ['id' => $id], 'invalidcourseid', '*', true); // From now on, the user must be enrolled to a course. require_course_login($course); diff --git a/lib.php b/lib.php index 78dca56503..7d7bf7c73c 100644 --- a/lib.php +++ b/lib.php @@ -94,7 +94,6 @@ * @return mixed true if the feature is supported, null if unknown */ function moodleoverflow_supports($feature) { - global $CFG; if (defined('FEATURE_MOD_PURPOSE')) { if ($feature == FEATURE_MOD_PURPOSE) { @@ -130,7 +129,7 @@ function moodleoverflow_supports($feature) { * * @return int The id of the newly inserted moodleoverflow record */ -function moodleoverflow_add_instance(stdClass $moodleoverflow, mod_moodleoverflow_mod_form $mform = null) { +function moodleoverflow_add_instance(stdClass $moodleoverflow, ?mod_moodleoverflow_mod_form $mform = null) { global $DB; // Set the current time. @@ -171,12 +170,12 @@ function moodleoverflow_instance_created($context, $moodleoverflow) { * (defined by the form in mod_form.php) this function * will update an existing instance with new data. * - * @param stdClass $moodleoverflow An object from the form in mod_form.php - * @param mod_moodleoverflow_mod_form $mform The form instance itself (if needed) + * @param stdClass $moodleoverflow An object from the form in mod_form.php + * @param mod_moodleoverflow_mod_form|null $mform The form instance itself (if needed) * * @return boolean Success/Fail */ -function moodleoverflow_update_instance(stdClass $moodleoverflow, mod_moodleoverflow_mod_form $mform = null) { +function moodleoverflow_update_instance(stdClass $moodleoverflow, ?mod_moodleoverflow_mod_form $mform = null) { global $DB; $moodleoverflow->timemodified = time(); @@ -230,11 +229,11 @@ function moodleoverflow_refresh_events($courseid = 0) { global $DB; if ($courseid == 0) { - if (!$moodleoverflows = $DB->get_records('moodleoverflow')) { + if (!$DB->get_records('moodleoverflow')) { return true; } } else { - if (!$moodleoverflows = $DB->get_records('moodleoverflow', ['course' => $courseid])) { + if (!$DB->get_records('moodleoverflow', ['course' => $courseid])) { return true; } } @@ -465,10 +464,10 @@ function moodleoverflow_pluginfile($course, $cm, $context, $filearea, $args, $fo * This function is called when the context for the page is a moodleoverflow module. This is not called by AJAX * so it is safe to rely on the $PAGE. * - * @param settings_navigation $settingsnav complete settings navigation tree - * @param navigation_node $moodleoverflownode moodleoverflow administration node + * @param settings_navigation $settingsnav complete settings navigation tree + * @param navigation_node|null $moodleoverflownode moodleoverflow administration node */ -function moodleoverflow_extend_settings_navigation(settings_navigation $settingsnav, navigation_node $moodleoverflownode = null) { +function moodleoverflow_extend_settings_navigation(settings_navigation $settingsnav, ?navigation_node $moodleoverflownode = null) { global $CFG, $DB, $PAGE, $USER; // Retrieve the current moodle record. diff --git a/locallib.php b/locallib.php index 2725b5c398..375da72dfd 100644 --- a/locallib.php +++ b/locallib.php @@ -47,8 +47,6 @@ function moodleoverflow_get_discussions($cm, $page = -1, $perpage = 0) { global $DB, $CFG, $USER; - // TODO Refactor variable naming. $discussion->id is first post and $discussion->discussion is discussion id? - // User must have the permission to view the discussions. $modcontext = context_module::instance($cm->id); if (!capabilities::has(capabilities::VIEW_DISCUSSION, $modcontext)) { @@ -775,7 +773,7 @@ function moodleoverflow_user_can_see_discussion($moodleoverflow, $discussion, $c } // Retrieve the coursemodule. - if (!$cm = get_coursemodule_from_instance('moodleoverflow', $moodleoverflow->id, $moodleoverflow->course)) { + if (!get_coursemodule_from_instance('moodleoverflow', $moodleoverflow->id, $moodleoverflow->course)) { throw new moodle_exception('invalidcoursemodule'); } @@ -1582,7 +1580,7 @@ function moodleoverflow_print_posts_nested($course, &$cm, $moodleoverflow, $disc * @return array */ function get_attachments($post, $cm) { - global $CFG, $OUTPUT; + global $OUTPUT; $attachments = []; if (empty($post->attachment)) { @@ -2147,7 +2145,6 @@ function moodleoverflow_update_all_grades_for_cm($moodleoverflowid) { /** * Updates all grades. - * */ function moodleoverflow_update_all_grades() { global $DB; @@ -2156,3 +2153,130 @@ function moodleoverflow_update_all_grades() { moodleoverflow_update_all_grades_for_cm($cmid->id); } } + + +/** + * Function to sort an array with a quicksort algorithm. This function is a recursive function that needs to + * be called from outside. + * + * @param array $array The array to be sorted. It is passed by reference. + * @param int $low The lowest index of the array. The first call should set it to 0. + * @param int $high The highest index of the array. The first call should set it to the length of the array - 1. + * + * @param string $key The key/attribute after what the algorithm sorts. The key should be an comparable integer. + * @param string $order The order of the sorting. It can be 'asc' or 'desc'. + * @return void + */ +function moodleoverflow_quick_array_sort(&$array, $low, $high, $key, $order) { + if ($low >= $high) { + return; + } + $left = $low; + $right = $high; + $pivot = $array[intval(($low + $high) / 2)]->$key; + + $compare = function($a, $b) use ($order) { + if ($order == 'asc') { + return $a < $b; + } else { + return $a > $b; + } + }; + + do { + while ($compare($array[$left]->$key, $pivot)) { + $left++; + } + while ($compare($pivot, $array[$right]->$key)) { + $right--; + } + if ($left <= $right) { + $temp = $array[$right]; + $array[$right] = $array[$left]; + $array[$left] = $temp; + $right--; + $left++; + } + } while ($left <= $right); + if ($low < $right) { + moodleoverflow_quick_array_sort($array, $low, $right, $key, $order); + } + if ($high > $left) { + moodleoverflow_quick_array_sort($array, $left, $high, $key, $order); + } +} + +/** + * Function to get a record from the database and throw an exception, if the record is not available. The error string is + * retrieved from moodleoverflow but can be retrieved from the core too. + * @param string $table The table to get the record from + * @param array $options Conditions for the record + * @param string $exceptionstring Name of the moodleoverflow exception that should be thrown in case there is no record. + * @param string $fields Optional fields that are retrieved from the found record. + * @param bool $coreexception Optional param if exception is from the core exceptions. + * @return mixed $record The found record + */ +function moodleoverflow_get_record_or_exception($table, $options, $exceptionstring, $fields = '*', $coreexception = false) { + global $DB; + if (!$record = $DB->get_record($table, $options, $fields)) { + if ($coreexception) { + throw new moodle_exception($exceptionstring); + } else { + throw new moodle_exception($exceptionstring, 'moodleoverflow'); + } + } + return $record; +} + +/** + * Function to retrieve a config and throw an exception, if the config is not found. + * @param string $plugin Plugin that has the configuration + * @param string $configname Name of configuration + * @param string $errorcode Error code/name of the exception + * @param string $exceptionmodule Module that has the exception. + * @return mixed $config + */ +function moodleoverflow_get_config_or_exception($plugin, $configname, $errorcode, $exceptionmodule) { + if (!$config = get_config($plugin, $configname)) { + throw new moodle_exception($errorcode, $exceptionmodule); + } + return $config; +} + +/** + * Function that throws an exception if a given check is true. + * @param bool $check The result of a boolean check. + * @param string $errorcode Error code/name of the exception + * @param string $coreexception Optional param if exception is from the core exceptions and not moodleoverflow. + * @return void + */ +function moodleoverflow_throw_exception_with_check($check, $errorcode, $coreexception = false) { + if ($check) { + if ($coreexception) { + throw new moodle_exception($errorcode); + } else { + throw new moodle_exception($errorcode, 'moodleoverflow'); + } + } +} + +/** + * Function that catches unenrolled users and redirects them to the enrolment page. + * @param context $coursecontext The context of the course. + * @param int $courseid Id of the course that the user needs to enrol. + * @param string $returnurl The url to return to after the user has been enrolled. + * @return void + */ +function moodleoverflow_catch_unenrolled_user($coursecontext, $courseid, $returnurl) { + global $SESSION; + if (!isguestuser() && !is_enrolled($coursecontext)) { + if (enrol_selfenrol_available($courseid)) { + $SESSION->wantsurl = qualified_me(); + $SESSION->enrolcancel = get_local_referer(false); + redirect(new \moodle_url('/enrol/index.php', [ + 'id' => $courseid, + 'returnurl' => $returnurl, + ]), get_string('youneedtoenrol')); + } + } +} diff --git a/markposts.php b/markposts.php index 9354f62912..77c9362253 100644 --- a/markposts.php +++ b/markposts.php @@ -21,6 +21,9 @@ * @copyright 2017 Kennet Winter * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ +defined('MOODLE_INTERNAL') || die(); + +global $CFG, $DB, $PAGE, $USER, $SESSION, $OUTPUT; // We do not need the locallib here. require_once('../../config.php'); @@ -46,14 +49,10 @@ $PAGE->set_url($url); // Retrieve the connected moodleoverflow instance. -if (!$moodleoverflow = $DB->get_record('moodleoverflow', ['id' => $moodleoverflowid])) { - throw new moodle_exception('invalidmoodleoverflowid', 'moodleoverflow'); -} +$moodleoverflow = moodleoverflow_get_record_or_exception('moodleoverflow', ['id' => $moodleoverflowid], 'invalidmoodleoverflowid'); // Retrieve the connected course. -if (!$course = $DB->get_record('course', ['id' => $moodleoverflow->course])) { - throw new moodle_exception('invalidcourseid'); -} +$course = moodleoverflow_get_record_or_exception('course', ['id' => $moodleoverflow->course], 'invalidcourseid', '*', true); // Get the coursemodule. if (!$cm = get_coursemodule_from_instance('moodleoverflow', $moodleoverflow->id, $course->id)) { @@ -100,10 +99,7 @@ // Check if the discussion exists. $options = ['id' => $discussionid, 'moodleoverflow' => $moodleoverflow->id]; - $discussion = $DB->get_record('moodleoverflow_discussions', $options); - if (!$discussion) { - throw new moodle_exception('invaliddiscussionid', 'moodleoverflow'); - } + $discussion = moodleoverflow_get_record_or_exception('moodleoverflow_discussions', $options, 'invaliddiscussionid'); // Mark all the discussions read. if (!\mod_moodleoverflow\readtracking::moodleoverflow_mark_discussion_read($discussionid, @@ -114,7 +110,6 @@ $status = \core\output\notification::NOTIFY_ERROR; } else { - // The discussion is successfully marked as read. $message = get_string('markmoodleoverflowreadsuccessful', 'moodleoverflow'); $status = \core\output\notification::NOTIFY_SUCCESS; diff --git a/post.php b/post.php index 7ca4085ac4..86bf67b23c 100644 --- a/post.php +++ b/post.php @@ -22,8 +22,6 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -// TODO refactor this. For more readability, and to avoid security issues. - // Include config and locallib. use mod_moodleoverflow\anonymous; use mod_moodleoverflow\review; @@ -691,8 +689,7 @@ $discussion = new \stdClass(); $discussion->id = $fromform->discussion; $discussion->moodleoverflow = $moodleoverflow->id; - \mod_moodleoverflow\subscriptions::moodleoverflow_post_subscription($fromform, - $moodleoverflow, $discussion, $modulecontext); + \mod_moodleoverflow\subscriptions::moodleoverflow_post_subscription($moodleoverflow, $discussion, $modulecontext); // Print a success-message. $message .= '

' . get_string("postaddedsuccess", "moodleoverflow") . '

'; @@ -767,8 +764,7 @@ $event->trigger(); // Subscribe to this thread. $discussion->moodleoverflow = $moodleoverflow->id; - \mod_moodleoverflow\subscriptions::moodleoverflow_post_subscription($fromform, - $moodleoverflow, $discussion, $modulecontext); + \mod_moodleoverflow\subscriptions::moodleoverflow_post_subscription($moodleoverflow, $discussion, $modulecontext); } // Redirect back to te discussion. diff --git a/subscribe.php b/subscribe.php index 0ea5367b30..0af8f73c2a 100644 --- a/subscribe.php +++ b/subscribe.php @@ -29,6 +29,8 @@ require_once(dirname(dirname(dirname(__FILE__))) . '/config.php'); require_once(dirname(__FILE__) . '/locallib.php'); +global $CFG, $DB, $PAGE, $USER, $SESSION, $OUTPUT; + // Define required and optional params. $id = required_param('id', PARAM_INT); // The moodleoverflow to set subscription on. $mode = optional_param('mode', null, PARAM_INT); // The moodleoverflow's subscription mode. @@ -50,9 +52,8 @@ } if (!is_null($discussionid)) { $url->param('d', $discussionid); - if (!$discussion = $DB->get_record('moodleoverflow_discussions', ['id' => $discussionid, 'moodleoverflow' => $id])) { - throw new moodle_exception('invaliddiscussionid', 'moodleoverflow'); - } + $discussion = moodleoverflow_get_record_or_exception('moodleoverflow_discussions', + ['id' => $discussionid, 'moodleoverflow' => $id], 'invaliddiscussionid'); } // Set the pages URL. diff --git a/tests/behat/installed.feature b/tests/behat/installed.feature index a6f43414c7..52e9a0c4a1 100644 --- a/tests/behat/installed.feature +++ b/tests/behat/installed.feature @@ -1,4 +1,4 @@ -@mod @mod_moodleoverflow +@mod @mod_moodleoverflow @javascript Feature: Installation succeeds In order to use this plugin As a user diff --git a/tests/behat/topicmove.feature b/tests/behat/topicmove.feature index 22ae518301..b0cb7dbffa 100644 --- a/tests/behat/topicmove.feature +++ b/tests/behat/topicmove.feature @@ -1,7 +1,6 @@ @mod @mod_moodleoverflow @javascript Feature: Teachers can move a discussion in one moodleoverflow forum to another moodleoverflow. - Background: Given the following "users" exist: | username | firstname | lastname | email | @@ -20,49 +19,48 @@ Feature: Teachers can move a discussion in one moodleoverflow forum to another m | moodleoverflow | everything anonymous | Test moodleoverflow description | C1 | 2 | 4 | And I log in as "admin" - Scenario: Move topic from public forum Given I am on "Course 1" course homepage - And I add a new discussion to "public moodleoverflow one" moodleoverflow with: + And I add a new discussion to "public moodleoverflow one" moodleoverflow with: | Subject | Public Message | | Message | This is the public message | - And I follow "public moodleoverflow one" - And I click on "Move this discussion to another moodleoverflow" "link" - Then I should see "public moodleoverflow two" - And I should see "question anonymous" - And I should see "everything anonymous" - And I should not see "Move discussion to public moodleoverflow one" - When I click on "Move discussion to public moodleoverflow two" "link" - And I am on "Course 1" course homepage - And I follow "public moodleoverflow two" - Then I should see "Public Message" + And I follow "public moodleoverflow one" + And I click on "Move this discussion to another moodleoverflow" "link" + Then I should see "public moodleoverflow two" + And I should see "question anonymous" + And I should see "everything anonymous" + And I should not see "Move discussion to public moodleoverflow one" + When I click on "Move discussion to public moodleoverflow two" "link" + And I am on "Course 1" course homepage + And I follow "public moodleoverflow two" + Then I should see "Public Message" Scenario: Move topic from question anonymous forum Given I am on "Course 1" course homepage - And I add a new discussion to "question anonymous" moodleoverflow with: - | Subject | Question Message | - | Message | This is the question anonymous message | - And I follow "question anonymous" - And I click on "Move this discussion to another moodleoverflow" "link" - And I should not see "Move discussion to public moodleoverflow one" - And I should not see "Move discussion to public moodleoverflow two" - And I should see "question anonymous" - And I should see "everything anonymous" - When I click on "Move discussion to everything anonymous" "link" - And I am on "Course 1" course homepage - And I follow "everything anonymous" - Then I should see "Question Message" + And I add a new discussion to "question anonymous" moodleoverflow with: + | Subject | Question Message | + | Message | This is the question anonymous message | + And I follow "question anonymous" + And I click on "Move this discussion to another moodleoverflow" "link" + And I should not see "Move discussion to public moodleoverflow one" + And I should not see "Move discussion to public moodleoverflow two" + And I should see "question anonymous" + And I should see "everything anonymous" + When I click on "Move discussion to everything anonymous" "link" + And I am on "Course 1" course homepage + And I follow "everything anonymous" + Then I should see "Question Message" Scenario: Move topic from question anonymous forum Given I am on "Course 1" course homepage - And I add a new discussion to "everything anonymous" moodleoverflow with: - | Subject | Everything Message | - | Message | This is the everything anonymous message | - And I follow "everything anonymous" - And I click on "Move this discussion to another moodleoverflow" "link" - And I should not see "Move discussion to public moodleoverflow one" - And I should not see "Move discussion to public moodleoverflow two" - And I should not see "Move discussion to question anonymous" - And I should not see "Move discussion to everything anonymous" + And I add a new discussion to "everything anonymous" moodleoverflow with: + | Subject | Everything Message | + | Message | This is the everything anonymous message | + And I follow "everything anonymous" + And I click on "Move this discussion to another moodleoverflow" "link" + And I should not see "Move discussion to public moodleoverflow one" + And I should not see "Move discussion to public moodleoverflow two" + And I should not see "Move discussion to question anonymous" + And I should not see "Move discussion to everything anonymous" diff --git a/tests/dailymail_test.php b/tests/dailymail_test.php index e27a2f1b50..c546cea291 100644 --- a/tests/dailymail_test.php +++ b/tests/dailymail_test.php @@ -60,7 +60,7 @@ final class dailymail_test extends \advanced_testcase { /** @var \stdClass discussion instance */ private $discussion; - /** @var moodleoverflow generator */ + /** @var \component_generator_base moodleoverflow generator */ private $generator; /** @@ -221,10 +221,6 @@ public function test_content_of_mail_delivery(): void { $linktodiscussion = 'discussion[0]->id; - // Assemble text. - $text = 'Course: ' . $linktocourse . ' -> ' . $linktoforum . ', Topic: ' - . $linktodiscussion . ' has ' . $messagecount . ' unread posts.'; - $this->assertStringContainsString($linktocourse, $message); $this->assertStringContainsString($linktoforum, $message); $this->assertStringContainsString($linktodiscussion, $message); diff --git a/tests/generator/lib.php b/tests/generator/lib.php index d7455df414..c27be6dad5 100644 --- a/tests/generator/lib.php +++ b/tests/generator/lib.php @@ -64,7 +64,7 @@ public function reset() { * * @return stdClass */ - public function create_instance($record = null, array $options = null) { + public function create_instance($record = null, ?array $options = null) { // Transform the record. $record = (object) (array) $record; diff --git a/tests/privacy_provider_test.php b/tests/privacy_provider_test.php index d67dab35fd..a9e7490712 100644 --- a/tests/privacy_provider_test.php +++ b/tests/privacy_provider_test.php @@ -28,7 +28,9 @@ global $CFG; use core_privacy\local\request\approved_contextlist; +use core_privacy\local\request\approved_userlist; use core_privacy\local\request\userlist; +use core_privacy\local\request\writer; use mod_moodleoverflow\privacy\provider; use mod_moodleoverflow\privacy\data_export_helper; @@ -92,7 +94,7 @@ protected function assert_discussion_data($expected, $actual, $userid) { * * @param object $expected The expected data in the post. * @param object $actual The actual data in the post. - * @param \core_privacy\local\request\writer $writer The writer used + * @param writer $writer The writer used */ protected function assert_post_data($expected, $actual, $writer) { // The message should have been passed through the rewriter. @@ -138,7 +140,7 @@ public function test_user_has_never_posted(): void { // Attempting to export data for this context should return nothing either. $this->export_context_data_for_user($user->id, $context, 'mod_moodleoverflow'); - $writer = \core_privacy\local\request\writer::with_context($context); + $writer = writer::with_context($context); // The provider should always export data for any context explicitly asked of it, but there should be no // metadata, files, or discussions. $this->assertEmpty($writer->get_data([get_string('discussions', 'mod_moodleoverflow')])); @@ -160,7 +162,7 @@ public function test_user_has_never_posted_subscribed_to_forum(): void { $context = \context_module::instance($cm->id); // Subscribe the user to the forum. - \mod_moodleoverflow\subscriptions::subscribe_user($user->id, $forum, $context); + subscriptions::subscribe_user($user->id, $forum, $context); // Retrieve all contexts - only this context should be returned. $contextlist = $this->get_contexts_for_userid($user->id, 'mod_moodleoverflow'); @@ -168,7 +170,7 @@ public function test_user_has_never_posted_subscribed_to_forum(): void { $this->assertEquals($context, $contextlist->current()); // Export all of the data for the context. $this->export_context_data_for_user($user->id, $context, 'mod_moodleoverflow'); - $writer = \core_privacy\local\request\writer::with_context($context); + $writer = writer::with_context($context); $this->assertTrue($writer->has_any_data()); $subcontext = data_export_helper::get_subcontext(); // There should be one item of metadata. @@ -196,14 +198,14 @@ public function test_user_has_never_posted_subscribed_to_discussion(): void { $cm = get_coursemodule_from_instance('moodleoverflow', $forum->id); $context = \context_module::instance($cm->id); // Subscribe the user to the discussion. - \mod_moodleoverflow\subscriptions::subscribe_user_to_discussion($user->id, $discussion, $context); + subscriptions::subscribe_user_to_discussion($user->id, $discussion, $context); // Retrieve all contexts - only this context should be returned. $contextlist = $this->get_contexts_for_userid($user->id, 'mod_moodleoverflow'); $this->assertCount(1, $contextlist); $this->assertEquals($context, $contextlist->current()); // Export all of the data for the context. $this->export_context_data_for_user($user->id, $context, 'mod_moodleoverflow'); - $writer = \core_privacy\local\request\writer::with_context($context); + $writer = writer::with_context($context); $this->assertTrue($writer->has_any_data()); // There should be nothing in the forum. The user is not subscribed there. $forumsubcontext = data_export_helper::get_subcontext(); @@ -234,7 +236,7 @@ public function test_user_has_posted_own_discussion(): void { list($user, $otheruser) = $this->create_users($course, 2); // Post twice - only the second discussion should be included. list($discussion, $post) = $this->generator->post_to_forum($forum, $user); - list($otherdiscussion, $otherpost) = $this->generator->post_to_forum($forum, $otheruser); + list($otherdiscussion) = $this->generator->post_to_forum($forum, $otheruser); $cm = get_coursemodule_from_instance('moodleoverflow', $forum->id); $context = \context_module::instance($cm->id); // Retrieve all contexts - only this context should be returned. @@ -244,7 +246,7 @@ public function test_user_has_posted_own_discussion(): void { // Export all of the data for the context. $this->setUser($user); $this->export_context_data_for_user($user->id, $context, 'mod_moodleoverflow'); - $writer = \core_privacy\local\request\writer::with_context($context); + $writer = writer::with_context($context); $this->assertTrue($writer->has_any_data()); // The other discussion should not have been returned as we did not post in it. $this->assertEmpty($writer->get_data(data_export_helper::get_subcontext($otherdiscussion))); @@ -264,7 +266,7 @@ public function test_user_has_posted_reply(): void { list($user, $otheruser) = $this->create_users($course, 2); // Post twice - only the second discussion should be included. list($discussion, $post) = $this->generator->post_to_forum($forum, $otheruser); - list($otherdiscussion, $otherpost) = $this->generator->post_to_forum($forum, $otheruser); + list($otherdiscussion) = $this->generator->post_to_forum($forum, $otheruser); $cm = get_coursemodule_from_instance('moodleoverflow', $forum->id); $context = \context_module::instance($cm->id); // Post a reply to the other person's post. @@ -277,7 +279,7 @@ public function test_user_has_posted_reply(): void { $this->assertEquals($context, $contextlist->current()); // Export all of the data for the context. $this->export_context_data_for_user($user->id, $context, 'mod_moodleoverflow'); - $writer = \core_privacy\local\request\writer::with_context($context); + $writer = writer::with_context($context); $this->assertTrue($writer->has_any_data()); // Refresh the discussions. $discussion = $DB->get_record('moodleoverflow_discussions', ['id' => $discussion->id]); @@ -289,8 +291,7 @@ public function test_user_has_posted_reply(): void { $this->assertNotEmpty($data); $this->assert_discussion_data($discussion, $data, $user->id); // The reply will be included. - $this->assert_post_data($reply, - $writer->get_data(data_export_helper::get_subcontext($discussion, $reply)), $writer); + $this->assert_post_data($reply, $writer->get_data(data_export_helper::get_subcontext($discussion, $reply)), $writer); } /** @@ -299,10 +300,7 @@ public function test_user_has_posted_reply(): void { */ public function test_user_has_rated_others(): void { $course = $this->getDataGenerator()->create_course(); - $forum = $this->getDataGenerator()->create_module('moodleoverflow', [ - 'course' => $course->id, - 'scale' => 100, - ]); + $forum = $this->getDataGenerator()->create_module('moodleoverflow', ['course' => $course->id, 'scale' => 100]); list($user, $otheruser) = $this->create_users($course, 2); list($discussion, $post) = $this->generator->post_to_forum($forum, $otheruser); $cm = get_coursemodule_from_instance('moodleoverflow', $forum->id); @@ -324,7 +322,7 @@ public function test_user_has_rated_others(): void { $this->assertEquals($context, $contextlist->current()); // Export all of the data for the context. $this->export_context_data_for_user($user->id, $context, 'mod_moodleoverflow'); - $writer = \core_privacy\local\request\writer::with_context($context); + $writer = writer::with_context($context); $this->assertTrue($writer->has_any_data()); // The discussion should not have been returned as we did not post in it. $this->assertEmpty($writer->get_data(data_export_helper::get_subcontext($discussion))); @@ -342,11 +340,8 @@ public function test_user_has_rated_others(): void { */ public function test_user_has_been_rated(): void { $course = $this->getDataGenerator()->create_course(); - $forum = $this->getDataGenerator()->create_module('moodleoverflow', [ - 'course' => $course->id, - 'scale' => 100, - ]); - list($user, $otheruser, $anotheruser) = $this->create_users($course, 3); + $forum = $this->getDataGenerator()->create_module('moodleoverflow', [ 'course' => $course->id, 'scale' => 100]); + list($user, $otheruser) = $this->create_users($course, 3); list($discussion, $post) = $this->generator->post_to_forum($forum, $user); $cm = get_coursemodule_from_instance('moodleoverflow', $forum->id); $context = \context_module::instance($cm->id); @@ -367,7 +362,7 @@ public function test_user_has_been_rated(): void { $this->assertEquals($context, $contextlist->current()); // Export all of the data for the context. $this->export_context_data_for_user($user->id, $context, 'mod_moodleoverflow'); - $writer = \core_privacy\local\request\writer::with_context($context); + $writer = writer::with_context($context); $this->assertTrue($writer->has_any_data()); $ratingdata = $writer->get_related_data(data_export_helper::get_subcontext($discussion, $post), 'rating'); @@ -384,11 +379,10 @@ public function test_user_tracking_data(): void { $cmoff = get_coursemodule_from_instance('moodleoverflow', $forumoff->id); $contextoff = \context_module::instance($cmoff->id); $forumon = $this->getDataGenerator()->create_module('moodleoverflow', ['course' => $course->id]); - $cmon = get_coursemodule_from_instance('moodleoverflow', $forumon->id); list($user) = $this->create_users($course, 1); // Set user tracking data. - \mod_moodleoverflow\readtracking::moodleoverflow_stop_tracking($forumoff->id, $user->id); - \mod_moodleoverflow\readtracking::moodleoverflow_start_tracking($forumon->id, $user->id); + readtracking::moodleoverflow_stop_tracking($forumoff->id, $user->id); + readtracking::moodleoverflow_start_tracking($forumon->id, $user->id); // Run as the user under test. $this->setUser($user); // Retrieve all contexts - only the forum tracking reads should be included. @@ -397,8 +391,7 @@ public function test_user_tracking_data(): void { $this->assertEquals($contextoff, $contextlist->current()); // Check export data for each context. $this->export_context_data_for_user($user->id, $contextoff, 'mod_moodleoverflow'); - $this->assertEquals(0, - \core_privacy\local\request\writer::with_context($contextoff)->get_metadata([], 'trackreadpreference')); + $this->assertEquals(0, writer::with_context($contextoff)->get_metadata([], 'trackreadpreference')); } /** @@ -416,9 +409,6 @@ public function test_user_read_posts(): void { $forum3 = $this->getDataGenerator()->create_module('moodleoverflow', ['course' => $course->id]); $cm3 = get_coursemodule_from_instance('moodleoverflow', $forum3->id); $context3 = \context_module::instance($cm3->id); - $forum4 = $this->getDataGenerator()->create_module('moodleoverflow', ['course' => $course->id]); - $cm4 = get_coursemodule_from_instance('moodleoverflow', $forum4->id); - $context4 = \context_module::instance($cm4->id); list($author, $user) = $this->create_users($course, 2); list($f1d1, $f1p1) = $this->generator->post_to_forum($forum1, $author); $f1p1reply = $this->generator->post_to_discussion($forum1, $f1d1, $author); @@ -432,101 +422,67 @@ public function test_user_read_posts(): void { $f3p1reply = $this->generator->post_to_discussion($forum3, $f3d1, $author); $f3d1 = $DB->get_record('moodleoverflow_discussions', ['id' => $f3d1->id]); list($f3d2, $f3p2) = $this->generator->post_to_forum($forum3, $author); - list($f4d1, $f4p1) = $this->generator->post_to_forum($forum4, $author); - $f4p1reply = $this->generator->post_to_discussion($forum4, $f4d1, $author); - $f4d1 = $DB->get_record('moodleoverflow_discussions', ['id' => $f4d1->id]); - list($f4d2, $f4p2) = $this->generator->post_to_forum($forum4, $author); + // Insert read info. // User has read post1, but not the reply or second post in forum1. - \mod_moodleoverflow\readtracking::moodleoverflow_add_read_record($user->id, $f1p1->id); + readtracking::moodleoverflow_add_read_record($user->id, $f1p1->id); // User has read post1 and its reply, but not the second post in forum2. - \mod_moodleoverflow\readtracking::moodleoverflow_add_read_record($user->id, $f2p1->id); - \mod_moodleoverflow\readtracking::moodleoverflow_add_read_record($user->id, $f2p1reply->id); + readtracking::moodleoverflow_add_read_record($user->id, $f2p1->id); + readtracking::moodleoverflow_add_read_record($user->id, $f2p1reply->id); // User has read post2 in forum3. - \mod_moodleoverflow\readtracking::moodleoverflow_add_read_record($user->id, $f3p2->id); + readtracking::moodleoverflow_add_read_record($user->id, $f3p2->id); // Nothing has been read in forum4. // Run as the user under test. $this->setUser($user); // Retrieve all contexts - should be three - forum4 has no data. $contextlist = $this->get_contexts_for_userid($user->id, 'mod_moodleoverflow'); $this->assertCount(3, $contextlist); - $contextids = [ - $context1->id, - $context2->id, - $context3->id, - ]; + $contextids = [$context1->id, $context2->id, $context3->id]; sort($contextids); $contextlistids = $contextlist->get_contextids(); sort($contextlistids); $this->assertEquals($contextids, $contextlistids); // Forum 1. $this->export_context_data_for_user($user->id, $context1, 'mod_moodleoverflow'); - $writer = \core_privacy\local\request\writer::with_context($context1); + $writer = writer::with_context($context1); // User has read f1p1. - $readdata = $writer->get_metadata( - data_export_helper::get_subcontext($f1d1, $f1p1), - 'postread' - ); + $readdata = $writer->get_metadata(data_export_helper::get_subcontext($f1d1, $f1p1), 'postread'); $this->assertNotEmpty($readdata); $this->assertTrue(isset($readdata->firstread)); $this->assertTrue(isset($readdata->lastread)); // User has not f1p1reply. - $readdata = $writer->get_metadata( - data_export_helper::get_subcontext($f1d1, $f1p1reply), - 'postread' - ); + $readdata = $writer->get_metadata(data_export_helper::get_subcontext($f1d1, $f1p1reply), 'postread'); $this->assertEmpty($readdata); // User has not f1p2. - $readdata = $writer->get_metadata( - data_export_helper::get_subcontext($f1d2, $f1p2), - 'postread' - ); + $readdata = $writer->get_metadata(data_export_helper::get_subcontext($f1d2, $f1p2), 'postread'); $this->assertEmpty($readdata); // Forum 2. $this->export_context_data_for_user($user->id, $context2, 'mod_moodleoverflow'); - $writer = \core_privacy\local\request\writer::with_context($context2); + $writer = writer::with_context($context2); // User has read f2p1. - $readdata = $writer->get_metadata( - data_export_helper::get_subcontext($f2d1, $f2p1), - 'postread' - ); + $readdata = $writer->get_metadata(data_export_helper::get_subcontext($f2d1, $f2p1), 'postread'); $this->assertNotEmpty($readdata); $this->assertTrue(isset($readdata->firstread)); $this->assertTrue(isset($readdata->lastread)); // User has read f2p1reply. - $readdata = $writer->get_metadata( - data_export_helper::get_subcontext($f2d1, $f2p1reply), - 'postread' - ); + $readdata = $writer->get_metadata(data_export_helper::get_subcontext($f2d1, $f2p1reply), 'postread'); $this->assertNotEmpty($readdata); $this->assertTrue(isset($readdata->firstread)); $this->assertTrue(isset($readdata->lastread)); // User has not read f2p2. - $readdata = $writer->get_metadata( - data_export_helper::get_subcontext($f2d2, $f2p2), - 'postread' - ); + $readdata = $writer->get_metadata(data_export_helper::get_subcontext($f2d2, $f2p2), 'postread'); $this->assertEmpty($readdata); // Forum 3. $this->export_context_data_for_user($user->id, $context3, 'mod_moodleoverflow'); - $writer = \core_privacy\local\request\writer::with_context($context3); + $writer = writer::with_context($context3); // User has not read f3p1. - $readdata = $writer->get_metadata( - data_export_helper::get_subcontext($f3d1, $f3p1), - 'postread' - ); + $readdata = $writer->get_metadata(data_export_helper::get_subcontext($f3d1, $f3p1), 'postread'); $this->assertEmpty($readdata); // User has not read f3p1reply. - $readdata = $writer->get_metadata( - data_export_helper::get_subcontext($f3d1, $f3p1reply), - 'postread' - ); + $readdata = $writer->get_metadata(data_export_helper::get_subcontext($f3d1, $f3p1reply), 'postread'); $this->assertEmpty($readdata); // User has read f3p2. - $readdata = $writer->get_metadata( - data_export_helper::get_subcontext($f3d2, $f3p2), - 'postread' - ); + $readdata = $writer->get_metadata(data_export_helper::get_subcontext($f3d2, $f3p2), 'postread'); $this->assertNotEmpty($readdata); $this->assertTrue(isset($readdata->firstread)); $this->assertTrue(isset($readdata->lastread)); @@ -539,45 +495,34 @@ public function test_post_attachment_inclusion(): void { global $DB; $fs = get_file_storage(); $course = $this->getDataGenerator()->create_course(); - list($author, $otheruser) = $this->create_users($course, 2); - $forum = $this->getDataGenerator()->create_module('moodleoverflow', [ - 'course' => $course->id, - 'scale' => 100, - ]); + list($author) = $this->create_users($course, 2); + $forum = $this->getDataGenerator()->create_module('moodleoverflow', ['course' => $course->id, 'scale' => 100]); $cm = get_coursemodule_from_instance('moodleoverflow', $forum->id); $context = \context_module::instance($cm->id); // Create a new discussion + post in the forum. list($discussion, $post) = $this->generator->post_to_forum($forum, $author); $discussion = $DB->get_record('moodleoverflow_discussions', ['id' => $discussion->id]); // Add a number of replies. + $this->generator->reply_to_post($post, $author); $reply = $this->generator->reply_to_post($post, $author); - $reply = $this->generator->reply_to_post($post, $author); - $reply = $this->generator->reply_to_post($reply, $author); - $posts[$reply->id] = $reply; + $this->generator->reply_to_post($reply, $author); // Add a fake inline image to the original post. - $createdfile = $fs->create_file_from_string([ - 'contextid' => $context->id, - 'component' => 'mod_moodleoverflow', - 'filearea' => 'attachment', - 'itemid' => $post->id, - 'filepath' => '/', - 'filename' => 'example.jpg', - ], - 'image contents (not really)'); + $createdfile = $fs->create_file_from_string(['contextid' => $context->id, 'component' => 'mod_moodleoverflow', + 'filearea' => 'attachment', 'itemid' => $post->id, 'filepath' => '/', 'filename' => 'example.jpg', ], + 'image contents (not really)'); // Create a second discussion + post in the forum without tags. - list($otherdiscussion, $otherpost) = $this->generator->post_to_forum($forum, $author); - $otherdiscussion = $DB->get_record('moodleoverflow_discussions', ['id' => $otherdiscussion->id]); + list(, $otherpost) = $this->generator->post_to_forum($forum, $author); // Add a number of replies. - $reply = $this->generator->reply_to_post($otherpost, $author); - $reply = $this->generator->reply_to_post($otherpost, $author); + $this->generator->reply_to_post($otherpost, $author); + $this->generator->reply_to_post($otherpost, $author); // Run as the user under test. $this->setUser($author); // Retrieve all contexts - should be one. $contextlist = $this->get_contexts_for_userid($author->id, 'mod_moodleoverflow'); $this->assertCount(1, $contextlist); $this->export_context_data_for_user($author->id, $context, 'mod_moodleoverflow'); - $writer = \core_privacy\local\request\writer::with_context($context); + $writer = writer::with_context($context); // The inline file should be on the first forum post. $subcontext = data_export_helper::get_subcontext($discussion, $post); $foundfiles = $writer->get_files($subcontext); @@ -587,6 +532,8 @@ public function test_post_attachment_inclusion(): void { /** * Ensure that all user data is deleted from a context. + * + * @return void */ public function test_all_users_deleted_from_context(): void { global $DB; @@ -596,10 +543,7 @@ public function test_all_users_deleted_from_context(): void { $forums = []; $contexts = []; for ($i = 0; $i < 2; $i++) { - $forum = $this->getDataGenerator()->create_module('moodleoverflow', [ - 'course' => $course->id, - 'scale' => 100, - ]); + $forum = $this->getDataGenerator()->create_module('moodleoverflow', ['course' => $course->id, 'scale' => 100]); $cm = get_coursemodule_from_instance('moodleoverflow', $forum->id); $context = \context_module::instance($cm->id); $forums[$forum->id] = $forum; @@ -623,14 +567,9 @@ public function test_all_users_deleted_from_context(): void { $reply = $this->generator->reply_to_post($reply, $user); $posts[$reply->id] = $reply; // Add a fake inline image to the original post. - $fs->create_file_from_string([ - 'contextid' => $context->id, - 'component' => 'mod_moodleoverflow', - 'filearea' => 'attachment', - 'itemid' => $post->id, - 'filepath' => '/', - 'filename' => 'example.jpg', - ], 'image contents (not really)'); + $fs->create_file_from_string(['contextid' => $context->id, 'component' => 'mod_moodleoverflow', + 'filearea' => 'attachment', 'itemid' => $post->id, 'filepath' => '/', + 'filename' => 'example.jpg', ], 'image contents (not really)'); } } // Mark all posts as read by user. @@ -639,13 +578,11 @@ public function test_all_users_deleted_from_context(): void { foreach ($posts as $post) { $discussion = $discussions[$post->discussion]; $forum = $forums[$discussion->moodleoverflow]; - $context = $contexts[$forum->id]; // Mark the post as being read by user. - \mod_moodleoverflow\readtracking::moodleoverflow_add_read_record($user->id, $post->id); + readtracking::moodleoverflow_add_read_record($user->id, $post->id); // Rate the other users content. if ($post->userid != $user->id) { $ratedposts[$post->id] = $post; - $rating = []; $rating['moodleoverflowid'] = $forum->id; $rating['discussionid'] = $discussion->id; @@ -714,16 +651,17 @@ public function test_all_users_deleted_from_context(): void { } // Ratings should not have been deleted. foreach ($postsinforum as $post) { - if (!isset($ratedposts[$post->id])) { - continue; + if (isset($ratedposts[$post->id])) { + $ratings = $DB->get_records('moodleoverflow_ratings', ['postid' => $post->id]); + $this->assertNotEmpty($ratings); } - $ratings = $DB->get_records('moodleoverflow_ratings', ['postid' => $post->id]); - $this->assertNotEmpty($ratings); } } /** * Ensure that all user data is deleted for a specific context. + * + * @return void */ public function test_delete_data_for_user(): void { global $DB; @@ -733,10 +671,7 @@ public function test_delete_data_for_user(): void { $forums = []; $contexts = []; for ($i = 0; $i < 2; $i++) { - $forum = $this->getDataGenerator()->create_module('moodleoverflow', [ - 'course' => $course->id, - 'scale' => 100, - ]); + $forum = $this->getDataGenerator()->create_module('moodleoverflow', ['course' => $course->id, 'scale' => 100]); $cm = get_coursemodule_from_instance('moodleoverflow', $forum->id); $context = \context_module::instance($cm->id); $forums[$forum->id] = $forum; @@ -756,7 +691,6 @@ public function test_delete_data_for_user(): void { $postsbyforum[$user->id][$context->id] = []; // Add a number of replies. $posts[$post->id] = $post; - $thisforumposts[$post->id] = $post; $postsbyforum[$user->id][$context->id][$post->id] = $post; $reply = $this->generator->reply_to_post($post, $user); $posts[$reply->id] = $reply; @@ -783,20 +717,16 @@ public function test_delete_data_for_user(): void { foreach ($posts as $post) { $discussion = $discussions[$post->discussion]; $forum = $forums[$discussion->moodleoverflow]; - $context = $contexts[$forum->id]; // Mark the post as being read by user1. - \mod_moodleoverflow\readtracking::moodleoverflow_add_read_record($user1->id, $post->id); + readtracking::moodleoverflow_add_read_record($user1->id, $post->id); } // Rate and tag all posts. - $ratedposts = []; foreach ($users as $user) { foreach ($posts as $post) { $discussion = $discussions[$post->discussion]; $forum = $forums[$discussion->moodleoverflow]; - $context = $contexts[$forum->id]; // Rate the other users content. if ($post->userid != $user->id) { - $ratedposts[$post->id] = $post; $rating = []; $rating['moodleoverflowid'] = $forum->id; @@ -840,9 +770,7 @@ public function test_delete_data_for_user(): void { // All posts should remain. $this->assertCount(40, $DB->get_records('moodleoverflow_posts')); // There should be 4 posts belonging to user1 that were not deleted. - $this->assertCount(4, $DB->get_records('moodleoverflow_posts', [ - 'userid' => $user1->id, - ])); + $this->assertCount(4, $DB->get_records('moodleoverflow_posts', ['userid' => $user1->id])); // Four of those posts should have been marked as deleted. // That means that the user ID is null and the message is empty. $this->assertCount(4, $DB->get_records_select('moodleoverflow_posts', "userid = :userid" @@ -853,19 +781,13 @@ public function test_delete_data_for_user(): void { ])); // Only user1's posts should have been marked this way. - $this->assertCount(4, $DB->get_records('moodleoverflow_posts', [ - 'userid' => 0, - ])); + $this->assertCount(4, $DB->get_records('moodleoverflow_posts', ['userid' => 0])); $this->assertCount(4, $DB->get_records_select('moodleoverflow_posts', - $DB->sql_compare_text('message') . " = " . $DB->sql_compare_text(':message'), [ - 'message' => '', - ])); + $DB->sql_compare_text('message') . " = " . $DB->sql_compare_text(':message'), ['message' => ''])); + // Only the posts in the first discussion should have been marked this way. - $this->assertCount(4, $DB->get_records_select('moodleoverflow_posts', - "userid = :userid AND id {$postinsql}", - array_merge($postinparams, [ - 'userid' => 0, - ]) + $this->assertCount(4, $DB->get_records_select('moodleoverflow_posts', "userid = :userid AND id {$postinsql}", + array_merge($postinparams, ['userid' => 0]) )); // Ratings should have been anonymized. @@ -925,7 +847,7 @@ protected function create_users($course, $count) { * * @return array The users created */ - protected function create_and_enrol_users($course, $count) { + protected function create_and_enrol_users($course, $count): array { $users = []; for ($i = 0; $i < $count; $i++) { $users[$i] = $this->getDataGenerator()->create_user(); @@ -937,6 +859,8 @@ protected function create_and_enrol_users($course, $count) { /** * Ensure that user data for specific users is deleted from a specified context. + * + * @return void */ public function test_delete_data_for_users(): void { global $DB; @@ -962,13 +886,12 @@ public function test_delete_data_for_users(): void { $discussions = []; $posts = []; - $postsbymoodleoverflow = []; + $postsbyforum = []; // Foreach of the 5 users and foreach of the two Moodleoverflows a post and discussion is created. // Additionally, 3 replies to each discussion are created. - // Last but not least the original post gets a fake image and attachement. - $counter = 0; + // Last but not least the original post gets a fake image and attachment. foreach ($users as $user) { - $postsbymoodleoverflow[$user->id] = []; + $postsbyforum[$user->id] = []; foreach ($moodleoverflows as $moodleoverflow) { $context = $contexts[$moodleoverflow->id]; @@ -977,24 +900,23 @@ public function test_delete_data_for_users(): void { $discussion = $DB->get_record('moodleoverflow_discussions', ['id' => $discussion->id]); $discussions[$discussion->id] = $discussion; - $postsbymoodleoverflow[$user->id][$context->id] = []; + $postsbyforum[$user->id][$context->id] = []; // Add a number of replies. $posts[$post->id] = $post; - $thismoodleoverflowposts[$post->id] = $post; - $postsbymoodleoverflow[$user->id][$context->id][$post->id] = $post; + $postsbyforum[$user->id][$context->id][$post->id] = $post; $reply = $this->generator->reply_to_post($post, $user); $posts[$reply->id] = $reply; - $postsbymoodleoverflow[$user->id][$context->id][$reply->id] = $reply; + $postsbyforum[$user->id][$context->id][$reply->id] = $reply; $reply = $this->generator->reply_to_post($post, $user); $posts[$reply->id] = $reply; - $postsbymoodleoverflow[$user->id][$context->id][$reply->id] = $reply; + $postsbyforum[$user->id][$context->id][$reply->id] = $reply; $reply = $this->generator->reply_to_post($reply, $user); $posts[$reply->id] = $reply; - $postsbymoodleoverflow[$user->id][$context->id][$reply->id] = $reply; + $postsbyforum[$user->id][$context->id][$reply->id] = $reply; // Add a fake inline image to the original post. $fs->create_file_from_string([ @@ -1021,11 +943,10 @@ public function test_delete_data_for_users(): void { $user1 = reset($users); foreach ($posts as $post) { // Mark the post as being read by user1. - \mod_moodleoverflow\readtracking::moodleoverflow_add_read_record($user1->id, $post->id); + readtracking::moodleoverflow_add_read_record($user1->id, $post->id); } // Rate all posts (Every user every post). - foreach ($users as $user) { foreach ($posts as $post) { $discussion = $discussions[$post->discussion]; @@ -1033,15 +954,9 @@ public function test_delete_data_for_users(): void { if ($post->userid != $user->id) { $time = time(); - $rating = (object) [ - 'userid' => $user->id, - 'postid' => $post->id, - 'discussionid' => $discussion->id, - 'moodleoverflowid' => $moodleoverflow->id, - 'rating' => 1, - 'firstrated' => $time, - 'lastchanged' => $time, - ]; + $rating = (object) ['userid' => $user->id, 'postid' => $post->id, 'discussionid' => $discussion->id, + 'moodleoverflowid' => $moodleoverflow->id, 'rating' => 1, 'firstrated' => $time, + 'lastchanged' => $time, ]; // Inserts a rating into the table. $DB->insert_record('moodleoverflow_ratings', $rating); } @@ -1051,7 +966,7 @@ public function test_delete_data_for_users(): void { // Delete for one of the moodleoverflows all post for the first user. $firstcontext = reset($contexts); - $approveduserlist = new \core_privacy\local\request\approved_userlist($firstcontext, 'mod_moodleoverflow', [$user1->id]); + $approveduserlist = new approved_userlist($firstcontext, 'mod_moodleoverflow', [$user1->id]); provider::delete_data_for_users($approveduserlist); // All posts should remain (5 user * 2 Moodleoverflows * 4 Post per Moodleoverflow). @@ -1059,9 +974,7 @@ public function test_delete_data_for_users(): void { // User 1 posted in every Moodleoverflow 4 post (8). // Post from the first Moodleoverflow are made anonymous. - $this->assertCount(4, $DB->get_records('moodleoverflow_posts', [ - 'userid' => $user1->id, - ])); + $this->assertCount(4, $DB->get_records('moodleoverflow_posts', ['userid' => $user1->id])); // All of the post from moodleoverflow 1 should have been filed with empty values. // That means the userid equals 0, message equals empty string, and message format equals FORMAT_PLAIN. @@ -1077,8 +990,7 @@ public function test_delete_data_for_users(): void { // Ratings were made anonymous from the affected posts. // All ratings from user1 in Moodleoverflow1 should have been deleted so 16 entries should be anonymous. // (20 post in Moodleoverflow -4 post belonging to user 1). - $this->assertCount(16, $DB->get_records_select('moodleoverflow_ratings', "userid = :userid" - , ['userid' => 0 ])); + $this->assertCount(16, $DB->get_records_select('moodleoverflow_ratings', "userid = :userid" , ['userid' => 0 ])); // All ratings should still exist (2 Moodleoverflows * 5 users * 16 post from other people). $this->assertCount(160, $DB->get_records('moodleoverflow_ratings')); @@ -1088,9 +1000,7 @@ public function test_delete_data_for_users(): void { // User 1 posted in every Moodleoverflow 1 discussion. // Discussion from the first Moodleoverflow are made anonymous. - $this->assertCount(1, $DB->get_records('moodleoverflow_discussions', [ - 'userid' => $user1->id, - ])); + $this->assertCount(1, $DB->get_records('moodleoverflow_discussions', ['userid' => $user1->id])); // All of the discussions from moodleoverflow 1 should have been filed with empty values. // That means the userid equals 0, and name equals empty string. @@ -1104,7 +1014,7 @@ public function test_delete_data_for_users(): void { // Get all the post ids where files should be deleted. $deletedpostids = []; $otherpostids = []; - foreach ($postsbymoodleoverflow as $user => $contexts) { + foreach ($postsbyforum as $user => $contexts) { foreach ($contexts as $thiscontextid => $theseposts) { $thesepostids = array_map(function($post) { return $post->id; @@ -1134,21 +1044,18 @@ public function test_delete_data_for_users(): void { * Ensure that the discussion author is listed as a user in the context. */ public function test_get_users_in_context_post_author(): void { - global $DB; - $component = 'mod_moodleoverflow'; - $course = $this->getDataGenerator()->create_course(); $moodleoverflow = $this->getDataGenerator()->create_module('moodleoverflow', ['course' => $course->id]); $cm = get_coursemodule_from_instance('moodleoverflow', $moodleoverflow->id); $context = \context_module::instance($cm->id); - list($author, $user) = $this->create_users($course, 2); + list($author) = $this->create_users($course, 2); - list($fd1, $fp1) = $this->generator->post_to_forum($moodleoverflow, $author); + $this->generator->post_to_forum($moodleoverflow, $author); - $userlist = new \core_privacy\local\request\userlist($context, $component); - \mod_moodleoverflow\privacy\provider::get_users_in_context($userlist); + $userlist = new userlist($context, 'moodleoverflow'); + provider::get_users_in_context($userlist); // There should only be one user in the list. $this->assertCount(1, $userlist); @@ -1160,33 +1067,26 @@ public function test_get_users_in_context_post_author(): void { */ public function test_get_users_in_context_post_authors(): void { global $DB; - $component = 'mod_moodleoverflow'; - $course = $this->getDataGenerator()->create_course(); $moodleoverflow = $this->getDataGenerator()->create_module('moodleoverflow', ['course' => $course->id]); $cm = get_coursemodule_from_instance('moodleoverflow', $moodleoverflow->id); $context = \context_module::instance($cm->id); - list($author, $user, $other) = $this->create_users($course, 3); + list($author, $user) = $this->create_users($course, 3); - list($fd1, $fp1) = $this->generator->post_to_forum($moodleoverflow, $author); - $fp1reply = $this->generator->post_to_discussion($moodleoverflow, $fd1, $user); - $fd1 = $DB->get_record('moodleoverflow_discussions', ['id' => $fd1->id]); + list($fd1) = $this->generator->post_to_forum($moodleoverflow, $author); + $this->generator->post_to_discussion($moodleoverflow, $fd1, $user); + $DB->get_record('moodleoverflow_discussions', ['id' => $fd1->id]); - $userlist = new \core_privacy\local\request\userlist($context, $component); - \mod_moodleoverflow\privacy\provider::get_users_in_context($userlist); + $userlist = new userlist($context, 'mod_moodleoverflow'); + provider::get_users_in_context($userlist); // Two users - author and replier. $this->assertCount(2, $userlist); - $expected = [$author->id, $user->id]; - sort($expected); - $actual = $userlist->get_userids(); - sort($actual); - - $this->assertEquals($expected, $actual); + $this->assertEquals(sort($expected), sort($actual)); } /** @@ -1195,226 +1095,157 @@ public function test_get_users_in_context_post_authors(): void { */ public function test_get_users_in_context_post_ratings(): void { global $DB; - $component = 'mod_moodleoverflow'; - $course = $this->getDataGenerator()->create_course(); $moodleoverflow = $this->getDataGenerator()->create_module('moodleoverflow', ['course' => $course->id]); $cm = get_coursemodule_from_instance('moodleoverflow', $moodleoverflow->id); $context = \context_module::instance($cm->id); - - list($author, $user, $other) = $this->create_users($course, 3); - + list($author, $user) = $this->create_users($course, 3); list($fd1, $fp1) = $this->generator->post_to_forum($moodleoverflow, $author); $time = time(); - $rating = (object) [ - 'userid' => $user->id, - 'postid' => $fp1->id, - 'discussionid' => $fd1->id, - 'moodleoverflowid' => $moodleoverflow->id, - 'rating' => 1, - 'firstrated' => $time, - 'lastchanged' => $time, - ]; + $rating = (object) ['userid' => $user->id, 'postid' => $fp1->id, 'discussionid' => $fd1->id, + 'moodleoverflowid' => $moodleoverflow->id, 'rating' => 1, 'firstrated' => $time, + 'lastchanged' => $time, ]; + // Inserts a rating into the table. $DB->insert_record('moodleoverflow_ratings', $rating); - $userlist = new \core_privacy\local\request\userlist($context, $component); - \mod_moodleoverflow\privacy\provider::get_users_in_context($userlist); + $userlist = new userlist($context, 'mod_moodleoverflow'); + provider::get_users_in_context($userlist); // Two users - author and rater. $this->assertCount(2, $userlist); - $expected = [$author->id, $user->id]; - sort($expected); - $actual = $userlist->get_userids(); - sort($actual); - $this->assertEquals($expected, $actual); + $this->assertEquals(sort($expected), sort($actual)); } /** * Ensure that all users with a moodleoverflow subscription preference included as a user in the context. */ public function test_get_users_in_context_with_subscription(): void { - global $DB; - $component = 'mod_moodleoverflow'; - $course = $this->getDataGenerator()->create_course(); - $moodleoverflow = $this->getDataGenerator()->create_module('moodleoverflow', ['course' => $course->id]); $cm = get_coursemodule_from_instance('moodleoverflow', $moodleoverflow->id); $context = \context_module::instance($cm->id); - - $othermoodleoverflow = $this->getDataGenerator()->create_module('moodleoverflow', ['course' => $course->id]); - $othercm = get_coursemodule_from_instance('moodleoverflow', $othermoodleoverflow->id); - $othercontext = \context_module::instance($othercm->id); - - list($user, $otheruser) = $this->create_users($course, 2); + list($user) = $this->create_users($course, 2); // Subscribe the user to the moodleoverflow. - \mod_moodleoverflow\subscriptions::subscribe_user($user->id, $moodleoverflow, $context); - - $userlist = new \core_privacy\local\request\userlist($context, $component); - \mod_moodleoverflow\privacy\provider::get_users_in_context($userlist); + subscriptions::subscribe_user($user->id, $moodleoverflow, $context); + $userlist = new userlist($context, 'mod_moodleoverflow'); + provider::get_users_in_context($userlist); // One user - the one with a digest preference. $this->assertCount(1, $userlist); - $expected = [$user->id]; - sort($expected); - $actual = $userlist->get_userids(); - sort($actual); - - $this->assertEquals($expected, $actual); + $this->assertEquals(sort($expected), sort($actual)); } /** * Ensure that all users with a per-discussion subscription preference included as a user in the context. */ public function test_get_users_in_context_with_discussion_subscription(): void { - $component = 'mod_moodleoverflow'; - $course = $this->getDataGenerator()->create_course(); - $moodleoverflow = $this->getDataGenerator()->create_module('moodleoverflow', ['course' => $course->id]); $cm = get_coursemodule_from_instance('moodleoverflow', $moodleoverflow->id); $context = \context_module::instance($cm->id); - $othermoodleoverflow = $this->getDataGenerator()->create_module('moodleoverflow', ['course' => $course->id]); - list($author, $user, $otheruser) = $this->create_users($course, 3); // Post in both of the moodleoverflows. - list($fd1, $fp1) = $this->generator->post_to_forum($moodleoverflow, $author); - list($ofd1, $ofp1) = $this->generator->post_to_forum($othermoodleoverflow, $author); + list($fd1) = $this->generator->post_to_forum($moodleoverflow, $author); + list($ofd1) = $this->generator->post_to_forum($othermoodleoverflow, $author); // Subscribe the user to the discussions. - \mod_moodleoverflow\subscriptions::subscribe_user_to_discussion($user->id, $fd1, $context); - \mod_moodleoverflow\subscriptions::subscribe_user_to_discussion($otheruser->id, $ofd1, $context); + subscriptions::subscribe_user_to_discussion($user->id, $fd1, $context); + subscriptions::subscribe_user_to_discussion($otheruser->id, $ofd1, $context); - $userlist = new \core_privacy\local\request\userlist($context, $component); - \mod_moodleoverflow\privacy\provider::get_users_in_context($userlist); + $userlist = new userlist($context, 'mod_moodleoverflow'); + provider::get_users_in_context($userlist); // Two users - the author, and the one who subscribed. $this->assertCount(2, $userlist); - $expected = [$author->id, $user->id]; - sort($expected); - $actual = $userlist->get_userids(); - sort($actual); - - $this->assertEquals($expected, $actual); + $this->assertEquals(sort($expected), sort($actual)); } /** * Ensure that all users with read tracking are included as a user in the context. */ public function test_get_users_in_context_with_read_post_tracking(): void { - $component = 'mod_moodleoverflow'; - $course = $this->getDataGenerator()->create_course(); - $moodleoverflow = $this->getDataGenerator()->create_module('moodleoverflow', ['course' => $course->id]); $cm = get_coursemodule_from_instance('moodleoverflow', $moodleoverflow->id); - $context = \context_module::instance($cm->id); $othermoodleoverflow = $this->getDataGenerator()->create_module('moodleoverflow', ['course' => $course->id]); $othercm = get_coursemodule_from_instance('moodleoverflow', $othermoodleoverflow->id); - $othercontext = \context_module::instance($othercm->id); - list($author, $user, $otheruser) = $this->create_users($course, 3); // Post in both of the moodleoverflows. - list($fd1, $fp1) = $this->generator->post_to_forum($moodleoverflow, $author); - list($ofd1, $ofp1) = $this->generator->post_to_forum($othermoodleoverflow, $author); + list(, $fp1) = $this->generator->post_to_forum($moodleoverflow, $author); + list(, $ofp1) = $this->generator->post_to_forum($othermoodleoverflow, $author); // Add read information for those users. - \mod_moodleoverflow\readtracking::moodleoverflow_add_read_record($user->id, $fp1->id); - \mod_moodleoverflow\readtracking::moodleoverflow_add_read_record($otheruser->id, $ofp1->id); + readtracking::moodleoverflow_add_read_record($user->id, $fp1->id); + readtracking::moodleoverflow_add_read_record($otheruser->id, $ofp1->id); - $userlist = new \core_privacy\local\request\userlist($context, $component); - \mod_moodleoverflow\privacy\provider::get_users_in_context($userlist); + $userlist = new userlist(\context_module::instance($cm->id), 'mod_moodleoverflow'); + provider::get_users_in_context($userlist); // Two user - the author, and the one who has read the post. $this->assertCount(2, $userlist); - $expected = [$author->id, $user->id]; - sort($expected); - $actual = $userlist->get_userids(); - sort($actual); - - $this->assertEquals($expected, $actual); + $this->assertEquals(sort($expected), sort($actual)); // Testing again for the other context. - $userlist = new \core_privacy\local\request\userlist($othercontext, $component); - \mod_moodleoverflow\privacy\provider::get_users_in_context($userlist); + $userlist = new userlist(\context_module::instance($othercm->id), 'mod_moodleoverflow'); + provider::get_users_in_context($userlist); // Two user - the author, and the one who has read the post. $this->assertCount(2, $userlist); - $expected = [$author->id, $otheruser->id]; - sort($expected); - $actual = $userlist->get_userids(); - sort($actual); - - $this->assertEquals($expected, $actual); + $this->assertEquals(sort($expected), sort($actual)); } /** * Ensure that all users with tracking preferences are included as a user in the context. */ public function test_get_users_in_context_with_tracking_preferences(): void { - global $DB; - $component = 'mod_moodleoverflow'; - $course = $this->getDataGenerator()->create_course(); - $moodleoverflow = $this->getDataGenerator()->create_module('moodleoverflow', ['course' => $course->id]); $cm = get_coursemodule_from_instance('moodleoverflow', $moodleoverflow->id); - $context = \context_module::instance($cm->id); $othermoodleoverflow = $this->getDataGenerator()->create_module('moodleoverflow', ['course' => $course->id]); $othercm = get_coursemodule_from_instance('moodleoverflow', $othermoodleoverflow->id); $othercontext = \context_module::instance($othercm->id); - - list($author, $user, $otheruser) = $this->create_users($course, 3); + list(, $user, $otheruser) = $this->create_users($course, 3); // Stop tracking the read posts. - \mod_moodleoverflow\readtracking::moodleoverflow_stop_tracking($moodleoverflow->id, $user->id); - \mod_moodleoverflow\readtracking::moodleoverflow_stop_tracking($othermoodleoverflow->id, $otheruser->id); + readtracking::moodleoverflow_stop_tracking($moodleoverflow->id, $user->id); + readtracking::moodleoverflow_stop_tracking($othermoodleoverflow->id, $otheruser->id); - $userlist = new \core_privacy\local\request\userlist($context, $component); - \mod_moodleoverflow\privacy\provider::get_users_in_context($userlist); + $userlist = new userlist(\context_module::instance($cm->id), 'mod_moodleoverflow'); + provider::get_users_in_context($userlist); // One user - the one who is tracking that moodleoverflow. $this->assertCount(1, $userlist); $expected = [$user->id]; - sort($expected); - $actual = $userlist->get_userids(); - sort($actual); - - $this->assertEquals($expected, $actual); + $this->assertEquals(sort($expected), sort($actual)); // Testing the other context. - $userlist = new \core_privacy\local\request\userlist($othercontext, $component); - \mod_moodleoverflow\privacy\provider::get_users_in_context($userlist); + $userlist = new userlist($othercontext, 'mod_moodleoverflow'); + provider::get_users_in_context($userlist); // One user - the one who is tracking that moodleoverflow. $this->assertCount(1, $userlist); - $expected = [$otheruser->id]; - sort($expected); - $actual = $userlist->get_userids(); - sort($actual); - - $this->assertEquals($expected, $actual); + $this->assertEquals(sort($expected), sort($actual)); } /** @@ -1426,28 +1257,23 @@ public function test_grades(): void { global $DB; $course = self::getDataGenerator()->create_course(); - $forum = self::getDataGenerator()->create_module('moodleoverflow', [ - 'course' => $course->id, - 'scale' => 100, - 'grademaxgrade' => 50, - 'gradescalefactor' => 2, - ]); + $forum = self::getDataGenerator()->create_module('moodleoverflow', ['course' => $course->id, 'scale' => 100, + 'grademaxgrade' => 50, 'gradescalefactor' => 2, ]); $cm = get_coursemodule_from_instance('moodleoverflow', $forum->id); $context = \context_module::instance($cm->id); list($user, $user2) = $this->create_and_enrol_users($course, 2); list( , $post) = $this->generator->post_to_forum($forum, $user); - \mod_moodleoverflow\ratings::moodleoverflow_add_rating($forum, $post->id, RATING_UPVOTE, $cm, $user2->id); + ratings::moodleoverflow_add_rating($forum, $post->id, RATING_UPVOTE, $cm, $user2->id); moodleoverflow_update_all_grades_for_cm($forum->id); - $grades = grade_get_grades($course->id, 'mod', 'moodleoverflow', $forum->id, - [$user->id, $user2->id]); + $grades = grade_get_grades($course->id, 'mod', 'moodleoverflow', $forum->id, [$user->id, $user2->id]); self::assertEquals("2.50", $grades->items[0]->grades[$user->id]->str_grade); self::assertEquals("0.50", $grades->items[0]->grades[$user2->id]->str_grade); // Test export. $this->export_context_data_for_user($user->id, $context, 'mod_moodleoverflow'); - $writer = \core_privacy\local\request\writer::with_context($context); - $metadata = $writer->get_all_metadata([]); + $writer = writer::with_context($context); + $metadata = $writer->get_all_metadata(); self::assertArrayHasKey('grade', $metadata); self::assertEquals(2.5, $metadata['grade']->value); @@ -1457,16 +1283,13 @@ public function test_grades(): void { self::assertContains("$context->id", $contextlist->get_contextids()); provider::delete_data_for_user($contextlist); moodleoverflow_update_all_grades_for_cm($forum->id); - $grades = $DB->get_records('moodleoverflow_grades', ['moodleoverflowid' => $forum->id], null, - 'userid, grade'); + $grades = $DB->get_records('moodleoverflow_grades', ['moodleoverflowid' => $forum->id], null, 'userid, grade'); self::assertEquals(2.5, $grades[$user->id]->grade); self::assertArrayNotHasKey($user2->id, $grades); // Test delete context. provider::delete_data_for_all_users_in_context($context); moodleoverflow_update_all_grades_for_cm($forum->id); - $grades = $DB->get_records('moodleoverflow_grades', ['moodleoverflowid' => $forum->id], null, - 'userid, grade'); - self::assertEmpty($grades); + self::assertEmpty($DB->get_records('moodleoverflow_grades', ['moodleoverflowid' => $forum->id], null, 'userid, grade')); } } diff --git a/tests/ratings_test.php b/tests/ratings_test.php index 396a9e50c5..479b133674 100644 --- a/tests/ratings_test.php +++ b/tests/ratings_test.php @@ -23,6 +23,7 @@ */ namespace mod_moodleoverflow; use mod_moodleoverflow\ratings; +use stdClass; defined('MOODLE_INTERNAL') || die(); @@ -38,51 +39,28 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ final class ratings_test extends \advanced_testcase { - /** @var \stdClass test course */ - private $course; - /** @var \stdClass coursemodule */ - private $coursemodule; - - /** @var \stdClass test moodleoverflow */ - private $moodleoverflow; - - /** @var \stdClass test teacher */ - private $teacher; - - /** @var \stdClass test user */ - private $user1; - - /** @var \stdClass another test user */ - private $user2; - - /** @var \stdClass a discussion */ - private $discussion; - - /** @var \stdClass a post from the teacher*/ + /** @var stdClass a post from the teacher*/ private $post; - /** @var \stdClass answer from user 1 */ + /** @var stdClass answer from user 1 */ private $answer1; - /** @var \stdClass answer from user 1 */ + /** @var stdClass answer from user 1 */ private $answer2; - /** @var \stdClass answer from user 1 */ + /** @var stdClass answer from user 1 */ private $answer3; - /** @var \stdClass answer from user 2 */ + /** @var stdClass answer from user 2 */ private $answer4; - /** @var \stdClass answer from user 2 */ + /** @var stdClass answer from user 2 */ private $answer5; - /** @var \stdClass answer from user 2 */ + /** @var stdClass answer from user 2 */ private $answer6; - /** @var \mod_moodleoverflow_generator $generator */ - private $generator; - /** * Test setUp. */ @@ -96,8 +74,8 @@ public function setUp(): void { */ public function tearDown(): void { // Clear all caches. - \mod_moodleoverflow\subscriptions::reset_moodleoverflow_cache(); - \mod_moodleoverflow\subscriptions::reset_discussion_cache(); + subscriptions::reset_moodleoverflow_cache(); + subscriptions::reset_discussion_cache(); } // Begin of test functions. @@ -182,40 +160,32 @@ public function test_answersorting_twogroups(): void { $this->set_ratingpreferences(0); // Test case 1: helpful and solved post, only solved posts. - $group1 = 'sh'; - $group2 = 's'; - $this->process_groups($group1, $group2); + $this->process_groups('sh', 's'); // Test case 2: helpful and solved post, only helpful posts. - $group2 = 'h'; - $this->process_groups($group1, $group2); + $this->process_groups('sh', 'h'); // Test case 3: helpful and solved post, not-marked posts. - $group2 = 'o'; - $this->process_groups($group1, $group2); + $this->process_groups('sh', 'o'); // Test case 4: only solved posts and only helpful posts with ratingpreferences = 0. - $group1 = 's'; - $group2 = 'h'; $this->set_ratingpreferences(0); $rightorder = [$this->post, $this->answer6, $this->answer5, $this->answer4, $this->answer2, $this->answer1, $this->answer3]; - $this->process_groups($group1, $group2, $rightorder); + $this->process_groups('s', 'h', $rightorder); // Test case 5: only solved posts and only helpful posts with ratingpreferences = 1. $this->set_ratingpreferences(1); - $this->process_groups($group1, $group2); + $this->process_groups('s', 'h'); // Test case 6: only solved posts and not-marked posts. - $group2 = 'o'; - $this->create_twogroups($group1, $group2); + $this->create_twogroups('s', 'o'); $posts = [$this->post, $this->answer1, $this->answer2, $this->answer3, $this->answer4, $this->answer5, $this->answer6]; $rightorder = [$this->post, $this->answer2, $this->answer1, $this->answer3, $this->answer6, $this->answer5, $this->answer4]; $result = $this->postsorderequal(ratings::moodleoverflow_sort_answers_by_ratings($posts), $rightorder); $this->assertEquals(1, $result); // Test case 6: only helpful posts and not-marked posts. - $group1 = 'h'; - $this->process_groups($group1, $group2); + $this->process_groups('h', 'o'); } /** @@ -232,8 +202,7 @@ public function test_answersorting_onegroup(): void { $this->set_ratingpreferences(0); // Test case 1: only solved and helpful posts. - $group = 'sh'; - $this->create_onegroup($group); + $this->create_onegroup('sh'); $posts = [$this->post, $this->answer1, $this->answer2, $this->answer3, $this->answer4, $this->answer5, $this->answer6]; $rightorder = [$this->post, $this->answer4, $this->answer6, $this->answer3, $this->answer1, $this->answer2, $this->answer5]; $result = $this->postsorderequal(ratings::moodleoverflow_sort_answers_by_ratings($posts), $rightorder); @@ -246,8 +215,7 @@ public function test_answersorting_onegroup(): void { $this->assertEquals(1, $result); // Test case 2: only solvedposts. - $group = 's'; - $this->create_onegroup($group); + $this->create_onegroup('s'); $rightorder = [$this->post, $this->answer4, $this->answer6, $this->answer3, $this->answer1, $this->answer2, $this->answer5]; $result = $this->postsorderequal(ratings::moodleoverflow_sort_answers_by_ratings($posts), $rightorder); $this->assertEquals(1, $result); @@ -259,8 +227,7 @@ public function test_answersorting_onegroup(): void { $this->assertEquals(1, $result); // Test case 3: only helpful posts. - $group = 'h'; - $this->create_onegroup($group); + $this->create_onegroup('h'); $rightorder = [$this->post, $this->answer4, $this->answer6, $this->answer3, $this->answer1, $this->answer2, $this->answer5]; $result = $this->postsorderequal(ratings::moodleoverflow_sort_answers_by_ratings($posts), $rightorder); $this->assertEquals(1, $result); @@ -272,8 +239,7 @@ public function test_answersorting_onegroup(): void { $this->assertEquals(1, $result); // Test case 4: only not marked posts. - $group = 'o'; - $this->create_onegroup($group); + $this->create_onegroup('o'); $rightorder = [$this->post, $this->answer4, $this->answer6, $this->answer3, $this->answer1, $this->answer2, $this->answer5]; $result = $this->postsorderequal(ratings::moodleoverflow_sort_answers_by_ratings($posts), $rightorder); $this->assertEquals(1, $result); @@ -296,31 +262,30 @@ public function test_answersorting_onegroup(): void { private function helper_course_set_up() { global $DB; // Create a new course with a moodleoverflow forum. - $this->course = $this->getDataGenerator()->create_course(); - $location = ['course' => $this->course->id]; - $this->moodleoverflow = $this->getDataGenerator()->create_module('moodleoverflow', $location); - $this->coursemodule = get_coursemodule_from_instance('moodleoverflow', $this->moodleoverflow->id); + $course = $this->getDataGenerator()->create_course(); + $location = ['course' => $course->id]; + $moodleoverflow = $this->getDataGenerator()->create_module('moodleoverflow', $location); // Create a teacher. - $this->teacher = $this->getDataGenerator()->create_user(['firstname' => 'Tamaro', 'lastname' => 'Walter']); - $this->getDataGenerator()->enrol_user($this->teacher->id, $this->course->id, 'student'); + $teacher = $this->getDataGenerator()->create_user(['firstname' => 'Tamaro', 'lastname' => 'Walter']); + $this->getDataGenerator()->enrol_user($teacher->id, $course->id, 'student'); // Create 2 users. - $this->user1 = $this->getDataGenerator()->create_user(['firstname' => 'Ava', 'lastname' => 'Davis']); - $this->getDataGenerator()->enrol_user($this->user1->id, $this->course->id, 'student'); - $this->user2 = $this->getDataGenerator()->create_user(['firstname' => 'Ethan', 'lastname' => 'Brown']); - $this->getDataGenerator()->enrol_user($this->user2->id, $this->course->id, 'student'); + $user1 = $this->getDataGenerator()->create_user(['firstname' => 'Ava', 'lastname' => 'Davis']); + $this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student'); + $user2 = $this->getDataGenerator()->create_user(['firstname' => 'Ethan', 'lastname' => 'Brown']); + $this->getDataGenerator()->enrol_user($user2->id, $course->id, 'student'); // Create a discussion, a parent post and six answers. - $this->generator = $this->getDataGenerator()->get_plugin_generator('mod_moodleoverflow'); - $this->discussion = $this->generator->post_to_forum($this->moodleoverflow, $this->teacher); - $this->post = $DB->get_record('moodleoverflow_posts', ['id' => $this->discussion[0]->firstpost], '*'); - $this->answer1 = $this->generator->reply_to_post($this->discussion[1], $this->user1, true); - $this->answer2 = $this->generator->reply_to_post($this->discussion[1], $this->user1, true); - $this->answer3 = $this->generator->reply_to_post($this->discussion[1], $this->user1, true); - $this->answer4 = $this->generator->reply_to_post($this->discussion[1], $this->user2, true); - $this->answer5 = $this->generator->reply_to_post($this->discussion[1], $this->user2, true); - $this->answer6 = $this->generator->reply_to_post($this->discussion[1], $this->user2, true); + $generator = $this->getDataGenerator()->get_plugin_generator('mod_moodleoverflow'); + $discussion = $generator->post_to_forum($moodleoverflow, $teacher); + $this->post = $DB->get_record('moodleoverflow_posts', ['id' => $discussion[0]->firstpost], '*'); + $this->answer1 = $generator->reply_to_post($discussion[1], $user1, true); + $this->answer2 = $generator->reply_to_post($discussion[1], $user1, true); + $this->answer3 = $generator->reply_to_post($discussion[1], $user1, true); + $this->answer4 = $generator->reply_to_post($discussion[1], $user2, true); + $this->answer5 = $generator->reply_to_post($discussion[1], $user2, true); + $this->answer6 = $generator->reply_to_post($discussion[1], $user2, true); } @@ -335,7 +300,8 @@ private function postsorderequal($sortedposts, $rightorder) { if (count($sortedposts) != count($rightorder)) { return 0; } - for ($i = 0; $i < count($sortedposts); $i++) { + $numberofposts = count($sortedposts); + for ($i = 0; $i < $numberofposts; $i++) { // Get the current elements. $sortedpost = current($sortedposts); $post = current($rightorder); @@ -542,10 +508,10 @@ private function create_twogroups($group1, $group2) { * Executing the sort function and comparing the sorted post to the expected order. * @param String $group1 * @param string $group2 - * @param array|null $orderposts + * @param array $orderposts * @return void */ - private function process_groups(String $group1, string $group2, array $orderposts = null) { + private function process_groups(String $group1, string $group2, array $orderposts = []) { $this->create_twogroups($group1, $group2); $posts = [$this->post, $this->answer1, $this->answer2, $this->answer3, $this->answer4, $this->answer5, $this->answer6]; $rightorder = [$this->post, $this->answer2, $this->answer1, $this->answer3, $this->answer6, $this->answer5, $this->answer4]; diff --git a/tests/subscriptions_test.php b/tests/subscriptions_test.php index 7fe9eae71d..26d653b7a9 100644 --- a/tests/subscriptions_test.php +++ b/tests/subscriptions_test.php @@ -45,8 +45,8 @@ final class subscriptions_test extends advanced_testcase { */ public function setUp(): void { // Clear all caches. - \mod_moodleoverflow\subscriptions::reset_moodleoverflow_cache(); - \mod_moodleoverflow\subscriptions::reset_discussion_cache(); + subscriptions::reset_moodleoverflow_cache(); + subscriptions::reset_discussion_cache(); } /** @@ -54,8 +54,8 @@ public function setUp(): void { */ public function tearDown(): void { // Clear all caches. - \mod_moodleoverflow\subscriptions::reset_moodleoverflow_cache(); - \mod_moodleoverflow\subscriptions::reset_discussion_cache(); + subscriptions::reset_moodleoverflow_cache(); + subscriptions::reset_discussion_cache(); } /** @@ -129,34 +129,34 @@ public function test_subscription_modes(): void { $this->setUser($user); // Test the forced subscription. - \mod_moodleoverflow\subscriptions::set_subscription_mode($moodleoverflow->id, MOODLEOVERFLOW_FORCESUBSCRIBE); + subscriptions::set_subscription_mode($moodleoverflow->id, MOODLEOVERFLOW_FORCESUBSCRIBE); $moodleoverflow = $DB->get_record('moodleoverflow', ['id' => $moodleoverflow->id]); $this->assertEquals(MOODLEOVERFLOW_FORCESUBSCRIBE, - \mod_moodleoverflow\subscriptions::get_subscription_mode($moodleoverflow)); - $this->assertTrue(\mod_moodleoverflow\subscriptions::is_forcesubscribed($moodleoverflow)); - $this->assertFalse(\mod_moodleoverflow\subscriptions::is_subscribable($moodleoverflow, $modulecontext)); - $this->assertFalse(\mod_moodleoverflow\subscriptions::subscription_disabled($moodleoverflow)); + subscriptions::get_subscription_mode($moodleoverflow)); + $this->assertTrue(subscriptions::is_forcesubscribed($moodleoverflow)); + $this->assertFalse(subscriptions::is_subscribable($moodleoverflow, $modulecontext)); + $this->assertFalse(subscriptions::subscription_disabled($moodleoverflow)); // Test the disallowed subscription. - \mod_moodleoverflow\subscriptions::set_subscription_mode($moodleoverflow->id, MOODLEOVERFLOW_DISALLOWSUBSCRIBE); + subscriptions::set_subscription_mode($moodleoverflow->id, MOODLEOVERFLOW_DISALLOWSUBSCRIBE); $moodleoverflow = $DB->get_record('moodleoverflow', ['id' => $moodleoverflow->id]); - $this->assertTrue(\mod_moodleoverflow\subscriptions::subscription_disabled($moodleoverflow)); - $this->assertFalse(\mod_moodleoverflow\subscriptions::is_subscribable($moodleoverflow, $modulecontext)); - $this->assertFalse(\mod_moodleoverflow\subscriptions::is_forcesubscribed($moodleoverflow)); + $this->assertTrue(subscriptions::subscription_disabled($moodleoverflow)); + $this->assertFalse(subscriptions::is_subscribable($moodleoverflow, $modulecontext)); + $this->assertFalse(subscriptions::is_forcesubscribed($moodleoverflow)); // Test the initial subscription. - \mod_moodleoverflow\subscriptions::set_subscription_mode($moodleoverflow->id, MOODLEOVERFLOW_INITIALSUBSCRIBE); + subscriptions::set_subscription_mode($moodleoverflow->id, MOODLEOVERFLOW_INITIALSUBSCRIBE); $moodleoverflow = $DB->get_record('moodleoverflow', ['id' => $moodleoverflow->id]); - $this->assertTrue(\mod_moodleoverflow\subscriptions::is_subscribable($moodleoverflow, $modulecontext)); - $this->assertFalse(\mod_moodleoverflow\subscriptions::subscription_disabled($moodleoverflow)); - $this->assertFalse(\mod_moodleoverflow\subscriptions::is_forcesubscribed($moodleoverflow)); + $this->assertTrue(subscriptions::is_subscribable($moodleoverflow, $modulecontext)); + $this->assertFalse(subscriptions::subscription_disabled($moodleoverflow)); + $this->assertFalse(subscriptions::is_forcesubscribed($moodleoverflow)); // Test the choose subscription. - \mod_moodleoverflow\subscriptions::set_subscription_mode($moodleoverflow->id, MOODLEOVERFLOW_CHOOSESUBSCRIBE); + subscriptions::set_subscription_mode($moodleoverflow->id, MOODLEOVERFLOW_CHOOSESUBSCRIBE); $moodleoverflow = $DB->get_record('moodleoverflow', ['id' => $moodleoverflow->id]); - $this->assertTrue(\mod_moodleoverflow\subscriptions::is_subscribable($moodleoverflow, $modulecontext)); - $this->assertFalse(\mod_moodleoverflow\subscriptions::subscription_disabled($moodleoverflow)); - $this->assertFalse(\mod_moodleoverflow\subscriptions::is_forcesubscribed($moodleoverflow)); + $this->assertTrue(subscriptions::is_subscribable($moodleoverflow, $modulecontext)); + $this->assertFalse(subscriptions::subscription_disabled($moodleoverflow)); + $this->assertFalse(subscriptions::is_forcesubscribed($moodleoverflow)); } /** @@ -182,7 +182,7 @@ public function test_unsubscribable_moodleoverflows(): void { $this->setUser($user); // Without any subscriptions, there should be nothing returned. - $result = \mod_moodleoverflow\subscriptions::get_unsubscribable_moodleoverflows(); + $result = subscriptions::get_unsubscribable_moodleoverflows(); $this->assertEquals(0, count($result)); // Create the moodleoverflows. @@ -196,15 +196,15 @@ public function test_unsubscribable_moodleoverflows(): void { $this->getDataGenerator()->create_module('moodleoverflow', $options); // At present the user is only subscribed to the initial moodleoverflow. - $result = \mod_moodleoverflow\subscriptions::get_unsubscribable_moodleoverflows(); + $result = subscriptions::get_unsubscribable_moodleoverflows(); $this->assertEquals(1, count($result)); // Ensure that the user is enrolled in all of the moodleoverflows execpt force subscribe. - \mod_moodleoverflow\subscriptions::subscribe_user($user->id, $disallow, $modulecontext); - \mod_moodleoverflow\subscriptions::subscribe_user($user->id, $choose, $modulecontext); + subscriptions::subscribe_user($user->id, $disallow, $modulecontext); + subscriptions::subscribe_user($user->id, $choose, $modulecontext); // At present the user is subscribed to all three moodleoverflows. - $result = \mod_moodleoverflow\subscriptions::get_unsubscribable_moodleoverflows(); + $result = subscriptions::get_unsubscribable_moodleoverflows(); $this->assertEquals(3, count($result)); } @@ -217,16 +217,12 @@ public function test_moodleoverflow_toggle_as_other(): void { // Reset the database after testing. $this->resetAfterTest(true); - // Create a course with a moodleoverflow. + // Create a course with a moodleoverflow. Get the module context and enroll a user in the course as a student. $course = $this->getDataGenerator()->create_course(); $options = ['course' => $course->id]; $moodleoverflow = $this->getDataGenerator()->create_module('moodleoverflow', $options); - - // Get the module context. $cm = get_coursemodule_from_instance('moodleoverflow', $moodleoverflow->id); $modulecontext = \context_module::instance($cm->id); - - // Create a user enrolled in the course as a student. list ($author) = $this->helper_create_users($course, 1); // Post a discussion to the moodleoverflow. @@ -236,149 +232,83 @@ public function test_moodleoverflow_toggle_as_other(): void { $discussion->moodleoverflow = $moodleoverflow->id; // Check that the user is currently not subscribed to the moodleoverflow. - $this->assertFalse(\mod_moodleoverflow\subscriptions::is_subscribed($author->id, $moodleoverflow, - $modulecontext)); + $this->assertFalse(subscriptions::is_subscribed($author->id, $moodleoverflow, $modulecontext)); // Check that the user is unsubscribed from the discussion too. - $this->assertFalse(\mod_moodleoverflow\subscriptions::is_subscribed($author->id, $moodleoverflow, - $modulecontext, $discussion->id)); + $this->assertFalse(subscriptions::is_subscribed($author->id, $moodleoverflow, $modulecontext, $discussion->id)); + + // Declare the options for the subscription tables. + $discussoptions = ['userid' => $author->id, 'discussion' => $discussion->id]; + $subscriptionoptions = ['userid' => $author->id, 'moodleoverflow' => $moodleoverflow->id]; // Check thast we have no records in either on the subscription tables. - $options = ['userid' => $author->id, 'moodleoverflow' => $moodleoverflow->id]; - $count = $DB->count_records('moodleoverflow_subscriptions', $options); - $this->assertEquals(0, $count); - $options = ['userid' => $author->id, 'discussion' => $discussion->id]; - $count = $DB->count_records('moodleoverflow_discuss_subs', $options); - $this->assertEquals(0, $count); + $this->assertEquals(0, $DB->count_records('moodleoverflow_subscriptions', $subscriptionoptions)); + $this->assertEquals(0, $DB->count_records('moodleoverflow_discuss_subs', $discussoptions)); - // Subscribing to the moodleoverflow should create a record in the subscription table, - // but the moodleoverflow discussion subscriptions table. - \mod_moodleoverflow\subscriptions::subscribe_user($author->id, $moodleoverflow, $modulecontext); - $options = ['userid' => $author->id, 'moodleoverflow' => $moodleoverflow->id]; - $count = $DB->count_records('moodleoverflow_subscriptions', $options); - $this->assertEquals(1, $count); - $options = ['userid' => $author->id, 'discussion' => $discussion->id]; - $count = $DB->count_records('moodleoverflow_discuss_subs', $options); - $this->assertEquals(0, $count); + // Subscribing to the moodleoverflow should add a record to the moodleoverflow subscription table. + subscriptions::subscribe_user($author->id, $moodleoverflow, $modulecontext); + $this->assertEquals(1, $DB->count_records('moodleoverflow_subscriptions', $subscriptionoptions)); + $this->assertEquals(0, $DB->count_records('moodleoverflow_discuss_subs', $discussoptions)); - // Unsubscribing should remove the record from the moodleoverflow subscription table. - // Do not modify the moodleoverflow discussion subscriptions table. - \mod_moodleoverflow\subscriptions::unsubscribe_user($author->id, $moodleoverflow, $modulecontext); - $options = ['userid' => $author->id, 'moodleoverflow' => $moodleoverflow->id]; - $count = $DB->count_records('moodleoverflow_subscriptions', $options); - $this->assertEquals(0, $count); - $options = ['userid' => $author->id, 'discussion' => $discussion->id]; - $count = $DB->count_records('moodleoverflow_discuss_subs', $options); - $this->assertEquals(0, $count); + // Unsubscribing should remove the record from the moodleoverflow subscription table. The discussion table stays the same. + subscriptions::unsubscribe_user($author->id, $moodleoverflow, $modulecontext); + $this->assertEquals(0, $DB->count_records('moodleoverflow_subscriptions', $subscriptionoptions)); + $this->assertEquals(0, $DB->count_records('moodleoverflow_discuss_subs', $discussoptions)); - // Enroling the user in the discussion should add one record to the - // moodleoverflow discussion table without modifying the form subscription. - \mod_moodleoverflow\subscriptions::subscribe_user_to_discussion($author->id, $discussion, $modulecontext); - $options = ['userid' => $author->id, 'moodleoverflow' => $moodleoverflow->id]; - $count = $DB->count_records('moodleoverflow_subscriptions', $options); - $this->assertEquals(0, $count); - $options = ['userid' => $author->id, 'discussion' => $discussion->id]; - $count = $DB->count_records('moodleoverflow_discuss_subs', $options); - $this->assertEquals(1, $count); + // Subscribing to the discussion should only add a record to the discussion subscription table. + subscriptions::subscribe_user_to_discussion($author->id, $discussion, $modulecontext); + $this->assertEquals(0, $DB->count_records('moodleoverflow_subscriptions', $subscriptionoptions)); + $this->assertEquals(1, $DB->count_records('moodleoverflow_discuss_subs', $discussoptions)); - // Unsubscribing should remove the record from the moodleoverflow subscriptions - // table and not modify the moodleoverflow discussion subscription table. - \mod_moodleoverflow\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion, $modulecontext); - $options = ['userid' => $author->id, 'discussion' => $discussion->id]; - $count = $DB->count_records('moodleoverflow_discuss_subs', $options); - $this->assertEquals(0, $count); - $options = ['userid' => $author->id, 'moodleoverflow' => $moodleoverflow->id]; - $count = $DB->count_records('moodleoverflow_subscriptions', $options); - $this->assertEquals(0, $count); + // Unsubscribing should remove the record from the moodleoverflow subscriptions and modify the discussion subscriptions. + subscriptions::unsubscribe_user_from_discussion($author->id, $discussion, $modulecontext); + $this->assertEquals(0, $DB->count_records('moodleoverflow_discuss_subs', $discussoptions)); + $this->assertEquals(0, $DB->count_records('moodleoverflow_subscriptions', $subscriptionoptions)); // Resubscribe to the discussion so that we can check the effect of moodleoverflow-level subscriptions. - \mod_moodleoverflow\subscriptions::subscribe_user_to_discussion($author->id, $discussion, $modulecontext); - $options = ['userid' => $author->id, 'discussion' => $discussion->id]; - $count = $DB->count_records('moodleoverflow_discuss_subs', $options); - $this->assertEquals(1, $count); - $options = ['userid' => $author->id, 'moodleoverflow' => $moodleoverflow->id]; - $count = $DB->count_records('moodleoverflow_subscriptions', $options); - $this->assertEquals(0, $count); + subscriptions::subscribe_user_to_discussion($author->id, $discussion, $modulecontext); + $this->assertEquals(1, $DB->count_records('moodleoverflow_discuss_subs', $discussoptions)); + $this->assertEquals(0, $DB->count_records('moodleoverflow_subscriptions', $subscriptionoptions)); - // Subscribing to the moodleoverflow should have no effect on the moodleoverflow discussion - // subscription table if the user did not request the change himself. - \mod_moodleoverflow\subscriptions::subscribe_user($author->id, $moodleoverflow, $modulecontext); - $options = ['userid' => $author->id, 'moodleoverflow' => $moodleoverflow->id]; - $count = $DB->count_records('moodleoverflow_subscriptions', $options); - $this->assertEquals(1, $count); - $options = ['userid' => $author->id, 'discussion' => $discussion->id]; - $count = $DB->count_records('moodleoverflow_discuss_subs', $options); - $this->assertEquals(1, $count); + // Subscribing to the moodleoverflow should have no effect on the discussion subscription. + subscriptions::subscribe_user($author->id, $moodleoverflow, $modulecontext); + $this->assertEquals(1, $DB->count_records('moodleoverflow_subscriptions', $subscriptionoptions)); + $this->assertEquals(1, $DB->count_records('moodleoverflow_discuss_subs', $discussoptions)); - // Unsubbing from the moodleoverflow should have no effect on the moodleoverflow - // discussion subscription table if the user did not request the change themself. - \mod_moodleoverflow\subscriptions::unsubscribe_user($author->id, $moodleoverflow, $modulecontext); - $options = ['userid' => $author->id, 'moodleoverflow' => $moodleoverflow->id]; - $count = $DB->count_records('moodleoverflow_subscriptions', $options); - $this->assertEquals(0, $count); - $options = ['userid' => $author->id, 'discussion' => $discussion->id]; - $count = $DB->count_records('moodleoverflow_discuss_subs', $options); - $this->assertEquals(1, $count); + // Unsubbing from the moodleoverflow should have no effect on the discussion subscription. + subscriptions::unsubscribe_user($author->id, $moodleoverflow, $modulecontext); + $this->assertEquals(0, $DB->count_records('moodleoverflow_subscriptions', $subscriptionoptions)); + $this->assertEquals(1, $DB->count_records('moodleoverflow_discuss_subs', $discussoptions)); - // Subscribing to the moodleoverflow should remove the per-discussion - // subscription preference if the user requested the change themself. - \mod_moodleoverflow\subscriptions::subscribe_user($author->id, $moodleoverflow, $modulecontext, true); - $options = ['userid' => $author->id, 'moodleoverflow' => $moodleoverflow->id]; - $count = $DB->count_records('moodleoverflow_subscriptions', $options); - $this->assertEquals(1, $count); - $options = ['userid' => $author->id, 'discussion' => $discussion->id]; - $count = $DB->count_records('moodleoverflow_discuss_subs', $options); - $this->assertEquals(0, $count); + // Subscribing to the moodleoverflow should remove the per-discussion subscription preference if the user wanted the change. + subscriptions::subscribe_user($author->id, $moodleoverflow, $modulecontext, true); + $this->assertEquals(1, $DB->count_records('moodleoverflow_subscriptions', $subscriptionoptions)); + $this->assertEquals(0, $DB->count_records('moodleoverflow_discuss_subs', $discussoptions)); // Now unsubscribe from the current discussion whilst being subscribed to the moodleoverflow as a whole. - \mod_moodleoverflow\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion, $modulecontext); - $options = ['userid' => $author->id, 'moodleoverflow' => $moodleoverflow->id]; - $count = $DB->count_records('moodleoverflow_subscriptions', $options); - $this->assertEquals(1, $count); - $options = ['userid' => $author->id, 'discussion' => $discussion->id]; - $count = $DB->count_records('moodleoverflow_discuss_subs', $options); - $this->assertEquals(1, $count); + subscriptions::unsubscribe_user_from_discussion($author->id, $discussion, $modulecontext); + $this->assertEquals(1, $DB->count_records('moodleoverflow_subscriptions', $subscriptionoptions)); + $this->assertEquals(1, $DB->count_records('moodleoverflow_discuss_subs', $discussoptions)); - // Unsubscribing from the moodleoverflow should remove the per-discussion - // subscription preference if the user requested the change himself. - \mod_moodleoverflow\subscriptions::unsubscribe_user($author->id, $moodleoverflow, $modulecontext, true); - $options = ['userid' => $author->id, 'moodleoverflow' => $moodleoverflow->id]; - $count = $DB->count_records('moodleoverflow_subscriptions', $options); - $this->assertEquals(0, $count); - $count = $DB->count_records('moodleoverflow_discuss_subs', [ - 'userid' => $author->id, - 'discussion' => $discussion->id, - ]); - $this->assertEquals(0, $count); + // Unsubscribing from the moodleoverflow should remove per-discussion subscription preference if the user wanted the change. + subscriptions::unsubscribe_user($author->id, $moodleoverflow, $modulecontext, true); + $this->assertEquals(0, $DB->count_records('moodleoverflow_subscriptions', $subscriptionoptions)); + $this->assertEquals(0, $DB->count_records('moodleoverflow_discuss_subs', $discussoptions)); // Subscribe to the discussion. - \mod_moodleoverflow\subscriptions::subscribe_user_to_discussion($author->id, $discussion, $modulecontext); - $options = ['userid' => $author->id, 'moodleoverflow' => $moodleoverflow->id]; - $count = $DB->count_records('moodleoverflow_subscriptions', $options); - $this->assertEquals(0, $count); - $count = $DB->count_records('moodleoverflow_discuss_subs', [ - 'userid' => $author->id, - 'discussion' => $discussion->id, - ]); - $this->assertEquals(1, $count); + subscriptions::subscribe_user_to_discussion($author->id, $discussion, $modulecontext); + $this->assertEquals(0, $DB->count_records('moodleoverflow_subscriptions', $subscriptionoptions)); + $this->assertEquals(1, $DB->count_records('moodleoverflow_discuss_subs', $discussoptions)); // Subscribe to the moodleoverflow without removing the discussion preferences. - \mod_moodleoverflow\subscriptions::subscribe_user($author->id, $moodleoverflow, $modulecontext); - $options = ['userid' => $author->id, 'moodleoverflow' => $moodleoverflow->id]; - $count = $DB->count_records('moodleoverflow_subscriptions', $options); - $this->assertEquals(1, $count); - $options = ['userid' => $author->id, 'discussion' => $discussion->id]; - $count = $DB->count_records('moodleoverflow_discuss_subs', $options); - $this->assertEquals(1, $count); + subscriptions::subscribe_user($author->id, $moodleoverflow, $modulecontext); + $this->assertEquals(1, $DB->count_records('moodleoverflow_subscriptions', $subscriptionoptions)); + $this->assertEquals(1, $DB->count_records('moodleoverflow_discuss_subs', $discussoptions)); // Unsubscribe from the discussion should result in a change. - \mod_moodleoverflow\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion, $modulecontext); - $options = ['userid' => $author->id, 'moodleoverflow' => $moodleoverflow->id]; - $count = $DB->count_records('moodleoverflow_subscriptions', $options); - $this->assertEquals(1, $count); - $options = ['userid' => $author->id, 'discussion' => $discussion->id]; - $count = $DB->count_records('moodleoverflow_discuss_subs', $options); - $this->assertEquals(1, $count); + subscriptions::unsubscribe_user_from_discussion($author->id, $discussion, $modulecontext); + $this->assertEquals(1, $DB->count_records('moodleoverflow_subscriptions', $subscriptionoptions)); + $this->assertEquals(1, $DB->count_records('moodleoverflow_discuss_subs', $discussoptions)); } /** @@ -397,14 +327,14 @@ public function test_moodleoverflow_discussion_subscription_moodleoverflow_unsub list($author) = $this->helper_create_users($course, 1); // Check that the user is currently not subscribed to the moodleoverflow. - $this->assertFalse(\mod_moodleoverflow\subscriptions::is_subscribed($author->id, $moodleoverflow, $moodleoverflow)); + $this->assertFalse(subscriptions::is_subscribed($author->id, $moodleoverflow, $moodleoverflow)); // Post a discussion to the moodleoverflow. list($discussion, $post) = $this->helper_post_to_moodleoverflow($moodleoverflow, $author); unset($post); // Check that the user is unsubscribed from the discussion too. - $this->assertFalse(\mod_moodleoverflow\subscriptions::is_subscribed($author->id, $moodleoverflow, + $this->assertFalse(subscriptions::is_subscribed($author->id, $moodleoverflow, $moodleoverflow, $discussion)); } @@ -429,21 +359,21 @@ public function test_moodleoverflow_discussion_subscription_moodleoverflow_subsc // Enrol the user in the moodleoverflow. // If a subscription was added, we get the record ID. - $this->assertIsInt(\mod_moodleoverflow\subscriptions::subscribe_user($author->id, + $this->assertIsInt(subscriptions::subscribe_user($author->id, $moodleoverflow, $modulecontext)); // If we already have a subscription when subscribing the user, we get a boolean (true). - $this->assertTrue(\mod_moodleoverflow\subscriptions::subscribe_user($author->id, $moodleoverflow, $modulecontext)); + $this->assertTrue(subscriptions::subscribe_user($author->id, $moodleoverflow, $modulecontext)); // Check that the user is currently subscribed to the moodleoverflow. - $this->assertTrue(\mod_moodleoverflow\subscriptions::is_subscribed($author->id, $moodleoverflow, $modulecontext)); + $this->assertTrue(subscriptions::is_subscribed($author->id, $moodleoverflow, $modulecontext)); // Post a discussion to the moodleoverflow. list($discussion, $post) = $this->helper_post_to_moodleoverflow($moodleoverflow, $author); unset($post); // Check that the user is subscribed to the discussion too. - $this->assertTrue(\mod_moodleoverflow\subscriptions::is_subscribed($author->id, $moodleoverflow, $modulecontext, + $this->assertTrue(subscriptions::is_subscribed($author->id, $moodleoverflow, $modulecontext, $discussion)); } @@ -467,7 +397,7 @@ public function test_moodleoverflow_discussion_subscription_moodleoverflow_unsub list($author) = $this->helper_create_users($course, 1); // Check that the user is currently not subscribed to the moodleoverflow. - $this->assertFalse(\mod_moodleoverflow\subscriptions::is_subscribed($author->id, $moodleoverflow, $moodleoverflow)); + $this->assertFalse(subscriptions::is_subscribed($author->id, $moodleoverflow, $moodleoverflow)); // Post a discussion to the moodleoverflow. $discussion = new \stdClass(); @@ -476,18 +406,18 @@ public function test_moodleoverflow_discussion_subscription_moodleoverflow_unsub $discussion->moodleoverflow = $moodleoverflow->id; // Attempting to unsubscribe from the discussion should not make a change. - $this->assertFalse(\mod_moodleoverflow\subscriptions::unsubscribe_user_from_discussion($author->id, + $this->assertFalse(subscriptions::unsubscribe_user_from_discussion($author->id, $discussion, $modulecontext)); // Then subscribe them to the discussion. - $this->assertTrue(\mod_moodleoverflow\subscriptions::subscribe_user_to_discussion($author->id, + $this->assertTrue(subscriptions::subscribe_user_to_discussion($author->id, $discussion, $modulecontext)); // Check that the user is still unsubscribed from the moodleoverflow. - $this->assertFalse(\mod_moodleoverflow\subscriptions::is_subscribed($author->id, $moodleoverflow, $moodleoverflow)); + $this->assertFalse(subscriptions::is_subscribed($author->id, $moodleoverflow, $moodleoverflow)); // But subscribed to the discussion. - $this->assertTrue(\mod_moodleoverflow\subscriptions::is_subscribed($author->id, $moodleoverflow, $modulecontext, + $this->assertTrue(subscriptions::is_subscribed($author->id, $moodleoverflow, $modulecontext, $discussion->id)); } @@ -511,10 +441,10 @@ public function test_moodleoverflow_discussion_subscription_moodleoverflow_subsc list($author) = $this->helper_create_users($course, 2); // Enrol the student in the moodleoverflow. - \mod_moodleoverflow\subscriptions::subscribe_user($author->id, $moodleoverflow, $modulecontext); + subscriptions::subscribe_user($author->id, $moodleoverflow, $modulecontext); // Check that the user is currently subscribed to the moodleoverflow. - $this->assertTrue(\mod_moodleoverflow\subscriptions::is_subscribed($author->id, $moodleoverflow, $modulecontext)); + $this->assertTrue(subscriptions::is_subscribed($author->id, $moodleoverflow, $modulecontext)); // Post a discussion to the moodleoverflow. $discussion = new \stdClass(); @@ -523,13 +453,13 @@ public function test_moodleoverflow_discussion_subscription_moodleoverflow_subsc $discussion->moodleoverflow = $moodleoverflow->id; // Then unsubscribe them from the discussion. - \mod_moodleoverflow\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion, $modulecontext); + subscriptions::unsubscribe_user_from_discussion($author->id, $discussion, $modulecontext); // Check that the user is still subscribed to the moodleoverflow. - $this->assertTrue(\mod_moodleoverflow\subscriptions::is_subscribed($author->id, $moodleoverflow, $modulecontext)); + $this->assertTrue(subscriptions::is_subscribed($author->id, $moodleoverflow, $modulecontext)); // But unsubscribed from the discussion. - $this->assertFalse(\mod_moodleoverflow\subscriptions::is_subscribed($author->id, $moodleoverflow, $modulecontext, + $this->assertFalse(subscriptions::is_subscribed($author->id, $moodleoverflow, $modulecontext, $discussion->id)); } @@ -538,23 +468,17 @@ public function test_moodleoverflow_discussion_subscription_moodleoverflow_subsc */ public function test_moodleoverflow_discussion_toggle_moodleoverflow_subscribed(): void { global $DB; - // Reset the database after testing. - $this->resetAfterTest(true); + $this->resetAfterTest(); - // Create a course with a moodleoverflow. + // Create a course with a moodleoverflow and enroll two users in the course as students and in the moodleoverflow. $course = $this->getDataGenerator()->create_course(); $options = ['course' => $course->id, 'forcesubscribe' => MOODLEOVERFLOW_CHOOSESUBSCRIBE]; $moodleoverflow = $this->getDataGenerator()->create_module('moodleoverflow', $options); - $cm = get_coursemodule_from_instance('moodleoverflow', $moodleoverflow->id); $modulecontext = \context_module::instance($cm->id); - - // Create two users enrolled in the course as students. list($author) = $this->helper_create_users($course, 2); - - // Enrol the student in the moodleoverflow. - \mod_moodleoverflow\subscriptions::subscribe_user($author->id, $moodleoverflow, $modulecontext); + subscriptions::subscribe_user($author->id, $moodleoverflow, $modulecontext); // Post a discussion to the moodleoverflow. $discussion = new \stdClass(); @@ -562,152 +486,82 @@ public function test_moodleoverflow_discussion_toggle_moodleoverflow_subscribed( unset($post); $discussion->moodleoverflow = $moodleoverflow->id; - // Check that the user is currently subscribed to the moodleoverflow. - $this->assertTrue(\mod_moodleoverflow\subscriptions::is_subscribed($author->id, $moodleoverflow, $modulecontext)); - - // Check that the user is initially subscribed to that discussion. - $this->assertTrue(\mod_moodleoverflow\subscriptions::is_subscribed($author->id, $moodleoverflow, $modulecontext, - $discussion->id)); + // Check that the user is currently subscribed to the moodleoverflow and initially subscribed to that discussion. + $this->assertTrue(subscriptions::is_subscribed($author->id, $moodleoverflow, $modulecontext)); + $this->assertTrue(subscriptions::is_subscribed($author->id, $moodleoverflow, $modulecontext, $discussion->id)); // An attempt to subscribe again should result in a falsey return to indicate that no change was made. - $this->assertFalse(\mod_moodleoverflow\subscriptions::subscribe_user_to_discussion($author->id, - $discussion, $modulecontext)); + $this->assertFalse(subscriptions::subscribe_user_to_discussion($author->id, $discussion, $modulecontext)); - // And there should be no discussion subscriptions (and one moodleoverflow subscription). - $options = ['userid' => $author->id, 'discussion' => $discussion->id]; - $count = $DB->count_records('moodleoverflow_discuss_subs', $options); - $this->assertEquals(0, $count); - $options = ['userid' => $author->id, 'moodleoverflow' => $moodleoverflow->id]; - $count = $DB->count_records('moodleoverflow_subscriptions', $options); - $this->assertEquals(1, $count); + // Declare the options for the subscription tables. + $discussoptions = ['userid' => $author->id, 'discussion' => $discussion->id]; + $subscriptionoptions = ['userid' => $author->id, 'moodleoverflow' => $moodleoverflow->id]; - // Then unsubscribe them from the discussion. - \mod_moodleoverflow\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion, $modulecontext); - - // Check that the user is still subscribed to the moodleoverflow. - $this->assertTrue(\mod_moodleoverflow\subscriptions::is_subscribed($author->id, $moodleoverflow, $modulecontext)); + // And there should be no discussion subscriptions (and one moodleoverflow subscription). + $this->assertEquals(0, $DB->count_records('moodleoverflow_discuss_subs', $discussoptions)); + $this->assertEquals(1, $DB->count_records('moodleoverflow_subscriptions', $subscriptionoptions)); - // An attempt to unsubscribe again should result in a falsey return to indicate that no change was made. - $this->assertFalse(\mod_moodleoverflow\subscriptions::unsubscribe_user_from_discussion($author->id, - $discussion, $modulecontext)); + // Unsubscribe them from the discussion while still subscribe the moodleoverflow. Attempt to unsubscribe again should fail. + subscriptions::unsubscribe_user_from_discussion($author->id, $discussion, $modulecontext); + $this->assertTrue(subscriptions::is_subscribed($author->id, $moodleoverflow, $modulecontext)); + $this->assertFalse(subscriptions::unsubscribe_user_from_discussion($author->id, $discussion, $modulecontext)); // And there should be a discussion subscriptions (and one moodleoverflow subscription). - $options = ['userid' => $author->id, 'discussion' => $discussion->id]; - $count = $DB->count_records('moodleoverflow_discuss_subs', $options); - $this->assertEquals(1, $count); - $options = ['userid' => $author->id, 'moodleoverflow' => $moodleoverflow->id]; - $count = $DB->count_records('moodleoverflow_subscriptions', $options); - $this->assertEquals(1, $count); - - // But unsubscribed from the discussion. - $this->assertFalse(\mod_moodleoverflow\subscriptions::is_subscribed($author->id, $moodleoverflow, $modulecontext, - $discussion->id)); - - // There should be a record in the discussion subscription tracking table. - $options = ['userid' => $author->id, 'discussion' => $discussion->id]; - $count = $DB->count_records('moodleoverflow_discuss_subs', $options); - $this->assertEquals(1, $count); - - // And one in the moodleoverflow subscription tracking table. - $options = ['userid' => $author->id, 'moodleoverflow' => $moodleoverflow->id]; - $count = $DB->count_records('moodleoverflow_subscriptions', $options); - $this->assertEquals(1, $count); - - // Now subscribe the user again to the discussion. - \mod_moodleoverflow\subscriptions::subscribe_user_to_discussion($author->id, $discussion, $modulecontext); - - // Check that the user is still subscribed to the moodleoverflow. - $this->assertTrue(\mod_moodleoverflow\subscriptions::is_subscribed($author->id, $moodleoverflow, $modulecontext)); - - // And is subscribed to the discussion again. - $this->assertTrue(\mod_moodleoverflow\subscriptions::is_subscribed($author->id, $moodleoverflow, $modulecontext, - $discussion->id)); - - // And one in the moodleoverflow subscription tracking table. - $options = ['userid' => $author->id, 'moodleoverflow' => $moodleoverflow->id]; - $count = $DB->count_records('moodleoverflow_subscriptions', $options); - $this->assertEquals(1, $count); - - // There should be no record in the discussion subscription tracking table. - $options = ['userid' => $author->id, 'discussion' => $discussion->id]; - $count = $DB->count_records('moodleoverflow_discuss_subs', $options); - $this->assertEquals(0, $count); - - // And unsubscribe again. - \mod_moodleoverflow\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion, $modulecontext); - - // Check that the user is still subscribed to the moodleoverflow. - $this->assertTrue(\mod_moodleoverflow\subscriptions::is_subscribed($author->id, $moodleoverflow, $modulecontext)); + $this->assertEquals(1, $DB->count_records('moodleoverflow_discuss_subs', $discussoptions)); + $this->assertEquals(1, $DB->count_records('moodleoverflow_subscriptions', $subscriptionoptions)); // But unsubscribed from the discussion. - $this->assertFalse(\mod_moodleoverflow\subscriptions::is_subscribed($author->id, $moodleoverflow, $modulecontext, - $discussion->id)); + $this->assertFalse(subscriptions::is_subscribed($author->id, $moodleoverflow, $modulecontext, $discussion->id)); - // And one in the moodleoverflow subscription tracking table. - $options = ['userid' => $author->id, 'moodleoverflow' => $moodleoverflow->id]; - $count = $DB->count_records('moodleoverflow_subscriptions', $options); - $this->assertEquals(1, $count); + // There should be one record in the discussion and moodleoverflow subscription tracking table. + $this->assertEquals(1, $DB->count_records('moodleoverflow_discuss_subs', $discussoptions)); + $this->assertEquals(1, $DB->count_records('moodleoverflow_subscriptions', $subscriptionoptions)); - // There should be a record in the discussion subscription tracking table. - $options = ['userid' => $author->id, 'discussion' => $discussion->id]; - $count = $DB->count_records('moodleoverflow_discuss_subs', $options); - $this->assertEquals(1, $count); + // Now subscribe the user again to the discussion. Now discussion and moodleoverflow should be subscribed. + subscriptions::subscribe_user_to_discussion($author->id, $discussion, $modulecontext); + $this->assertTrue(subscriptions::is_subscribed($author->id, $moodleoverflow, $modulecontext)); + $this->assertTrue(subscriptions::is_subscribed($author->id, $moodleoverflow, $modulecontext, $discussion->id)); - // And subscribe the user again to the discussion. - \mod_moodleoverflow\subscriptions::subscribe_user_to_discussion($author->id, $discussion, $modulecontext); + // And one in the moodleoverflow subscription and no record in the discussion tracking table. + $this->assertEquals(1, $DB->count_records('moodleoverflow_subscriptions', $subscriptionoptions)); + $this->assertEquals(0, $DB->count_records('moodleoverflow_discuss_subs', $discussoptions)); - // Check that the user is still subscribed to the moodleoverflow. - $this->assertTrue(\mod_moodleoverflow\subscriptions::is_subscribed($author->id, $moodleoverflow, $modulecontext)); - $this->assertTrue(\mod_moodleoverflow\subscriptions::is_subscribed($author->id, $moodleoverflow, $modulecontext)); + // And unsubscribe again. Only moodleoverflow should be subscribed. Discussion should be unsubscribed. + subscriptions::unsubscribe_user_from_discussion($author->id, $discussion, $modulecontext); + $this->assertTrue(subscriptions::is_subscribed($author->id, $moodleoverflow, $modulecontext)); + $this->assertFalse(subscriptions::is_subscribed($author->id, $moodleoverflow, $modulecontext, $discussion->id)); - // And is subscribed to the discussion again. - $this->assertTrue(\mod_moodleoverflow\subscriptions::is_subscribed($author->id, $moodleoverflow, $modulecontext, - $discussion->id)); - - // There should be no record in the discussion subscription tracking table. - $options = ['userid' => $author->id, 'discussion' => $discussion->id]; - $count = $DB->count_records('moodleoverflow_discuss_subs', $options); - $this->assertEquals(0, $count); + // There should be one record in the moodleoverflow and discussion subscription tracking table. + $this->assertEquals(1, $DB->count_records('moodleoverflow_subscriptions', $subscriptionoptions)); + $this->assertEquals(1, $DB->count_records('moodleoverflow_discuss_subs', $discussoptions)); - // And one in the forum subscription tracking table. - $options = ['userid' => $author->id, 'moodleoverflow' => $moodleoverflow->id]; - $count = $DB->count_records('moodleoverflow_subscriptions', $options); - $this->assertEquals(1, $count); + // And subscribe the user again to the discussion. Both should be subscribed. + subscriptions::subscribe_user_to_discussion($author->id, $discussion, $modulecontext); + $this->assertTrue(subscriptions::is_subscribed($author->id, $moodleoverflow, $modulecontext)); + $this->assertTrue(subscriptions::is_subscribed($author->id, $moodleoverflow, $modulecontext, $discussion->id)); - // And unsubscribe again. - \mod_moodleoverflow\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion, $modulecontext); + // There should be no record in the discussion and one in the moodleoverflow subscription tracking table. + $this->assertEquals(0, $DB->count_records('moodleoverflow_discuss_subs', $discussoptions)); + $this->assertEquals(1, $DB->count_records('moodleoverflow_subscriptions', $subscriptionoptions)); - // But unsubscribed from the discussion. - $this->assertFalse(\mod_moodleoverflow\subscriptions::is_subscribed($author->id, $moodleoverflow, $modulecontext, - $discussion->id)); + // And unsubscribe again from the discussion. Only moodleoverflow should be subscribed. + subscriptions::unsubscribe_user_from_discussion($author->id, $discussion, $modulecontext); + $this->assertTrue(subscriptions::is_subscribed($author->id, $moodleoverflow, $modulecontext)); + $this->assertFalse(subscriptions::is_subscribed($author->id, $moodleoverflow, $modulecontext, $discussion->id)); - // Check that the user is still subscribed to the moodleoverflow. - $this->assertTrue(\mod_moodleoverflow\subscriptions::is_subscribed($author->id, $moodleoverflow, $modulecontext)); - - // There should be a record in the discussion subscription tracking table. - $options = ['userid' => $author->id, 'discussion' => $discussion->id]; - $count = $DB->count_records('moodleoverflow_discuss_subs', $options); - $this->assertEquals(1, $count); - - // And one in the moodleoverflow subscription tracking table. - $options = ['userid' => $author->id, 'moodleoverflow' => $moodleoverflow->id]; - $count = $DB->count_records('moodleoverflow_subscriptions', $options); - $this->assertEquals(1, $count); + // There should be a record in the discussion and one in the moodleoverflow subscription tracking table. + $this->assertEquals(1, $DB->count_records('moodleoverflow_discuss_subs', $discussoptions)); + $this->assertEquals(1, $DB->count_records('moodleoverflow_subscriptions', $subscriptionoptions)); // Now unsubscribe the user from the moodleoverflow. - $this->assertTrue(\mod_moodleoverflow\subscriptions::unsubscribe_user($author->id, $moodleoverflow, $modulecontext, - true)); + $this->assertTrue(subscriptions::unsubscribe_user($author->id, $moodleoverflow, $modulecontext, true)); // This removes both the moodleoverflow, and the moodleoverflow records. - $options = ['userid' => $author->id, 'discussion' => $discussion->id]; - $count = $DB->count_records('moodleoverflow_discuss_subs', $options); - $this->assertEquals(0, $count); - $options = ['userid' => $author->id, 'moodleoverflow' => $moodleoverflow->id]; - $count = $DB->count_records('moodleoverflow_subscriptions', $options); - $this->assertEquals(0, $count); + $this->assertEquals(0, $DB->count_records('moodleoverflow_discuss_subs', $discussoptions)); + $this->assertEquals(0, $DB->count_records('moodleoverflow_subscriptions', $subscriptionoptions)); // And should have reset the discussion cache value. - $result = \mod_moodleoverflow\subscriptions::fetch_discussion_subscription($moodleoverflow->id, $author->id); + $result = subscriptions::fetch_discussion_subscription($moodleoverflow->id, $author->id); $this->assertIsArray($result); $this->assertFalse(isset($result[$discussion->id])); } @@ -721,20 +575,16 @@ public function test_moodleoverflow_discussion_toggle_moodleoverflow_unsubscribe // Reset the database after testing. $this->resetAfterTest(true); - // Create a course, with a moodleoverflow. + // Create a course, with a moodleoverflow and get the module context. Create two users enrolled inthe course as students. $course = $this->getDataGenerator()->create_course(); $options = ['course' => $course->id, 'forcesubscribe' => MOODLEOVERFLOW_CHOOSESUBSCRIBE]; $moodleoverflow = $this->getDataGenerator()->create_module('moodleoverflow', $options); - - // Get the module context. $cm = get_coursemodule_from_instance('moodleoverflow', $moodleoverflow->id); $modulecontext = \context_module::instance($cm->id); - - // Create two users enrolled in the course as students. list($author) = $this->helper_create_users($course, 2); // Check that the user is currently unsubscribed to the moodleoverflow. - $this->assertFalse(\mod_moodleoverflow\subscriptions::is_subscribed($author->id, $moodleoverflow, $modulecontext)); + $this->assertFalse(subscriptions::is_subscribed($author->id, $moodleoverflow, $modulecontext)); // Post a discussion to the moodleoverflow. $discussion = new \stdClass(); @@ -742,54 +592,47 @@ public function test_moodleoverflow_discussion_toggle_moodleoverflow_unsubscribe unset($post); $discussion->moodleoverflow = $moodleoverflow->id; + // Declare the options for the subscription tables. + $discussoptions = ['userid' => $author->id, 'discussion' => $discussion->id]; + // Check that the user is initially unsubscribed to that discussion. - $this->assertFalse(\mod_moodleoverflow\subscriptions::is_subscribed($author->id, $moodleoverflow, $modulecontext, - $discussion->id)); + $this->assertFalse(subscriptions::is_subscribed($author->id, $moodleoverflow, $modulecontext, $discussion->id)); // Then subscribe them to the discussion. - $this->assertTrue(\mod_moodleoverflow\subscriptions::subscribe_user_to_discussion($author->id, - $discussion, $modulecontext)); + $this->assertTrue(subscriptions::subscribe_user_to_discussion($author->id, $discussion, $modulecontext)); // An attempt to subscribe again should result in a falsey return to indicate that no change was made. - $this->assertFalse(\mod_moodleoverflow\subscriptions::subscribe_user_to_discussion($author->id, - $discussion, $modulecontext)); + $this->assertFalse(subscriptions::subscribe_user_to_discussion($author->id, $discussion, $modulecontext)); // Check that the user is still unsubscribed from the moodleoverflow. - $this->assertFalse(\mod_moodleoverflow\subscriptions::is_subscribed($author->id, $moodleoverflow, $modulecontext)); + $this->assertFalse(subscriptions::is_subscribed($author->id, $moodleoverflow, $modulecontext)); // But subscribed to the discussion. - $this->assertTrue(\mod_moodleoverflow\subscriptions::is_subscribed($author->id, $moodleoverflow, $modulecontext, - $discussion->id)); + $this->assertTrue(subscriptions::is_subscribed($author->id, $moodleoverflow, $modulecontext, $discussion->id)); // There should be a record in the discussion subscription tracking table. - $options = ['userid' => $author->id, 'discussion' => $discussion->id]; - $count = $DB->count_records('moodleoverflow_discuss_subs', $options); - $this->assertEquals(1, $count); + $this->assertEquals(1, $DB->count_records('moodleoverflow_discuss_subs', $discussoptions)); // Now unsubscribe the user again from the discussion. - \mod_moodleoverflow\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion, $modulecontext); + subscriptions::unsubscribe_user_from_discussion($author->id, $discussion, $modulecontext); // Check that the user is still unsubscribed from the moodleoverflow. - $this->assertFalse(\mod_moodleoverflow\subscriptions::is_subscribed($author->id, $moodleoverflow, $modulecontext)); + $this->assertFalse(subscriptions::is_subscribed($author->id, $moodleoverflow, $modulecontext)); // And is unsubscribed from the discussion again. - $this->assertFalse(\mod_moodleoverflow\subscriptions::is_subscribed($author->id, $moodleoverflow, $modulecontext, - $discussion->id)); + $this->assertFalse(subscriptions::is_subscribed($author->id, $moodleoverflow, $modulecontext, $discussion->id)); // There should be no record in the discussion subscription tracking table. - $options = ['userid' => $author->id, 'discussion' => $discussion->id]; - $count = $DB->count_records('moodleoverflow_discuss_subs', $options); - $this->assertEquals(0, $count); + $this->assertEquals(0, $DB->count_records('moodleoverflow_discuss_subs', $discussoptions)); // And subscribe the user again to the discussion. - \mod_moodleoverflow\subscriptions::subscribe_user_to_discussion($author->id, $discussion, $modulecontext); + subscriptions::subscribe_user_to_discussion($author->id, $discussion, $modulecontext); // And is subscribed to the discussion again. - $this->assertTrue(\mod_moodleoverflow\subscriptions::is_subscribed($author->id, $moodleoverflow, $modulecontext, - $discussion->id)); + $this->assertTrue(subscriptions::is_subscribed($author->id, $moodleoverflow, $modulecontext, $discussion->id)); // Check that the user is still unsubscribed from the moodleoverflow. - $this->assertFalse(\mod_moodleoverflow\subscriptions::is_subscribed($author->id, $moodleoverflow, $modulecontext)); + $this->assertFalse(subscriptions::is_subscribed($author->id, $moodleoverflow, $modulecontext)); // There should be a record in the discussion subscription tracking table. $options = ['userid' => $author->id, 'discussion' => $discussion->id]; @@ -797,14 +640,13 @@ public function test_moodleoverflow_discussion_toggle_moodleoverflow_unsubscribe $this->assertEquals(1, $count); // And unsubscribe again. - \mod_moodleoverflow\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion, $modulecontext); + subscriptions::unsubscribe_user_from_discussion($author->id, $discussion, $modulecontext); // But unsubscribed from the discussion. - $this->assertFalse(\mod_moodleoverflow\subscriptions::is_subscribed($author->id, $moodleoverflow, $modulecontext, - $discussion->id)); + $this->assertFalse(subscriptions::is_subscribed($author->id, $moodleoverflow, $modulecontext, $discussion->id)); // Check that the user is still unsubscribed from the moodleoverflow. - $this->assertFalse(\mod_moodleoverflow\subscriptions::is_subscribed($author->id, $moodleoverflow, $modulecontext)); + $this->assertFalse(subscriptions::is_subscribed($author->id, $moodleoverflow, $modulecontext)); // There should be no record in the discussion subscription tracking table. $options = ['userid' => $author->id, 'discussion' => $discussion->id]; @@ -822,37 +664,34 @@ public function test_fetch_subscribed_users_subscriptions(): void { // Reset the database after testing. $this->resetAfterTest(true); - // Create a course, with a moodleoverflow. where users are initially subscribed. + // Create a course, with a moodleoverflow. where users are initially subscribed and get the module context. $course = $this->getDataGenerator()->create_course(); $options = ['course' => $course->id, 'forcesubscribe' => MOODLEOVERFLOW_INITIALSUBSCRIBE]; $moodleoverflow = $this->getDataGenerator()->create_module('moodleoverflow', $options); - - // Get the module context. $cm = get_coursemodule_from_instance('moodleoverflow', $moodleoverflow->id); $modulecontext = \context_module::instance($cm->id); - // Create some user enrolled in the course as a student. + // Create five user enrolled in the course as a student. $usercount = 5; $users = $this->helper_create_users($course, $usercount); // All users should be subscribed. - $subscribers = \mod_moodleoverflow\subscriptions::get_subscribed_users($moodleoverflow, $modulecontext); + $subscribers = subscriptions::get_subscribed_users($moodleoverflow, $modulecontext); $this->assertEquals($usercount, count($subscribers)); // Subscribe the guest user too to the moodleoverflow - they should never be returned by this function. $this->getDataGenerator()->enrol_user($CFG->siteguest, $course->id); - $subscribers = \mod_moodleoverflow\subscriptions::get_subscribed_users($moodleoverflow, $modulecontext); + $subscribers = subscriptions::get_subscribed_users($moodleoverflow, $modulecontext); $this->assertEquals($usercount, count($subscribers)); // Unsubscribe 2 users. - $unsubscribedcount = 2; - for ($i = 0; $i < $unsubscribedcount; $i++) { - \mod_moodleoverflow\subscriptions::unsubscribe_user($users[$i]->id, $moodleoverflow, $modulecontext); + for ($i = 0; $i < 2; $i++) { + subscriptions::unsubscribe_user($users[$i]->id, $moodleoverflow, $modulecontext); } // The subscription count should now take into account those users who have been unsubscribed. - $subscribers = \mod_moodleoverflow\subscriptions::get_subscribed_users($moodleoverflow, $modulecontext); - $this->assertEquals($usercount - $unsubscribedcount, count($subscribers)); + $subscribers = subscriptions::get_subscribed_users($moodleoverflow, $modulecontext); + $this->assertEquals($usercount - 2, count($subscribers)); } /** @@ -877,7 +716,7 @@ public function test_fetch_subscribed_users_forced(): void { $this->helper_create_users($course, $usercount); // All users should be subscribed. - $subscribers = \mod_moodleoverflow\subscriptions::get_subscribed_users($moodleoverflow, $modulecontext); + $subscribers = subscriptions::get_subscribed_users($moodleoverflow, $modulecontext); $this->assertEquals($usercount, count($subscribers)); } @@ -910,21 +749,19 @@ public function test_fetch_subscribed_users_discussion_subscriptions(): void { $discussion->moodleoverflow = $moodleoverflow->id; // All users should be subscribed. - $subscribers = \mod_moodleoverflow\subscriptions::get_subscribed_users($moodleoverflow, $modulecontext); + $subscribers = subscriptions::get_subscribed_users($moodleoverflow, $modulecontext); $this->assertEquals($usercount, count($subscribers)); - $subscribers = \mod_moodleoverflow\subscriptions::get_subscribed_users($moodleoverflow, $modulecontext, null, - true); + $subscribers = subscriptions::get_subscribed_users($moodleoverflow, $modulecontext, null, true); $this->assertEquals($usercount, count($subscribers)); - \mod_moodleoverflow\subscriptions::unsubscribe_user_from_discussion($users[0]->id, $discussion, $modulecontext); + subscriptions::unsubscribe_user_from_discussion($users[0]->id, $discussion, $modulecontext); // All users should be subscribed. - $subscribers = \mod_moodleoverflow\subscriptions::get_subscribed_users($moodleoverflow, $modulecontext); + $subscribers = subscriptions::get_subscribed_users($moodleoverflow, $modulecontext); $this->assertEquals($usercount, count($subscribers)); // All users should be subscribed. - $subscribers = \mod_moodleoverflow\subscriptions::get_subscribed_users($moodleoverflow, $modulecontext, null, - true); + $subscribers = subscriptions::get_subscribed_users($moodleoverflow, $modulecontext, null, true); $this->assertEquals($usercount, count($subscribers)); // Manually insert an extra subscription for one of the users. @@ -936,35 +773,27 @@ public function test_fetch_subscribed_users_discussion_subscriptions(): void { $DB->insert_record('moodleoverflow_discuss_subs', $record); // The discussion count should not have changed. - $subscribers = \mod_moodleoverflow\subscriptions::get_subscribed_users($moodleoverflow, $modulecontext); + $subscribers = subscriptions::get_subscribed_users($moodleoverflow, $modulecontext); $this->assertEquals($usercount, count($subscribers)); - $subscribers = \mod_moodleoverflow\subscriptions::get_subscribed_users($moodleoverflow, $modulecontext, null, - true); + $subscribers = subscriptions::get_subscribed_users($moodleoverflow, $modulecontext, null, true); $this->assertEquals($usercount, count($subscribers)); // Unsubscribe 2 users. - $unsubscribedcount = 2; - for ($i = 0; $i < $unsubscribedcount; $i++) { - \mod_moodleoverflow\subscriptions::unsubscribe_user($users[$i]->id, $moodleoverflow, $modulecontext); - } + subscriptions::unsubscribe_user($users[0]->id, $moodleoverflow, $modulecontext); + subscriptions::unsubscribe_user($users[1]->id, $moodleoverflow, $modulecontext); // The subscription count should now take into account those users who have been unsubscribed. - $subscribers = \mod_moodleoverflow\subscriptions::get_subscribed_users($moodleoverflow, $modulecontext); - $this->assertEquals($usercount - $unsubscribedcount, count($subscribers)); - $subscribers = \mod_moodleoverflow\subscriptions::get_subscribed_users($moodleoverflow, $modulecontext, null, - true); - $this->assertEquals($usercount - $unsubscribedcount, count($subscribers)); + $subscribers = subscriptions::get_subscribed_users($moodleoverflow, $modulecontext); + $this->assertEquals($usercount - 2, count($subscribers)); + $subscribers = subscriptions::get_subscribed_users($moodleoverflow, $modulecontext, null, true); + $this->assertEquals($usercount - 2, count($subscribers)); // Now subscribe one of those users back to the discussion. - $subedusers = 1; - for ($i = 0; $i < $subedusers; $i++) { - \mod_moodleoverflow\subscriptions::subscribe_user_to_discussion($users[$i]->id, $discussion, $modulecontext); - } - $subscribers = \mod_moodleoverflow\subscriptions::get_subscribed_users($moodleoverflow, $modulecontext); - $this->assertEquals($usercount - $unsubscribedcount, count($subscribers)); - $subscribers = \mod_moodleoverflow\subscriptions::get_subscribed_users($moodleoverflow, $modulecontext, null, - true); - $this->assertEquals($usercount - $unsubscribedcount + $subedusers, count($subscribers)); + subscriptions::subscribe_user_to_discussion($users[0]->id, $discussion, $modulecontext); + $subscribers = subscriptions::get_subscribed_users($moodleoverflow, $modulecontext); + $this->assertEquals($usercount - 2, count($subscribers)); + $subscribers = subscriptions::get_subscribed_users($moodleoverflow, $modulecontext, null, true); + $this->assertEquals($usercount - 1, count($subscribers)); } /** @@ -972,7 +801,6 @@ public function test_fetch_subscribed_users_discussion_subscriptions(): void { */ public function test_force_subscribed_to_moodleoverflow(): void { global $DB; - // Reset database after testing. $this->resetAfterTest(true); @@ -992,7 +820,7 @@ public function test_force_subscribed_to_moodleoverflow(): void { $this->getDataGenerator()->enrol_user($user->id, $course->id, $roleids['student']); // Check that the user is currently subscribed to the moodleoverflow. - $this->assertTrue(\mod_moodleoverflow\subscriptions::is_subscribed($user->id, $moodleoverflow, $context)); + $this->assertTrue(subscriptions::is_subscribed($user->id, $moodleoverflow, $context)); assign_capability('mod/moodleoverflow:allowforcesubscribe', CAP_PROHIBIT, $roleids['student'], $context); @@ -1018,17 +846,17 @@ public function test_subscription_cache_prefill(): void { $users = $this->helper_create_users($course, 20); // Reset the subscription cache. - \mod_moodleoverflow\subscriptions::reset_moodleoverflow_cache(); + subscriptions::reset_moodleoverflow_cache(); // Filling the subscription cache should only use a single query, except for Postgres, which delegates actual reading // to Cursors, thus tripling the amount of queries. We intend to test the cache, though, so no worries. - $this->assertNull(\mod_moodleoverflow\subscriptions::fill_subscription_cache($moodleoverflow->id)); + $this->assertNull(subscriptions::fill_subscription_cache($moodleoverflow->id)); $postfillcount = $DB->perf_get_reads(); // Now fetch some subscriptions from that moodleoverflow - these should use // the cache and not perform additional queries. foreach ($users as $user) { - $this->assertTrue(\mod_moodleoverflow\subscriptions::fetch_subscription_cache($moodleoverflow->id, $user->id)); + $this->assertTrue(subscriptions::fetch_subscription_cache($moodleoverflow->id, $user->id)); } $finalcount = $DB->perf_get_reads(); $this->assertEquals($finalcount, $postfillcount); @@ -1053,14 +881,14 @@ public function test_subscription_cache_fill(): void { $users = $this->helper_create_users($course, 20); // Reset the subscription cache. - \mod_moodleoverflow\subscriptions::reset_moodleoverflow_cache(); + subscriptions::reset_moodleoverflow_cache(); // Filling the subscription cache should only use a single query. $startcount = $DB->perf_get_reads(); // Fetch some subscriptions from that moodleoverflow - these should not use the cache and will perform additional queries. foreach ($users as $user) { - $this->assertTrue(\mod_moodleoverflow\subscriptions::fetch_subscription_cache($moodleoverflow->id, $user->id)); + $this->assertTrue(subscriptions::fetch_subscription_cache($moodleoverflow->id, $user->id)); } $finalcount = $DB->perf_get_reads(); $this->assertEquals(20, $finalcount - $startcount); @@ -1080,34 +908,35 @@ public function test_discussion_subscription_cache_fill_for_course(): void { // Create the moodleoverflows. $options = ['course' => $course->id, 'forcesubscribe' => MOODLEOVERFLOW_DISALLOWSUBSCRIBE]; - $disallowmoodleoverflow = $this->getDataGenerator()->create_module('moodleoverflow', $options); + $disallowobject = $this->getDataGenerator()->create_module('moodleoverflow', $options); $options = ['course' => $course->id, 'forcesubscribe' => MOODLEOVERFLOW_CHOOSESUBSCRIBE]; - $choosemoodleoverflow = $this->getDataGenerator()->create_module('moodleoverflow', $options); + $chooseobject = $this->getDataGenerator()->create_module('moodleoverflow', $options); $options = ['course' => $course->id, 'forcesubscribe' => MOODLEOVERFLOW_INITIALSUBSCRIBE]; - $initialmoodleoverflow = $this->getDataGenerator()->create_module('moodleoverflow', $options); + $initialobject = $this->getDataGenerator()->create_module('moodleoverflow', $options); // Create some users and keep a reference to the first user. $users = $this->helper_create_users($course, 20); $user = reset($users); // Reset the subscription caches. - \mod_moodleoverflow\subscriptions::reset_moodleoverflow_cache(); + subscriptions::reset_moodleoverflow_cache(); - $result = \mod_moodleoverflow\subscriptions::fill_subscription_cache_for_course($course->id, $user->id); + $result = subscriptions::fill_subscription_cache_for_course($course->id, $user->id); $this->assertNull($result); $postfillcount = $DB->perf_get_reads(); - $this->assertFalse(\mod_moodleoverflow\subscriptions::fetch_subscription_cache($disallowmoodleoverflow->id, $user->id)); - $this->assertFalse(\mod_moodleoverflow\subscriptions::fetch_subscription_cache($choosemoodleoverflow->id, $user->id)); - $this->assertTrue(\mod_moodleoverflow\subscriptions::fetch_subscription_cache($initialmoodleoverflow->id, $user->id)); + $this->assertFalse(subscriptions::fetch_subscription_cache($disallowobject->id, $user->id)); + $this->assertFalse(subscriptions::fetch_subscription_cache($chooseobject->id, $user->id)); + $this->assertTrue(subscriptions::fetch_subscription_cache($initialobject->id, $user->id)); $finalcount = $DB->perf_get_reads(); $this->assertEquals(0, $finalcount - $postfillcount); // Test for all users. foreach ($users as $user) { - $result = \mod_moodleoverflow\subscriptions::fill_subscription_cache_for_course($course->id, $user->id); - $this->assertFalse(\mod_moodleoverflow\subscriptions::fetch_subscription_cache($disallowmoodleoverflow->id, $user->id)); - $this->assertFalse(\mod_moodleoverflow\subscriptions::fetch_subscription_cache($choosemoodleoverflow->id, $user->id)); - $this->assertTrue(\mod_moodleoverflow\subscriptions::fetch_subscription_cache($initialmoodleoverflow->id, $user->id)); + $result = subscriptions::fill_subscription_cache_for_course($course->id, $user->id); + $this->assertNull($result); + $this->assertFalse(subscriptions::fetch_subscription_cache($disallowobject->id, $user->id)); + $this->assertFalse(subscriptions::fetch_subscription_cache($chooseobject->id, $user->id)); + $this->assertTrue(subscriptions::fetch_subscription_cache($initialobject->id, $user->id)); } $finalcount = $DB->perf_get_reads(); $reads = $finalcount - $postfillcount; @@ -1162,24 +991,24 @@ public function test_discussion_subscription_cache_prefill(): void { if ($usercount % 2) { continue; } - \mod_moodleoverflow\subscriptions::unsubscribe_user_from_discussion($user->id, $discussion, $modulecontext); + subscriptions::unsubscribe_user_from_discussion($user->id, $data, $modulecontext); $usercount++; } $moodleoverflowcount++; } // Reset the subscription caches. - \mod_moodleoverflow\subscriptions::reset_moodleoverflow_cache(); - \mod_moodleoverflow\subscriptions::reset_discussion_cache(); + subscriptions::reset_moodleoverflow_cache(); + subscriptions::reset_discussion_cache(); // Filling the discussion subscription cache should only use a single query. - $this->assertNull(\mod_moodleoverflow\subscriptions::fill_discussion_subscription_cache($moodleoverflow->id)); + $this->assertNull(subscriptions::fill_discussion_subscription_cache($moodleoverflow->id)); $postfillcount = $DB->perf_get_reads(); // Now fetch some subscriptions from that moodleoverflow - these should use // the cache and not perform additional queries. foreach ($users as $user) { - $result = \mod_moodleoverflow\subscriptions::fetch_discussion_subscription($moodleoverflow->id, $user->id); + $result = subscriptions::fetch_discussion_subscription($moodleoverflow->id, $user->id); $this->assertIsArray($result); } $finalcount = $DB->perf_get_reads(); @@ -1229,22 +1058,22 @@ public function test_discussion_subscription_cache_fill(): void { if ($usercount % 2) { continue; } - \mod_moodleoverflow\subscriptions::unsubscribe_user_from_discussion($user->id, $discussion, $modulecontext); + subscriptions::unsubscribe_user_from_discussion($user->id, $data, $modulecontext); $usercount++; } $moodleoverflowcount++; } // Reset the subscription caches. - \mod_moodleoverflow\subscriptions::reset_moodleoverflow_cache(); - \mod_moodleoverflow\subscriptions::reset_discussion_cache(); + subscriptions::reset_moodleoverflow_cache(); + subscriptions::reset_discussion_cache(); $startcount = $DB->perf_get_reads(); // Now fetch some subscriptions from that moodleoverflow - these should use // the cache and not perform additional queries. foreach ($users as $user) { - $result = \mod_moodleoverflow\subscriptions::fetch_discussion_subscription($moodleoverflow->id, $user->id); + $result = subscriptions::fetch_discussion_subscription($moodleoverflow->id, $user->id); $this->assertIsArray($result); } $finalcount = $DB->perf_get_reads(); @@ -1268,16 +1097,12 @@ public function test_moodleoverflow_subscribe_toggle_as_other_repeat_subscriptio // Reset the database after testing. $this->resetAfterTest(true); - // Create a course, with a moodleoverflow. + // Create a course, with a moodleoverflow and get the module context. Create a user enrolled in the course as a student. $course = $this->getDataGenerator()->create_course(); $options = ['course' => $course->id, 'forcesubscribe' => MOODLEOVERFLOW_CHOOSESUBSCRIBE]; $moodleoverflow = $this->getDataGenerator()->create_module('moodleoverflow', $options); - - // Get the module context. $cm = get_coursemodule_from_instance('moodleoverflow', $moodleoverflow->id); $modulecontext = \context_module::instance($cm->id); - - // Create a user enrolled in the course as a student. list($user) = $this->helper_create_users($course, 1); // Post a discussion to the moodleoverflow. @@ -1286,73 +1111,52 @@ public function test_moodleoverflow_subscribe_toggle_as_other_repeat_subscriptio unset($post); $discussion->moodleoverflow = $moodleoverflow->id; + // Declare the options for the subscription tables. + $discussoptions = ['userid' => $user->id, 'discussion' => $discussion->id]; + $subscriptionoptions = ['userid' => $user->id, 'moodleoverflow' => $moodleoverflow->id]; + // Confirm that the user is currently not subscribed to the moodleoverflow. - $this->assertFalse(\mod_moodleoverflow\subscriptions::is_subscribed($user->id, $moodleoverflow, $modulecontext)); + $this->assertFalse(subscriptions::is_subscribed($user->id, $moodleoverflow, $modulecontext)); // Confirm that the user is unsubscribed from the discussion too. - $this->assertFalse(\mod_moodleoverflow\subscriptions::is_subscribed($user->id, $moodleoverflow, $modulecontext, - $discussion->id)); + $this->assertFalse(subscriptions::is_subscribed($user->id, $moodleoverflow, $modulecontext, $discussion->id)); // Confirm that we have no records in either of the subscription tables. - $this->assertEquals(0, $DB->count_records('moodleoverflow_subscriptions', [ - 'userid' => $user->id, - 'moodleoverflow' => $moodleoverflow->id, - ])); - $this->assertEquals(0, $DB->count_records('moodleoverflow_discuss_subs', [ - 'userid' => $user->id, - 'discussion' => $discussion->id, - ])); + $this->assertEquals(0, $DB->count_records('moodleoverflow_subscriptions', $subscriptionoptions)); + $this->assertEquals(0, $DB->count_records('moodleoverflow_discuss_subs', $discussoptions)); // Subscribing to the moodleoverflow should create a record in the subscriptions table, // but not the moodleoverflow discussion subscriptions table. - \mod_moodleoverflow\subscriptions::subscribe_user($user->id, $moodleoverflow, $modulecontext); - $this->assertEquals(1, $DB->count_records('moodleoverflow_subscriptions', [ - 'userid' => $user->id, - 'moodleoverflow' => $moodleoverflow->id, - ])); - $this->assertEquals(0, $DB->count_records('moodleoverflow_discuss_subs', [ - 'userid' => $user->id, - 'discussion' => $discussion->id, - ])); + subscriptions::subscribe_user($user->id, $moodleoverflow, $modulecontext); + $this->assertEquals(1, $DB->count_records('moodleoverflow_subscriptions', $subscriptionoptions)); + $this->assertEquals(0, $DB->count_records('moodleoverflow_discuss_subs', $discussoptions)); // Now unsubscribe from the discussion. This should return true. $uid = $user->id; - $this->assertTrue(\mod_moodleoverflow\subscriptions::unsubscribe_user_from_discussion($uid, $discussion, $modulecontext)); + $this->assertTrue(subscriptions::unsubscribe_user_from_discussion($uid, $discussion, $modulecontext)); // Attempting to unsubscribe again should return false because no change was made. - $this->assertFalse(\mod_moodleoverflow\subscriptions::unsubscribe_user_from_discussion($uid, $discussion, $modulecontext)); + $this->assertFalse(subscriptions::unsubscribe_user_from_discussion($uid, $discussion, $modulecontext)); // Subscribing to the discussion again should return truthfully as the subscription preference was removed. - $this->assertTrue(\mod_moodleoverflow\subscriptions::subscribe_user_to_discussion($user->id, $discussion, $modulecontext)); + $this->assertTrue(subscriptions::subscribe_user_to_discussion($user->id, $discussion, $modulecontext)); // Attempting to subscribe again should return false because no change was made. - $this->assertFalse(\mod_moodleoverflow\subscriptions::subscribe_user_to_discussion($user->id, $discussion, $modulecontext)); + $this->assertFalse(subscriptions::subscribe_user_to_discussion($user->id, $discussion, $modulecontext)); // Now unsubscribe from the discussion. This should return true once more. - $this->assertTrue(\mod_moodleoverflow\subscriptions::unsubscribe_user_from_discussion($uid, $discussion, $modulecontext)); + $this->assertTrue(subscriptions::unsubscribe_user_from_discussion($uid, $discussion, $modulecontext)); // And unsubscribing from the moodleoverflow but not as a request from the user should maintain their preference. - \mod_moodleoverflow\subscriptions::unsubscribe_user($user->id, $moodleoverflow, $modulecontext); + subscriptions::unsubscribe_user($user->id, $moodleoverflow, $modulecontext); - $this->assertEquals(0, $DB->count_records('moodleoverflow_subscriptions', [ - 'userid' => $user->id, - 'moodleoverflow' => $moodleoverflow->id, - ])); - $this->assertEquals(1, $DB->count_records('moodleoverflow_discuss_subs', [ - 'userid' => $user->id, - 'discussion' => $discussion->id, - ])); + $this->assertEquals(0, $DB->count_records('moodleoverflow_subscriptions', $subscriptionoptions)); + $this->assertEquals(1, $DB->count_records('moodleoverflow_discuss_subs', $discussoptions)); // Subscribing to the discussion should return truthfully because a change was made. - $this->assertTrue(\mod_moodleoverflow\subscriptions::subscribe_user_to_discussion($user->id, $discussion, $modulecontext)); - $this->assertEquals(0, $DB->count_records('moodleoverflow_subscriptions', [ - 'userid' => $user->id, - 'moodleoverflow' => $moodleoverflow->id, - ])); - $this->assertEquals(1, $DB->count_records('moodleoverflow_discuss_subs', [ - 'userid' => $user->id, - 'discussion' => $discussion->id, - ])); + $this->assertTrue(subscriptions::subscribe_user_to_discussion($user->id, $discussion, $modulecontext)); + $this->assertEquals(0, $DB->count_records('moodleoverflow_subscriptions', $subscriptionoptions)); + $this->assertEquals(1, $DB->count_records('moodleoverflow_discuss_subs', $discussoptions)); } /** @@ -1361,20 +1165,8 @@ public function test_moodleoverflow_subscribe_toggle_as_other_repeat_subscriptio * @return array */ public static function is_subscribable_moodleoverflows() { - return [ - [ - 'forcesubscribe' => MOODLEOVERFLOW_DISALLOWSUBSCRIBE, - ], - [ - 'forcesubscribe' => MOODLEOVERFLOW_CHOOSESUBSCRIBE, - ], - [ - 'forcesubscribe' => MOODLEOVERFLOW_INITIALSUBSCRIBE, - ], - [ - 'forcesubscribe' => MOODLEOVERFLOW_FORCESUBSCRIBE, - ], - ]; + return [['forcesubscribe' => MOODLEOVERFLOW_DISALLOWSUBSCRIBE], ['forcesubscribe' => MOODLEOVERFLOW_CHOOSESUBSCRIBE], + ['forcesubscribe' => MOODLEOVERFLOW_INITIALSUBSCRIBE], ['forcesubscribe' => MOODLEOVERFLOW_FORCESUBSCRIBE], ]; } /** @@ -1387,7 +1179,6 @@ public static function is_subscribable_provider(): array { foreach (self::is_subscribable_moodleoverflows() as $moodleoverflow) { $data[] = [$moodleoverflow]; } - return $data; } @@ -1407,8 +1198,7 @@ public function test_is_subscribable_logged_out($options): void { $options['course'] = $course->id; $moodleoverflow = $this->getDataGenerator()->create_module('moodleoverflow', $options); - $this->assertFalse(\mod_moodleoverflow\subscriptions::is_subscribable($moodleoverflow, - \context_module::instance($moodleoverflow->cmid))); + $this->assertFalse(subscriptions::is_subscribable($moodleoverflow, \context_module::instance($moodleoverflow->cmid))); } /** @@ -1432,8 +1222,7 @@ public function test_is_subscribable_is_guest($options): void { $options['course'] = $course->id; $moodleoverflow = $this->getDataGenerator()->create_module('moodleoverflow', $options); - $this->assertFalse(\mod_moodleoverflow\subscriptions::is_subscribable($moodleoverflow, - \context_module::instance($moodleoverflow->cmid))); + $this->assertFalse(subscriptions::is_subscribable($moodleoverflow, \context_module::instance($moodleoverflow->cmid))); } /** @@ -1442,22 +1231,10 @@ public function test_is_subscribable_is_guest($options): void { */ public static function is_subscribable_loggedin_provider(): array { return [ - [ - ['forcesubscribe' => MOODLEOVERFLOW_DISALLOWSUBSCRIBE], - false, - ], - [ - ['forcesubscribe' => MOODLEOVERFLOW_CHOOSESUBSCRIBE], - true, - ], - [ - ['forcesubscribe' => MOODLEOVERFLOW_INITIALSUBSCRIBE], - true, - ], - [ - ['forcesubscribe' => MOODLEOVERFLOW_FORCESUBSCRIBE], - false, - ], + [['forcesubscribe' => MOODLEOVERFLOW_DISALLOWSUBSCRIBE], false], + [['forcesubscribe' => MOODLEOVERFLOW_CHOOSESUBSCRIBE], true], + [['forcesubscribe' => MOODLEOVERFLOW_INITIALSUBSCRIBE], true], + [['forcesubscribe' => MOODLEOVERFLOW_FORCESUBSCRIBE], false], ]; } @@ -1484,7 +1261,7 @@ public function test_is_subscribable_loggedin($options, $expect): void { $this->getDataGenerator()->enrol_user($user->id, $course->id); $this->setUser($user); - $this->assertEquals($expect, \mod_moodleoverflow\subscriptions::is_subscribable($moodleoverflow, - \context_module::instance($moodleoverflow->cmid))); + $this->assertEquals($expect, subscriptions::is_subscribable($moodleoverflow, + \context_module::instance($moodleoverflow->cmid))); } } diff --git a/tests/userstats_test.php b/tests/userstats_test.php index 080a11dd95..037b1db1f6 100644 --- a/tests/userstats_test.php +++ b/tests/userstats_test.php @@ -230,7 +230,6 @@ public function test_total_anonymous(): void { // Get the current userstats to compare later. $olduserstats = $this->create_statstable(); - $oldupvotesuser1 = $this->get_specific_userstats($olduserstats, $this->user1, 'receivedupvotes'); $oldactivityuser1 = $this->get_specific_userstats($olduserstats, $this->user1, 'forumactivity'); $oldupvotesuser2 = $this->get_specific_userstats($olduserstats, $this->user2, 'receivedupvotes'); diff --git a/tracking.php b/tracking.php index b152d5d439..4c5c5b2224 100644 --- a/tracking.php +++ b/tracking.php @@ -25,6 +25,7 @@ // Require needed files. require_once("../../config.php"); require_once("locallib.php"); +global $CFG, $DB, $USER; // Get submitted parameters. $id = required_param('id', PARAM_INT); // The moodleoverflow to track or untrack. @@ -34,14 +35,10 @@ require_sesskey(); // Retrieve the moodleoverflow instance to track or untrack. -if (!$moodleoverflow = $DB->get_record("moodleoverflow", ["id" => $id])) { - throw new moodle_exception('invalidmoodleoverflowid', 'moodleoverflow'); -} +$moodleoverflow = moodleoverflow_get_record_or_exception('moodleoverflow', ['id' => $id], 'invalidmoodleoverflowid'); // Retrieve the course of the instance. -if (!$course = $DB->get_record("course", ["id" => $moodleoverflow->course])) { - throw new moodle_exception('invalidcoursemodule'); -} +$course = moodleoverflow_get_record_or_exception('course', ['id' => $moodleoverflow->course], 'invalidcourseid', '*', true); // Retrieve the course module of that course. if (!$cm = get_coursemodule_from_instance("moodleoverflow", $moodleoverflow->id, $course->id)) { @@ -95,9 +92,7 @@ redirect($returnpageurl, get_string('nownottracking', 'moodleoverflow', $info), 1); } else { - // The insertion failed. - - // Print an error message. + // The insertion failed. Print an error message. throw new moodle_exception('cannottrack', 'moodleoverflow', get_local_referer(false)); } @@ -116,9 +111,7 @@ redirect($returnto, get_string('nowtracking', 'moodleoverflow', $info), 1); } else { - // The deletion failed. - - // Print an error message. + // The deletion failed. Print an error message. throw new moodle_exception('cannottrack', 'moodleoverflow', get_local_referer(false)); } } diff --git a/view.php b/view.php index 4178d7913d..52b55a157a 100644 --- a/view.php +++ b/view.php @@ -65,7 +65,6 @@ // Save the allowmultiplemarks setting. $marksetting = $DB->get_record('moodleoverflow', ['id' => $moodleoverflow->id], 'allowmultiplemarks'); - // Require a login. require_login($course, true, $cm);