/** * Convenience function for subclasses. Returns HTML code suitable to * use for a button in this area. * @param mod_forumng_discussion $discussion * @param string $name Text of button * @param string $script Name/path of .php script (relative to mod/forumng) * @param bool $post If true, makes the button send a POST request * @param array $options If included, passes these options as well as 'd' * @param string $extrahtml If specified, adds this HTML at end of (just * inside) the form * @param bool $highlight If true, adds a highlight class to the form * @param bool $selector If true, adds a selector class to the form (indicating that the * JavaScript post selector should be used) * @return string HTML code for button */ protected static function get_button($discussion, $name, $script, $post = false, $options = array(), $extrahtml = '', $highlight = false, $selector = false) { $method = $post ? 'post' : 'get'; $optionshtml = ''; $options['d'] = $discussion->get_id(); if ($discussion->get_forum()->is_shared()) { $options['clone'] = $discussion->get_forum()->get_course_module_id(); } if ($post) { $options['sesskey'] = sesskey(); } foreach ($options as $key => $value) { $optionshtml .= '<input type="hidden" name="' . $key . '" value="' . $value . '" />'; } $class = ''; if ($highlight) { $class = 'forumng-highlight'; } if ($selector) { $class .= ' forumng-selectorbutton'; } if ($class !== '') { $class = ' class="' . trim($class) . '"'; } return "<form method='{$method}' action='{$script}' {$class}><div>" . "{$optionshtml}<input type='submit' value='{$name}' />" . "{$extrahtml}</div></form>"; }
/** * Adds a discussion to the list (internal use only). * @param mod_forumng_discussion $discussion */ function add_discussion($discussion) { if ($discussion->is_sticky() && !$discussion->is_deleted()) { $this->stickydiscussions[$discussion->get_id()] = $discussion; } else { $this->normaldiscussions[$discussion->get_id()] = $discussion; } }
function forumngfeature_usage_show_mostreaders($params, $forum = null) { global $DB, $PAGE; $cloneid = empty($params['clone']) ? 0 : $params['clone']; if ($forum == null) { if (empty($params['id'])) { throw new moodle_exception('Missing forum id param'); } $forum = mod_forumng::get_from_cmid($params['id'], $cloneid); } $groupwhere = ''; $groupparams = array(); $groupid = 0; if (!empty($params['group']) && $params['group'] != mod_forumng::NO_GROUPS && $params['group'] != mod_forumng::ALL_GROUPS) { $groupwhere = 'AND (fd.groupid = :groupid OR fd.groupid IS NULL)'; $groupid = $params['group']; $groupparams = array('groupid' => $groupid); } if (has_capability('mod/forumng:viewreadinfo', $forum->get_context())) { if (!$PAGE->has_set_url()) { // Set context when called via ajax. $PAGE->set_context($forum->get_context()); } $renderer = $PAGE->get_renderer('forumngfeature_usage'); // Only get enrolled users - speeds up query significantly on large forums. list($sql, $params) = get_enrolled_sql($forum->get_context(), '', $groupid, true); // View discussions read. $readers = $DB->get_recordset_sql("\n SELECT COUNT(fr.userid) AS count, fr.discussionid\n FROM {forumng_discussions} fd\n RIGHT JOIN (\n\t\t SELECT discussionid, userid\n\t\t FROM (\n\t\t SELECT * FROM {forumng_read}\n\t\t UNION ALL\n\t\t SELECT frp.id, frp.userid, fp.discussionid, frp.time\n FROM {forumng_posts} fp\n RIGHT JOIN {forumng_read_posts} frp ON fp.id = frp.postid\n WHERE fp.deleted = 0 AND fp.oldversion = 0\n ) frp GROUP BY discussionid, userid\n ) fr ON fr.discussionid = fd.id\n WHERE fd.forumngid = :courseid\n AND fd.deleted = 0\n {$groupwhere}\n AND fr.userid IN({$sql})\n GROUP BY fr.discussionid\n ORDER BY count desc, fr.discussionid desc", array_merge(array('courseid' => $forum->get_id()), $groupparams, $params), 0, 5); $readerlist = array(); foreach ($readers as $discuss) { $discussion = mod_forumng_discussion::get_from_id($discuss->discussionid, $cloneid); list($content, $user) = $renderer->render_usage_discussion_info($forum, $discussion); $readerlist[] = $renderer->render_usage_list_item($forum, $discuss->count, $user, $content); } return $renderer->render_usage_list($readerlist, 'mostreaders', false); } }
public function apply($discussion, $all, $selected, $formdata) { global $CFG; $filecontext = $discussion->get_context(); $forum = $discussion; if (!isset($formdata->mailnow)) { $formdata->mailnow = false; } foreach ($selected as $postid) { // Call the lock for selected discussions. $discussion = mod_forumng_discussion::get_from_id($postid, $formdata->clone); if (!$discussion->is_deleted() && !$discussion->is_locked()) { $newpostid = $discussion->lock($formdata->subject, $formdata->message['text'], $formdata->message['format'], $formdata->attachments, $formdata->mailnow, '', '', $formdata->asmoderator); // Save attachments. file_save_draft_area_files($formdata->attachments, $filecontext->id, 'mod_forumng', 'attachment', $newpostid, null); $newtext = file_save_draft_area_files($formdata->message['itemid'], $filecontext->id, 'mod_forumng', 'message', $newpostid, null, $formdata->message['text']); if ($newtext !== $formdata->message['text']) { mod_forumng_post::update_message_for_files($newpostid, $newtext); } } } // Redirect to the Main page. redirect('../../view.php?' . $forum->get_link_params(mod_forumng::PARAM_PLAIN)); }
/** * Obtain all flagged discussions in the forum by the given or current user, * The results should be ordered by the last post modified date (fplast.modified DESC) * @param int $userid User whose flags will be retrieved; 0 = current * @return array Array of mod_forumng_discussion objects */ public function get_flagged_discussions($userid = 0) { global $USER; if ($userid != -1) { if ($userid == 0) { $userid = $USER->id; } $records = mod_forumng_discussion::query_discussions('fd.forumngid = ? AND ff.flagged IS NOT NULL AND ff.discussionid = fd.id AND ff.userid = ?', array($this->get_id(), $userid), $userid, 'x.flagged DESC', '', '', $this, true); } $result = array(); foreach ($records as $record) { // Get discussion details from record and create discussionfields. $discussion = new mod_forumng_discussion($this, $record, true, $userid); $result[$record->id] = $discussion; } return $result; }
/** * Either delete or archive old discussions based on the forum setting */ public static function archive_old_discussions() { global $CFG, $DB; $now = time(); $housekeepingquery = "\nFROM\n {forumng_discussions} fd\n INNER JOIN {forumng_posts} fp ON fd.lastpostid = fp.id\n INNER JOIN {forumng} f ON fd.forumngid = f.id\nWHERE\n f.removeafter<>0 AND fd.sticky<>1 AND fp.modified<? - f.removeafter\n"; $housekeepingparams = array($now); $count = $DB->count_records_sql("SELECT COUNT(1) {$housekeepingquery}", $housekeepingparams); if ($count) { if (!PHPUNIT_TEST) { mtrace("\nBeginning processing {$count} discussion archiving/deleting requests"); } $housekeepingrs = $DB->get_recordset_sql("\nSELECT\n fd.id AS discussionid, f.id AS forumngid, f.removeafter, f.removeto\n{$housekeepingquery}\nORDER BY f.removeto", $housekeepingparams); $targetforum = null; $targetcourseid = null; $cronlog = ''; $discussionmovecount = 0; $discussiondeletecount = 0; $discussionautolocked = 0; foreach ($housekeepingrs as $rec) { $discussion = mod_forumng_discussion::get_from_id($rec->discussionid, mod_forumng::CLONE_DIRECT); if ($rec->removeto) { if ($rec->removeto == -1) { // Locked record or discussion deleted. if ($discussion->is_locked() || $discussion->is_auto_locked() || $discussion->is_deleted()) { continue; } else { $end = $discussion->get_time_end(); $canautolock = true; // Check to see whether time now is beyond the end time. if ($end > $now) { $canautolock = false; } if ($canautolock) { // Lock record. $discussion->auto_lock(); $discussionautolocked++; } else { continue; } } } else { // Moving to a different forum. $forum = $discussion->get_forum(); $course = $forum->get_course(); $modinfo = get_fast_modinfo($course); if ($forum->can_archive_forum($modinfo, $cronlog)) { // Do not get the target forum and course id again // if the target forum is the same. if (!$targetforum || $targetforum->get_id() != $rec->removeto) { $targetforum = mod_forumng::get_from_id($rec->removeto, mod_forumng::CLONE_DIRECT); $targetforum = $targetforum->get_real_forum(); } // Target discussion groupid must be the same as the original groupid. $targetgroupmode = $targetforum->get_group_mode(); $targetgroupid = $targetgroupmode ? $discussion->get_group_id() : null; $discussion->move($targetforum, $targetgroupid); $discussionmovecount++; } } } else { // Delete all discussions and relevant data permanently. $discussion->permanently_delete(); $discussiondeletecount++; } } $housekeepingrs->close(); if (!PHPUNIT_TEST) { mtrace("\n {$discussionmovecount} discussions have been archived and " . "{$discussiondeletecount} discussions have been deleted permanently and " . "{$discussionautolocked} discussions have been automatically locked"); } } }
/** * Either delete or archive old discussions based on the forum setting */ static function archive_old_discussions() { global $CFG, $DB; $now = time(); $housekeepingquery = "\nFROM\n {forumng_discussions} fd\n INNER JOIN {forumng_posts} fp ON fd.lastpostid = fp.id\n INNER JOIN {forumng} f ON fd.forumngid = f.id\nWHERE\n f.removeafter<>0 AND fd.sticky<>1 AND fp.modified<? - f.removeafter\n"; $housekeepingparams = array($now); $count = $DB->count_records_sql("SELECT COUNT(1) {$housekeepingquery}", $housekeepingparams); if ($count) { mtrace("\nBeginning processing {$count} discussion archiving/deleting requests"); $housekeepingrs = $DB->get_recordset_sql("\nSELECT\n fd.id AS discussionid, f.id AS forumngid, f.removeafter, f.removeto\n{$housekeepingquery}\nORDER BY f.removeto", $housekeepingparams); $targetforum = null; $targetcourseid = null; $cronlog = ''; $discussionmovecount = 0; $discussiondeletecount = 0; foreach ($housekeepingrs as $rec) { $discussion = mod_forumng_discussion::get_from_id($rec->discussionid, mod_forumng::CLONE_DIRECT); if ($rec->removeto) { //moving to a different forum $forum = $discussion->get_forum(); $course = $forum->get_course(); $modinfo = get_fast_modinfo($course); if ($forum->can_archive_forum($modinfo, $cronlog)) { // Do not get the target forum and course id again // if the target forum is the same if (!$targetforum || $targetforum->get_id() != $rec->removeto) { $targetforum = mod_forumng::get_from_id($rec->removeto, mod_forumng::CLONE_DIRECT); $targetforum = $targetforum->get_real_forum(); } //target discussion groupid must be the same as the original groupid $targetgroupmode = $targetforum->get_group_mode(); $targetgroupid = $targetgroupmode ? $discussion->get_group_id() : null; $discussion->move($targetforum, $targetgroupid); $discussionmovecount++; } } else { //Delete all discussions and relevant data permanently $discussion->permanently_delete(); $discussiondeletecount++; } } $housekeepingrs->close(); mtrace("\n {$discussionmovecount} discussions have been archived and " . "{$discussiondeletecount} discussions have been deleted permanently."); } }
public function load_data() { global $DB, $COURSE; // Load base data $this->load_base_data($this->forumngid); // Get all files used in the discussions. if ($this->discussionids == '') { // Fallback in case nothing sent - get every discussion in forum! $this->discussionids = array(); $groupid = mod_forumng::get_activity_group($this->cm, true); if ($groupid == -1) { $groupid = null; } $discussions = $DB->get_records('forumng_discussions', array('forumngid' => $this->cm->instance, 'groupid' => $groupid), '', 'id, postid'); foreach ($discussions as $discussionrec) { if (!$discussionrec->postid) { continue; } $discussion = mod_forumng_discussion::get_from_id($discussionrec->id, $this->cloneid); if ($discussion->can_view()) { $this->discussionids[] = $discussion->get_id(); } } } else { $this->posts = $this->discussionids; // Set so decode works. $this->discussionids = $this->decode_string_to_array(); $this->posts = ''; } if (empty($this->discussionids)) { throw new moodle_exception('exportallnodisc', 'forumngfeature_export', $this->get_return_url()); } foreach ($this->discussionids as $discussionid) { $this->discussionid = $discussionid; $this->add_files(); } }
/** * Called when displaying a group of posts together on one page. * @param mod_forumng_discussion $discussion Forum object * @param string $html HTML that has already been created for the group * of posts * @return string Modified (if necessary) HTML */ public function render_post_group($discussion, $html) { // Add ForumNG rating form if there are any ForumNG rating selects. // Check any Form exists before adding actionform. $hasratings = strpos($html, '<div class="forumng-editrating">') !== false; $hasform = strpos($html, '<form') !== false; if ($hasratings && !$hasform) { $script = '<script type="text/javascript">' . 'document.getElementById("forumng-actionform").autocomplete=false;' . '</script>'; $html = '<form method="post" id="forumng-actionform" ' . 'action="action.php"><div>' . $script . $html . $discussion->get_link_params(mod_forumng::PARAM_FORM); if ($hasratings) { $html .= '<input type="submit" id="forumng-saveallratings" value="' . get_string('saveallratings', 'forumng') . '" name="action.rate"/>'; } $html .= '</div></form>'; } return $html; }
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ require_once '../../config.php'; require_once 'mod_forumng.php'; // Require discussion parameter here. Other parameters may be required in forum // type. $discussionid = required_param('d', PARAM_INT); $pageparams = array('d' => $discussionid); $cloneid = optional_param('clone', 0, PARAM_INT); if ($cloneid) { $pageparams['clone'] = $cloneid; } // Construct discussion variable (will check id is valid) // Retrieve new copy of discussion from database, but store it in cache // for further use. $discussion = mod_forumng_discussion::get_from_id($discussionid, $cloneid, 0, false, true); $forum = $discussion->get_forum(); $course = $forum->get_course(); $cm = $forum->get_course_module(); $context = $forum->get_context(); $draftid = optional_param('draft', 0, PARAM_INT); if ($draftid) { $pageparams['draft'] = $draftid; $draft = mod_forumng_draft::get_from_id($draftid); if (!$draft->is_reply() || $draft->get_discussion_id() != $discussionid) { print_error('draft_mismatch', 'forumng', $forum->get_url(mod_forumng::PARAM_HTML)); } $root = $discussion->get_root_post(); $inreplyto = $root->find_child($draft->get_parent_post_id(), false); if (!$inreplyto || !$inreplyto->can_reply($whynot) || !$discussion->can_view()) { if (!$whynot) {
/** * Extend tests that check forumns and discussions being marked as read. * */ public function test_discussions_mark_read() { global $USER, $DB; $this->resetAfterTest(true); $this->setAdminUser(); $adminid = $USER->id; $generator = $this->getDataGenerator()->get_plugin_generator('mod_forumng'); $course = $this->get_new_course(); $etuser1 = $this->get_new_user('editingteacher', $course->id); $suser1 = $this->get_new_user('student', $course->id); $suser2 = $this->get_new_user('student', $course->id); $group1 = $this->get_new_group($course->id); $group2 = $this->get_new_group($course->id); $this->get_new_group_member($group1->id, $etuser1->id); $this->get_new_group_member($group1->id, $suser1->id); // Create 2 forums (1 group forum, 1 no groups), each with 1 discussion. $forum1 = $this->get_new_forumng($course->id, array('groupmode' => VISIBLEGROUPS)); $forum2 = $this->get_new_forumng($course->id); $did1 = $generator->create_discussion(array('course' => $course, 'forum' => $forum1->get_id(), 'userid' => $etuser1->id, 'groupid' => $group1->id)); $did2 = $generator->create_discussion(array('course' => $course, 'forum' => $forum2->get_id(), 'userid' => $etuser1->id)); // Set the time for offset use. $posttime = time(); // Ensure user prefs allow discussions/posts to be marked as read 'automatically'. unset_user_preference('forumng_manualmark', $etuser1); unset_user_preference('forumng_manualmark', $suser1); // Root post auto marked as read for ET the creator, of forum1 at group level. $etforums = mod_forumng::get_course_forums($course, $etuser1->id, mod_forumng::UNREAD_DISCUSSIONS); // Forum contains discussion post read by etuser1. $this->assertFalse($etforums[$forum1->get_id()]->has_unread_discussions()); $this->assertEquals(0, $etforums[$forum1->get_id()]->get_num_unread_discussions()); // Suser1 has NOT read root posts. $s1forums = mod_forumng::get_course_forums($course, $suser1->id, mod_forumng::UNREAD_DISCUSSIONS); // Forums contain discussion posts NOT read by Suser1. $this->assertTrue($s1forums[$forum1->get_id()]->has_unread_discussions()); $this->assertTrue($s1forums[$forum2->get_id()]->has_unread_discussions()); // Discussion contains posts NOT read by S1. $this->assertEquals(1, $s1forums[$forum1->get_id()]->get_num_unread_discussions()); $this->assertEquals(1, $s1forums[$forum2->get_id()]->get_num_unread_discussions()); // User Prefs allow the marking of both discussion root posts as read 'automatically'. $posttime = $posttime + 2; $did1read = mod_forumng_discussion::get_from_id($did1[0], 0); $did1read->mark_read($posttime, $suser1->id); $did2read = mod_forumng_discussion::get_from_id($did2[0], 0); $did2read->mark_read($posttime, $suser1->id); // Check the root posts now marked as read for S1. $s1forums = mod_forumng::get_course_forums($course, $suser1->id, mod_forumng::UNREAD_DISCUSSIONS); // Forums contain NO discussions not read by Suser1. $this->assertFalse($s1forums[$forum1->get_id()]->has_unread_discussions()); $this->assertFalse($s1forums[$forum2->get_id()]->has_unread_discussions()); // No forumn discussions contain root posts not read by Suser1. $this->assertEquals(0, $s1forums[$forum1->get_id()]->get_num_unread_discussions()); $this->assertEquals(0, $s1forums[$forum2->get_id()]->get_num_unread_discussions()); // Set user pref so discussions/posts marked 'manually'. set_user_preference('forumng_manualmark', 1, $etuser1); set_user_preference('forumng_manualmark', 1, $suser1); // Add extra posts to both discussions with time modified offset. $posttime = $posttime + 2; $did1s1p1 = $generator->create_post(array('discussionid' => $did1[0], 'parentpostid' => $did1[1], 'userid' => $suser1->id, 'modified' => $posttime)); $did1etp1 = $generator->create_post(array('discussionid' => $did1[0], 'parentpostid' => $did1[1], 'userid' => $etuser1->id, 'modified' => $posttime)); $did1s2p1 = $generator->create_post(array('discussionid' => $did1[0], 'parentpostid' => $did1[1], 'userid' => $suser2->id, 'modified' => $posttime)); $did2s1p2 = $generator->create_post(array('discussionid' => $did2[0], 'parentpostid' => $did2[1], 'userid' => $suser1->id, 'modified' => $posttime)); $did2etp2 = $generator->create_post(array('discussionid' => $did2[0], 'parentpostid' => $did2[1], 'userid' => $etuser1->id, 'modified' => $posttime)); $did2s2p1 = $generator->create_post(array('discussionid' => $did2[0], 'parentpostid' => $did2[1], 'userid' => $suser2->id, 'modified' => $posttime)); $did1s1post1 = mod_forumng_post::get_from_id($did1s1p1->id, 0); $did2s1post2 = mod_forumng_post::get_from_id($did2s1p2->id, 0); $did1etpost1 = mod_forumng_post::get_from_id($did1etp1->id, 0); $did2etpost2 = mod_forumng_post::get_from_id($did2etp2->id, 0); $did1s2post1 = mod_forumng_post::get_from_id($did1s2p1->id, 0); $did2s2post1 = mod_forumng_post::get_from_id($did2s2p1->id, 0); // Check read status of new posts. $etforums = mod_forumng::get_course_forums($course, $etuser1->id, mod_forumng::UNREAD_DISCUSSIONS); // Discussions DO have posts not read by ET. $this->assertTrue($etforums[$forum1->get_id()]->has_unread_discussions()); $this->assertTrue($etforums[$forum2->get_id()]->has_unread_discussions()); // A number of discussions contain posts NOT read by ET. $this->assertEquals(1, $etforums[$forum1->get_id()]->get_num_unread_discussions()); $this->assertEquals(1, $etforums[$forum2->get_id()]->get_num_unread_discussions()); $s1forums = mod_forumng::get_course_forums($course, $suser1->id, mod_forumng::UNREAD_DISCUSSIONS); // Discussions DO have posts not read by Suser1. $this->assertTrue($s1forums[$forum1->get_id()]->has_unread_discussions()); $this->assertTrue($s1forums[$forum2->get_id()]->has_unread_discussions()); // A number of discussions contain posts NOT read by Suser1. $this->assertEquals(1, $s1forums[$forum1->get_id()]->get_num_unread_discussions()); $this->assertEquals(1, $s1forums[$forum2->get_id()]->get_num_unread_discussions()); // Mark posts read individually. $posttime = $posttime + 2; $did1s1post1->mark_read($posttime, $etuser1->id); // Poster suser1, reader teacher 1. $did2s1post2->mark_read($posttime, $etuser1->id); // Poster suser1, reader teacher 1. $did1etpost1->mark_read($posttime, $suser1->id); // Poster etuser1, reader suser1. $did2etpost2->mark_read($posttime, $suser1->id); // Poster etuser1, reader suser1. $did1s2post1->mark_read($posttime, $suser1->id); $did2s2post1->mark_read($posttime, $suser1->id); $did1s2post1->mark_read($posttime, $etuser1->id); $did2s2post1->mark_read($posttime, $etuser1->id); // Check read status of newly marked read posts. $etforums = mod_forumng::get_course_forums($course, $etuser1->id, mod_forumng::UNREAD_DISCUSSIONS); // Discussions have NO posts not read by ET. $this->assertFalse($etforums[$forum1->get_id()]->has_unread_discussions()); $this->assertFalse($etforums[$forum2->get_id()]->has_unread_discussions()); // No discussions contain posts not read by ET. $this->assertEquals(0, $etforums[$forum1->get_id()]->get_num_unread_discussions()); $this->assertEquals(0, $etforums[$forum2->get_id()]->get_num_unread_discussions()); $s1forums = mod_forumng::get_course_forums($course, $suser1->id, mod_forumng::UNREAD_DISCUSSIONS); // Discussions have NO posts not read by Suser1. $this->assertFalse($s1forums[$forum1->get_id()]->has_unread_discussions()); $this->assertFalse($s1forums[$forum2->get_id()]->has_unread_discussions()); // No discussions contain posts not read by Suser1. $this->assertEquals(0, $s1forums[$forum1->get_id()]->get_num_unread_discussions()); $this->assertEquals(0, $s1forums[$forum2->get_id()]->get_num_unread_discussions()); // Get read counts for ET user, includes their own posts, // also checks both query_forums() and query_discussions(). $discussion1etuser = mod_forumng_discussion::get_from_id($did1[0], 0, $etuser1->id); $etuserposts = $discussion1etuser->get_num_posts(); $this->assertEquals(1, count($etuserposts)); $unreadpostsetuser = $discussion1etuser->get_num_unread_posts(); $this->assertEquals(0, $unreadpostsetuser); $readpostsetuser = $DB->get_records('forumng_read_posts', array('userid' => $etuser1->id)); $this->assertCount(4, $readpostsetuser); $discussion2etuser = mod_forumng_discussion::get_from_id($did2[0], 0, $etuser1->id); $etuserposts = $discussion2etuser->get_num_posts(); $this->assertEquals(1, count($etuserposts)); $unreadpostsetuser = $discussion2etuser->get_num_unread_posts(); $this->assertEquals(0, $unreadpostsetuser); $readpostsetuser = $DB->get_records('forumng_read_posts', array('userid' => $etuser1->id)); $this->assertCount(4, $readpostsetuser); // Get read counts for the student user 1, includes count of their own posts. $discussion1suser1 = mod_forumng_discussion::get_from_id($did1[0], 0, $suser1->id); $suser1posts = $discussion1suser1->get_num_posts(); $this->assertEquals(1, count($suser1posts)); $unreadpostsuser1 = $discussion1suser1->get_num_unread_posts(); $this->assertEquals(0, $unreadpostsuser1); $readpostsuser1 = $DB->get_records('forumng_read_posts', array('userid' => $suser1->id)); $this->assertCount(4, $readpostsuser1); $discussion2suser1 = mod_forumng_discussion::get_from_id($did2[0], 0, $suser1->id); $suser1posts = $discussion2suser1->get_num_posts(); $this->assertEquals(1, count($suser1posts)); $unreadpostsuser1 = $discussion2suser1->get_num_unread_posts(); $this->assertEquals(0, $unreadpostsuser1); $readpostsuser1 = $DB->get_records('forumng_read_posts', array('userid' => $suser1->id)); $this->assertCount(4, $readpostsuser1); // Ensure user prefs allow discussions/posts to be marked as read 'automatically'. unset_user_preference('forumng_manualmark', $etuser1); unset_user_preference('forumng_manualmark', $suser1); // Mark read at forumn/discussion level 'automatically'. $posttime = $posttime + 2; // Mark forumn/discussion 1 read 'automatically'. $did1read = mod_forumng_discussion::get_from_id($did1[0], 0); $did1read->mark_read($posttime, $etuser1->id); $did1read->mark_read($posttime, $suser1->id); // Mark forumn/discussion 2 read 'automatically'. $did2read = mod_forumng_discussion::get_from_id($did2[0], 0); $did2read->mark_read($posttime, $suser1->id); $did2read->mark_read($posttime, $etuser1->id); // Re-check Forumn read status of forum/discussions/posts. $etforums = mod_forumng::get_course_forums($course, $etuser1->id, mod_forumng::UNREAD_DISCUSSIONS); // Forum discussions have NO posts not read by ET. $this->assertFalse($etforums[$forum1->get_id()]->has_unread_discussions('use')); $this->assertFalse($etforums[$forum2->get_id()]->has_unread_discussions()); // No forum discussion contains posts not read by ET. $this->assertEquals(0, $etforums[$forum1->get_id()]->get_num_unread_discussions()); $this->assertEquals(0, $etforums[$forum2->get_id()]->get_num_unread_discussions()); $s1forums = mod_forumng::get_course_forums($course, $suser1->id, mod_forumng::UNREAD_DISCUSSIONS); // Forum discussions have NO posts not read by S1. $this->assertFalse($s1forums[$forum1->get_id()]->has_unread_discussions()); $this->assertFalse($s1forums[$forum2->get_id()]->has_unread_discussions()); // No forum discussion contains posts not read by S1. $this->assertEquals(0, $s1forums[$forum1->get_id()]->get_num_unread_discussions()); $this->assertEquals(0, $s1forums[$forum2->get_id()]->get_num_unread_discussions()); // Add some more posts to discussion 2 only, to remain NOT MARKED manually. $posttime = $posttime + 2; $did2s1p3 = $generator->create_post(array('discussionid' => $did2[0], 'parentpostid' => $did2[1], 'userid' => $suser1->id, 'modified' => $posttime)); $did2s1post3 = mod_forumng_post::get_from_id($did2s1p3->id, 0); $did2etp3 = $generator->create_post(array('discussionid' => $did2[0], 'parentpostid' => $did2[1], 'userid' => $suser2->id, 'modified' => $posttime)); $did2etpost3 = mod_forumng_post::get_from_id($did2etp3->id, 0); // Setuser pref so discussions/posts can be marked 'manually'. set_user_preference('forumng_manualmark', 1, $etuser1); set_user_preference('forumng_manualmark', 1, $suser1); // Check read status of forum/discussions/posts. $etforums = mod_forumng::get_course_forums($course, $etuser1->id, mod_forumng::UNREAD_DISCUSSIONS); // Forumn discussion 1 has NO post not read by ET. $this->assertFalse($etforums[$forum1->get_id()]->has_unread_discussions()); $this->assertEquals(0, $etforums[$forum1->get_id()]->get_num_unread_discussions()); // Forumn discussion 2 has post NOT read by ET. $this->assertTrue($etforums[$forum2->get_id()]->has_unread_discussions()); $this->assertEquals(1, $etforums[$forum2->get_id()]->get_num_unread_discussions()); $s1forums = mod_forumng::get_course_forums($course, $suser1->id, mod_forumng::UNREAD_DISCUSSIONS); // Forumn discussions 1 has NO post unread by S1. $this->assertFalse($s1forums[$forum1->get_id()]->has_unread_discussions()); $this->assertEquals(0, $s1forums[$forum1->get_id()]->get_num_unread_discussions()); // Forumn discussion 2 DOES contain posts not read by S1. $this->assertTrue($s1forums[$forum2->get_id()]->has_unread_discussions()); $this->assertEquals(1, $s1forums[$forum2->get_id()]->get_num_unread_discussions()); // Mark only the older posts read individually. $posttime = $posttime + 2; $did1s1post1->mark_read($posttime, $etuser1->id); // Poster suser1, reader teacher 1. $did2s1post2->mark_read($posttime, $etuser1->id); // Poster suser1, reader teacher 1. $did1etpost1->mark_read($posttime, $suser1->id); // Poster etuser1, reader suser1. $did2etpost2->mark_read($posttime, $suser1->id); // Poster etuser1, reader suser1. // Get read counts for ET user, includes their own posts, // also checks both query_forums() and query_discussions(). $discussion1etuser = mod_forumng_discussion::get_from_id($did1[0], 0, $etuser1->id); $etuserposts = $discussion1etuser->get_num_posts(); $this->assertEquals(4, $etuserposts); $unreadpostsetuser = $discussion1etuser->get_num_unread_posts(); $this->assertEquals(0, $unreadpostsetuser); $readpostsetuser = $DB->get_records('forumng_read_posts', array('userid' => $etuser1->id)); $this->assertCount(2, $readpostsetuser); $discussion2etuser = mod_forumng_discussion::get_from_id($did2[0], 0, $etuser1->id); $etuserposts = $discussion2etuser->get_num_posts(); $this->assertEquals(6, $etuserposts); $unreadpostsetuser = $discussion2etuser->get_num_unread_posts(); $this->assertEquals(2, $unreadpostsetuser); // Get read counts for the student user 1, includes count of their own posts. $discussion1suser1 = mod_forumng_discussion::get_from_id($did1[0], 0, $suser1->id); $suser1posts = $discussion1suser1->get_num_posts(); $this->assertEquals(1, count($suser1posts)); $unreadpostsuser1 = $discussion1suser1->get_num_unread_posts(); $this->assertEquals(0, $unreadpostsuser1); $readpostsuser1 = $DB->get_records('forumng_read_posts', array('userid' => $suser1->id)); $this->assertCount(2, $readpostsuser1); $discussion2suser1 = mod_forumng_discussion::get_from_id($did2[0], 0, $suser1->id); $suser1posts = $discussion2suser1->get_num_posts(); $this->assertEquals(1, count($suser1posts)); $unreadpostsuser1 = $discussion2suser1->get_num_unread_posts(); $this->assertEquals(1, $unreadpostsuser1); $readpostsuser1 = $DB->get_records('forumng_read_posts', array('userid' => $suser1->id)); $this->assertCount(2, $readpostsuser1); // Check read status of forum/discussions/posts. $etforums = mod_forumng::get_course_forums($course, $etuser1->id, mod_forumng::UNREAD_DISCUSSIONS); // Forumn discussion 1 has NO posts not read by ET. $this->assertFalse($etforums[$forum1->get_id()]->has_unread_discussions()); $this->assertEquals(0, $etforums[$forum1->get_id()]->get_num_unread_discussions()); // Forumn discussion 2 contains posts NOT read by ET. $this->assertTrue($etforums[$forum2->get_id()]->has_unread_discussions()); $this->assertEquals(1, $etforums[$forum2->get_id()]->get_num_unread_discussions()); $s1forums = mod_forumng::get_course_forums($course, $suser1->id, mod_forumng::UNREAD_DISCUSSIONS); // Forumn discussion 1 has NO posts not read by S1. $this->assertFalse($etforums[$forum1->get_id()]->has_unread_discussions()); $this->assertEquals(0, $etforums[$forum1->get_id()]->get_num_unread_discussions()); // Forumn discussion 2 contains posts NOT read by S1. $this->assertTrue($etforums[$forum2->get_id()]->has_unread_discussions()); $this->assertEquals(1, $etforums[$forum2->get_id()]->get_num_unread_discussions()); // Mark forumns read 'automatically'. $forums = mod_forumng::get_course_forums($course, $etuser1->id); $posttime = $posttime + 2; $forums[$forum1->get_id()]->mark_read(0, $posttime, $etuser1->id); $forums[$forum2->get_id()]->mark_read(0, $posttime, $etuser1->id); $forums = mod_forumng::get_course_forums($course, $suser1->id); $posttime = $posttime + 2; $forums[$forum2->get_id()]->mark_read(0, $posttime, $suser1->id); $forums[$forum1->get_id()]->mark_read(0, $posttime, $suser1->id); // Check Discussion read status of forum/discussions. $etforums = mod_forumng::get_course_forums($course, $etuser1->id, mod_forumng::UNREAD_DISCUSSIONS); // Forum discussions have NO posts not read by ET. $this->assertFalse($etforums[$forum1->get_id()]->has_unread_discussions()); $this->assertFalse($etforums[$forum2->get_id()]->has_unread_discussions()); // Forum discussions contain NO posts unread by ET. $this->assertEquals(0, $etforums[$forum1->get_id()]->get_num_unread_discussions()); $this->assertEquals(0, $etforums[$forum2->get_id()]->get_num_unread_discussions()); $s1forums = mod_forumng::get_course_forums($course, $suser1->id, mod_forumng::UNREAD_DISCUSSIONS); // Forum discussions have NO posts not read by S1. $this->assertFalse($s1forums[$forum1->get_id()]->has_unread_discussions()); $this->assertFalse($s1forums[$forum2->get_id()]->has_unread_discussions()); // No Forum 1 discussion contains posts not read by S1. $this->assertEquals(0, $s1forums[$forum1->get_id()]->get_num_unread_discussions()); $this->assertEquals(0, $s1forums[$forum2->get_id()]->get_num_unread_discussions()); }
/** * Displays the discussion page. * @param mod_forumng_discussion $discussion Discussion */ public function print_discussion_page($discussion) { global $PAGE; $out = mod_forumng_utils::get_renderer(); $previousread = (int) $discussion->get_time_read(); // 'Read date' option (used when viewing all posts so that they keep // their read/unread colouring) $timeread = optional_param('timeread', 0, PARAM_INT); if ($timeread) { $discussion->pretend_time_read($timeread); $previousread = $timeread; } // 'Expand all' option (always chosen for non-JS browsers) $expandall = optional_param('expand', 0, PARAM_INT) || $PAGE->devicetypeinuse == 'legacy'; // 'Expand all' option (always chosen for non-JS browsers) $collapseall = optional_param('collapse', 0, PARAM_INT); if (!$collapseall && !$expandall && $PAGE->devicetypeinuse == 'mobile') { $collapseall = 1; } // Link back to first unread post if there is one print $discussion->display_unread_skip_link(); // Magic expand tracker (for use in JS only, never set server-side). // This tracks expanded posts, and makes the Back button 'work' in // the sense that it will expand these posts again. print '<form method="post" action="."><div>' . '<input type="hidden" id="expanded_posts" name="expanded_posts" ' . 'value="" /></div></form>'; // Get content for all posts in the discussion $options = array(); if ($expandall) { $options[mod_forumng_post::OPTION_CHILDREN_EXPANDED] = true; } if ($collapseall) { $options[mod_forumng_post::OPTION_CHILDREN_COLLAPSED] = true; } $content = $out->render_discussion($discussion, $options); // Some post display options use the read time to construct links // (usually for non-JS version) so that unread state is maintained. $options[mod_forumng_post::OPTION_READ_TIME] = $previousread; // Display expand all option if there are any 'Expand' links in content $fakedate = '&timeread=' . $previousread; print '<div id="forumng-expandall">'; $showexpandall = preg_match('~<a [^>]*href="discuss\\.php\\?d=[0-9]+[^"]*&expand=1#p[0-9]+">~', $content); // Note: On bad browsers we always expand all posts $showcollapseall = preg_match('~<div class="forumng-post forumng-full.*<div class="forumng-post forumng-full~s', $content) && $PAGE->devicetypeinuse != 'legacy'; if ($showexpandall) { print '<a class="forumng-expandall-link" href="' . $discussion->get_url(mod_forumng::PARAM_HTML) . '&expand=1' . $fakedate . '">' . get_string('expandall', 'forumng') . '</a>'; if ($showcollapseall) { print '<span class="forumng-dot-separator"> • </span>'; } } if ($showcollapseall) { print '<a class="forumng-collapseall-link" href="' . $discussion->get_url(mod_forumng::PARAM_HTML) . '&collapse=1' . $fakedate . '">' . get_string('collapseall', 'forumng') . '</a> '; } print '</div>'; // Display content print $content; // Link back to forum print $discussion->display_link_back_to_forum(); // Display discussion features (row of buttons) print $discussion->display_forumngfeature_discussions(); // Display the subscription options to this disucssion if available print $discussion->display_subscribe_options(); // Atom/RSS links print $discussion->display_feed_links(); // Set read data [shouldn't this logic be somewhere else as it is not // part of display?] if (mod_forumng::mark_read_automatically()) { $discussion->mark_read(); } }
/** * Create a discussion using the generator, returns discussion object * @param mod_forumng $forum * @param array $options Must contain userid * @return mod_forumng_discussion */ public function get_new_discussion(mod_forumng $forum, array $options) { $options['forum'] = $forum->get_id(); $options['course'] = $forum->get_course_id(); $generator = $this->getDataGenerator()->get_plugin_generator('mod_forumng'); $dis = $generator->create_discussion($options); return mod_forumng_discussion::get_from_id($dis[0], mod_forumng::CLONE_DIRECT); }
/** * Calls search_update on each child of the current post, and recurses. * Used when the subject's discussion is changed. */ public function search_update_children() { if (!mod_forumng::search_installed()) { return; } // If the in-memory post object isn't already part of a full // discussion... if (!is_array($this->children)) { // ...then get one $discussion = mod_forumng_discussion::get_from_id($this->discussion->get_id(), $this->get_forum()->get_course_module_id()); $post = $discussion->get_root_post()->find_child($this->get_id()); // Do this update on the new discussion $post->search_update_children(); return; } // Loop through all children foreach ($this->children as $child) { // Update its search fields $child->search_update(); // Recurse $child->search_update_children(); } }
function get_forum_discussions_groups($selectedids, $forum, $cloneid) { $groups = array(); foreach ($selectedids as $d) { // We have the discussions and forum cmid, check to see whether it has groups. $discussion = mod_forumng_discussion::get_from_id($d, $cloneid); // Work out target group. $group = get_target_group($discussion, $forum, true); $groups[] = $group; } $groups = array_unique($groups); return $groups; }
function make_discussion($forum, $posts, $readusers, &$userids, $ratingpercent) { set_time_limit(200); // Make discussion static $index = 0; $index++; list($discussionid, $postid) = $forum->create_discussion(null, 'Discussion ' . $index, get_post_text(), FORMAT_HTML, array(), false, 0, 0, false, false, $userids[mt_rand(0, count($userids) - 1)], false); $discussion = mod_forumng_discussion::get_from_id($discussionid, mod_forumng::CLONE_DIRECT); // Make posts $count = my_random($posts) - 1; $allposts = array($discussion->get_root_post()); for ($i = 0; $i < $count; $i++) { make_post($discussion, $allposts, $userids, $ratingpercent); } // Mark the discussion read if requested if ($readusers > 0) { $now = time(); for ($i = 0; $i < $readusers; $i++) { $discussion->mark_read($now, $userids[$i]); } } // Progress print '.'; }
/** * Obtains list of posts to include in an Atom/RSS feed. * @param int $groupid Group ID (may be ALL_GROUPS) * @param int $userid User ID * @param mod_forumng_discussion $discussion Discussion object (intended only * for calls via the mod_forumng_discussion method) * @return array Array of mod_forumng_post objects */ public function get_feed_posts($groupid, $userid, $discussion = null) { // Don't let user view any posts in a discussion feed they can't see // (I don't think they should be given a key in this case, but just // to be sure). if ($discussion && !$this->get_type()->can_view_discussion($discussion, $userid)) { return array(); } // Number of items to output $items = $this->get_effective_feed_items(); // Get most recent N posts from db $whereparams = array(); if ($discussion) { $where = 'fd.id = ?'; $whereparams[] = $discussion->get_id(); } else { $where = 'fd.forumngid = ?'; $whereparams[] = $this->get_id(); if ($this->get_group_mode() && $groupid != self::ALL_GROUPS) { $where .= ' AND fd.groupid = ?'; $whereparams[] = $groupid; } } // Don't include deleted or old-version posts $where .= ' AND fp.oldversion = 0 AND fp.deleted = 0 AND fd.deleted = 0'; // Or ones out of time $now = time(); $where .= " AND (fd.timestart < ?)" . " AND (fd.timeend = 0 OR fd.timeend > ?)"; $whereparams[] = $now; $whereparams[] = $now; $postrecs = mod_forumng_post::query_posts($where, $whereparams, 'GREATEST(fp.created, fd.timestart) DESC', false, false, false, $userid, true, false, 0, $items); if (count($postrecs) == 0) { // No posts! return array(); } $result = array(); if ($discussion) { foreach ($postrecs as $rec) { $post = new mod_forumng_post($discussion, $rec, null); $result[$rec->id] = $post; } } else { // Based on these posts, get all mentioned discussions $discussionids = array(); $discussionposts = array(); foreach ($postrecs as $rec) { $discussionids[] = $rec->discussionid; $discussionposts[$rec->discussionid][] = $rec->id; } list($discussionpart, $discussionpartparams) = mod_forumng_utils::get_in_array_sql('fd.id', $discussionids); $rs = mod_forumng_discussion::query_discussions($discussionpart, $discussionpartparams, -1, 'id'); // Build the discussion and post objects $posts = array(); foreach ($rs as $rec) { $discussion = new mod_forumng_discussion($this, $rec, true, -1); if ($discussion->can_view($userid)) { foreach ($discussionposts[$discussion->get_id()] as $postid) { $post = new mod_forumng_post($discussion, $postrecs[$postid], null); $posts[$postid] = $post; } } } $rs->close(); // Put them back in order of the post records, and return foreach ($postrecs as $rec) { // Records might be excluded if user can't view discussion if (array_key_exists($rec->id, $posts)) { $result[$rec->id] = $posts[$rec->id]; } } } return $result; }
/** * Returns an array of recipients for OU alerts * @param char $type * @param int $id * @returns array */ function forumng_oualerts_additional_recipients($type, $id) { global $CFG; require_once $CFG->dirroot . '/mod/forumng/mod_forumng.php'; require_once $CFG->dirroot . '/mod/forumng/mod_forumng_discussion.php'; $recipents = array(); if ($type == 'post') { $discussion = mod_forumng_discussion::get_from_post_id($id, mod_forumng::CLONE_DIRECT); $forum = $discussion->get_forum(); $recipients = $forum->get_reportingemails(); } return $recipients; }
/** * Tests discussion locking */ public function test_lock() { global $USER, $DB; $this->resetAfterTest(); $this->setAdminUser(); $course1 = $this->get_new_course(); $orig = $this->get_new_forumng($course1->id, array('removeto' => -1, 'removeafter' => 1)); $dis = $this->get_new_discussion($orig, array('userid' => $USER->id)); $dis2 = $this->get_new_discussion($orig, array('userid' => $USER->id)); $dis3 = $this->get_new_discussion($orig, array('userid' => $USER->id)); // Alter post modified times to in past. foreach ($DB->get_records('forumng_posts') as $post) { $new = new stdClass(); $new->id = $post->id; $new->modified = 1420070400; $DB->update_record('forumng_posts', $new); } // Delete dis2 so not auto-locked. $dis2->delete(false); $this->assertFalse($dis->is_locked()); $this->assertFalse($dis->is_auto_locked()); $lockpostid = $dis->lock('sub', 'mess', FORMAT_HTML); $this->assertTrue($dis->is_locked()); $this->assertFalse($dis->is_auto_locked()); $dis = mod_forumng_discussion::get_from_id($dis->get_id(), mod_forumng::CLONE_DIRECT); $this->assertTrue($dis->is_locked()); $this->assertFalse($dis->is_auto_locked()); $dis->unlock(); $this->assertFalse($dis->is_locked()); $this->assertFalse($dis->is_auto_locked()); $lockpost = mod_forumng_post::get_from_id($lockpostid, mod_forumng::CLONE_DIRECT); $this->assertNotEmpty($lockpost->get_deleted()); // Check auto-locking ($dis3 should be auto-locked only). $dis->lock('', '', FORMAT_HTML); mod_forumng_cron::archive_old_discussions(); $dis = mod_forumng_discussion::get_from_id($dis->get_id(), mod_forumng::CLONE_DIRECT); $dis2 = mod_forumng_discussion::get_from_id($dis2->get_id(), mod_forumng::CLONE_DIRECT); $dis3 = mod_forumng_discussion::get_from_id($dis3->get_id(), mod_forumng::CLONE_DIRECT); $this->assertTrue($dis->is_locked()); $this->assertFalse($dis->is_auto_locked()); $this->assertFalse($dis2->is_locked()); $this->assertFalse($dis2->is_auto_locked()); $this->assertTrue($dis3->is_locked()); $this->assertTrue($dis3->is_auto_locked()); }
* Script used to paste discussion into new forum. * @package forumngfeature * @subpackage copy * @copyright 2011 The Open University * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ // Scripts for paste the discussion or cancel the paste. require_once '../../../../config.php'; require_once $CFG->dirroot . '/mod/forumng/mod_forumng.php'; $cmid = required_param('cmid', PARAM_INT); $groupid = optional_param('group', mod_forumng::NO_GROUPS, PARAM_INT); $cloneid = optional_param('clone', 0, PARAM_INT); $targetforum = mod_forumng::get_from_cmid($cmid, $cloneid); if (optional_param('cancel', '', PARAM_RAW)) { unset($SESSION->forumng_copyfrom); redirect($targetforum->get_url(mod_forumng::PARAM_PLAIN)); } // If the paste action has already been done or cancelled in a different window/tab. if (!isset($SESSION->forumng_copyfrom)) { redirect($targetforum->get_url(mod_forumng::PARAM_PLAIN)); } $olddiscussionid = $SESSION->forumng_copyfrom; $oldcloneid = $SESSION->forumng_copyfromclone; $olddiscussion = mod_forumng_discussion::get_from_id($olddiscussionid, $oldcloneid); // Check permission to copy the discussion require_capability('mod/forumng:copydiscussion', $olddiscussion->get_forum()->get_context()); // Security check to see if can start a new discussion in the target forum. $targetforum->require_start_discussion($groupid); $olddiscussion->copy($targetforum, $groupid); unset($SESSION->forumng_copyfrom); redirect($targetforum->get_url(mod_forumng::PARAM_PLAIN));
/** * Merges the contents of this discussion into another discussion. * @param mod_forumng_discussion $targetdiscussion Target discussion * @param int $userid User ID (0 = current) * @param bool $log True to log this action */ public function merge_into($targetdiscussion, $userid = 0, $log = true) { global $DB; $transaction = $DB->start_delegated_transaction(); // Delete search data for the source discussion $this->ismakingsearchchange = true; $root = $this->get_root_post(); $root->search_update(); $root->search_update_children(); $this->ismakingsearchchange = false; // Update parent post id of root post $record = new stdClass(); $record->id = $this->discussionfields->postid; $record->parentpostid = $targetdiscussion->discussionfields->postid; $DB->update_record('forumng_posts', $record); // Move all posts into new discussion $DB->execute("UPDATE {forumng_posts} SET discussionid = ? WHERE discussionid = ?", array($targetdiscussion->get_id(), $this->get_id())); // Delete this discussion $DB->delete_records('forumng_discussions', array('id' => $this->discussionfields->id)); // Attachments are OK because they are still in the same context, postid // etc (note this would NOT be the case if we allowed merging between // forums). if ($this->get_forum()->get_id() != $targetdiscussion->get_forum()->get_id()) { throw new coding_exception('Cannot merge into different forum'); } // Merging the discussion into another might cause completion changes // (if there was a requirement for discussions and this is no longer // a discussion in its own right). $this->update_completion(false); // Update the search data for the target discussion after the merge $newroot = $targetdiscussion->get_root_post(); $newroot->search_update(); $newroot->search_update_children(); if ($log) { $this->log('merge discussion', 'd' . $this->get_id() . ' into d' . $targetdiscussion->get_id()); } $transaction->allow_commit(); $this->uncache(); $targetdiscussion->uncache(); }
public function test_rating() { global $USER, $DB; $this->resetAfterTest(); $generator = $this->getDataGenerator()->get_plugin_generator('mod_forumng'); $course = $this->get_new_course(); $course2 = $this->get_new_course(); $suser = $this->get_new_user('student', $course->id); $this->setAdminUser(); $forum = $this->get_new_forumng($course->id, array('name' => 'TEST', 'intro' => 'abc123', 'enableratings' => mod_forumng::FORUMNG_STANDARD_RATING, 'ratingscale' => 10)); $forum2 = $this->get_new_forumng($course->id, array('name' => 'TEST2', 'intro' => 'abc123', 'enableratings' => mod_forumng::FORUMNG_NO_RATING)); $forum3 = $this->get_new_forumng($course2->id, array('name' => 'TEST', 'intro' => 'abc123', 'enableratings' => mod_forumng::FORUMNG_STANDARD_RATING, 'ratingscale' => 10)); $did1 = $generator->create_discussion(array('course' => $course, 'forum' => $forum->get_id(), 'userid' => $suser->id)); $did2 = $generator->create_discussion(array('course' => $course, 'forum' => $forum->get_id(), 'userid' => $suser->id)); $did3 = $generator->create_discussion(array('course' => $course, 'forum' => $forum->get_id(), 'userid' => $suser->id)); $did4 = $generator->create_discussion(array('course' => $course, 'forum' => $forum->get_id(), 'userid' => $suser->id)); // Add rating to all 3 discussions. $rm = new rating_manager(); $params = new stdClass(); $params->context = $forum->get_context(); $params->component = 'mod_forumng'; $params->ratingarea = 'post'; $params->scaleid = $forum->get_rating_scale(); $params->userid = $USER->id; $params->itemid = $did1[1]; $rating = new rating($params); $rating->update_rating(5); $params->itemid = $did2[1]; $rating = new rating($params); $rating->update_rating(5); $params->itemid = $did3[1]; $rating = new rating($params); $rating->update_rating(5); // Check rating object gets added where expected. $post = mod_forumng_post::get_from_id($did1[1], mod_forumng::CLONE_DIRECT, false, false); $ratings = $post->get_ratings(); $this->assertNotNull($ratings); $this->assertEquals($did1[1], $ratings->itemid); $post = mod_forumng_post::get_from_id($did1[1], mod_forumng::CLONE_DIRECT, true, false); $ratings = $post->get_ratings(); $this->assertNotNull($ratings); $this->assertEquals($did1[1], $ratings->itemid); $post = mod_forumng_post::get_from_id($did1[1], mod_forumng::CLONE_DIRECT, true, true); $ratings = $post->get_ratings(); $this->assertNotNull($ratings); $this->assertEquals($did1[1], $ratings->itemid); $ratedposts = $forum->get_all_posts_by_user($suser->id, null, 'fp.id', null, null, true); $this->assertCount(3, $ratedposts); $allposts = $forum->get_all_posts_by_user($suser->id, null); $this->assertCount(4, $allposts); $this->assertNotNull($allposts[$did1[1]]->get_ratings()); // Update grades (does nothing). $forum->update_grades(); // Enable rating grading, forumng_update_instance() should update grades. forumng_update_instance((object) array('instance' => $forum->get_id(), 'grading' => mod_forumng::GRADING_SUM)); $grades = grade_get_grades($course->id, 'mod', 'forumng', $forum->get_id(), $suser->id); // Note sum is set to 10 not 15 as max grade is 10. $this->assertEquals(10, abs($grades->items[0]->grades[$suser->id]->grade)); // Enable rating grading, forumng_update_instance() should update grades. forumng_update_instance((object) array('instance' => $forum->get_id(), 'grading' => mod_forumng::GRADING_COUNT)); $grades = grade_get_grades($course->id, 'mod', 'forumng', $forum->get_id(), $suser->id); $this->assertEquals(3, abs($grades->items[0]->grades[$suser->id]->grade)); // Check get_rated_posts_by_user. $extrapost = $generator->create_post(array('discussionid' => $did1[0], 'parentpostid' => $did1[1], 'userid' => $suser->id, 'created' => 1388589745)); $extraposts = $forum->get_rated_posts_by_user($forum, $suser->id, -1, 'fp.id', null, null); $this->assertCount(0, $extraposts); $extraposts = $forum->get_rated_posts_by_user($forum, $USER->id, -1, 'fp.id', null, null); $this->assertCount(3, $extraposts); $params->itemid = $extrapost->id; $rating = new rating($params); $rating->update_rating(10); $extraposts = $forum->get_rated_posts_by_user($forum, $USER->id, -1, 'fp.id', null, null); $this->assertCount(4, $extraposts); // Now filter out the 'old' extrapost. $extraposts = $forum->get_rated_posts_by_user($forum, $USER->id, -1, 'fp.id', null, null, 1388600000); $this->assertCount(3, $extraposts); // Check discussion delete. $discuss = mod_forumng_discussion::get_from_id($did1[0], mod_forumng::CLONE_DIRECT); $discuss->permanently_delete(); $rating = $DB->get_record('rating', array('itemid' => $did1[1])); $this->assertFalse($rating); $grades = grade_get_grades($course->id, 'mod', 'forumng', $forum->get_id(), $suser->id); $this->assertEquals(2, abs($grades->items[0]->grades[$suser->id]->grade)); // Check discussion move. $discuss = mod_forumng_discussion::get_from_id($did2[0], mod_forumng::CLONE_DIRECT); $discuss->move($forum2, 0); $grades = grade_get_grades($course->id, 'mod', 'forumng', $forum->get_id(), $suser->id); $this->assertEquals(1, abs($grades->items[0]->grades[$suser->id]->grade)); forumng_update_instance((object) array('instance' => $forum2->get_id(), 'grading' => mod_forumng::GRADING_COUNT, 'enableratings' => mod_forumng::FORUMNG_STANDARD_RATING, 'ratingscale' => 10)); $grades = grade_get_grades($course->id, 'mod', 'forumng', $forum2->get_id(), $suser->id); $this->assertEquals(1, abs($grades->items[0]->grades[$suser->id]->grade)); $rating = $DB->get_record('rating', array('itemid' => $did2[1])); $this->assertNotEmpty($rating); $this->assertEquals($forum2->get_context(true)->id, $rating->contextid); // Check discussion copy. $discuss = mod_forumng_discussion::get_from_id($did3[0], mod_forumng::CLONE_DIRECT); $discuss->copy($forum3, 0); $grades = grade_get_grades($course->id, 'mod', 'forumng', $forum->get_id(), $suser->id); $this->assertEquals(1, abs($grades->items[0]->grades[$suser->id]->grade)); // Check rating didn't copy as forum in another course. $ratingtotal = $DB->get_records('rating'); $this->assertCount(2, $ratingtotal); // Check rating does copy to foum in same course. $discuss->copy($forum2, 0); $ratingtotal = $DB->get_records('rating'); $this->assertCount(3, $ratingtotal); // Check forum deleting. course_delete_module($forum->get_course_module_id()); $ratingtotal = $DB->get_records('rating'); $this->assertCount(2, $ratingtotal); $grades = grade_get_grades($course->id, 'mod', 'forumng', $forum->get_id(), $suser->id); $this->assertEmpty($grades->items); }
/** * This function handles all aspects of page processing and then calls * methods in $selector at the appropriate moments. * @param post_selector $selector Object that extends this base class */ public static function go($selector) { global $PAGE, $FULLME, $SESSION; $id = required_param('id', PARAM_INT); $cloneid = optional_param('clone', 0, PARAM_INT); $fromselect = optional_param('fromselect', 0, PARAM_INT); $all = optional_param('all', '', PARAM_RAW); $select = optional_param('select', '', PARAM_RAW); $isform = optional_param('postselectform', 0, PARAM_INT); $PAGE->set_url($FULLME); // Get basic objects. $forum = mod_forumng::get_from_cmid($id, $cloneid); $forumngid = $forum->get_id(); $params = array_merge($_REQUEST, $forum->get_link_params_array()); if (optional_param('cancel', '', PARAM_RAW)) { // CALL TYPE 6. redirect('../../view.php?' . $forum->get_link_params(mod_forumng::PARAM_PLAIN)); } $cm = $forum->get_course_module(); $course = $forum->get_course(); $groupid = mod_forumng::get_activity_group($cm, true); // Page name and permissions. $pagename = $selector->get_page_name(); $buttonname = $selector->get_button_name(); $forum->require_view($groupid); $selector->require_capability($forum->get_context(), $forum); if (!($fromselect || $isform || $all)) { // Either an initial request (non-JS) to display the 'dialog' box, // or a request to show the list of posts with checkboxes for selection. // Both types share same navigation. $out = $forum->init_page(new moodle_url('/mod/forumng/view.php', $forum->get_link_params_array())); print $out->header(); if (!$select) { // Show initial dialog. print $out->box_start(); print html_writer::tag('h2', $buttonname); print html_writer::start_tag('form', array('action' => $_SERVER['PHP_SELF'], 'method' => 'get', 'id' => 'discsel')); print html_writer::start_tag('div'); foreach ($params as $param => $paramval) { print html_writer::empty_tag('input', array('name' => $param, 'type' => 'hidden', 'value' => $paramval)); } print html_writer::tag('p', get_string('selectordiscall', 'forumng')); print html_writer::start_tag('div', array('class' => 'forumng-buttons')); print html_writer::empty_tag('input', array('name' => 'all', 'type' => 'submit', 'value' => get_string('selectoralldisc', 'forumng'))); print html_writer::empty_tag('input', array('name' => 'select', 'type' => 'submit', 'value' => get_string('selectorselecteddisc', 'forumng'))); print html_writer::empty_tag('input', array('name' => 'cancel', 'type' => 'submit', 'value' => get_string('cancel'))); print html_writer::end_tag('div'); print html_writer::end_tag('div'); print html_writer::end_tag('form'); print $out->box_end(); } else { // Show list of posts to select. print html_writer::start_tag('div', array('class' => 'forumng-selectintro')); print html_writer::tag('p', get_string('selectdiscintro', 'forumng')); print html_writer::end_tag('div'); print html_writer::start_tag('form', array('action' => $_SERVER['PHP_SELF'], 'method' => 'post', 'id' => 'discsel')); print html_writer::start_tag('div'); print $forum->get_link_params(mod_forumng::PARAM_FORM); print html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'fromselect', 'value' => '1')); foreach ($params as $param => $paramval) { print html_writer::empty_tag('input', array('name' => $param, 'type' => 'hidden', 'value' => $paramval)); } // Now show discussions, allow for override at type level if following is no good. if (method_exists($forum->get_type(), 'print_select_page')) { print $forum->get_type()->print_select_page($forum, $groupid); } else { // Use default processing, get view and hack in selectors. ob_start(); $forum->get_type()->print_view_page($forum, $groupid); $discussionhtml = ob_get_contents(); ob_end_clean(); // Try and hack into the discussion list - must be xhtml... $doc = new DOMDocument('1.0', 'utf-8'); @$doc->loadHTML($discussionhtml); $docnew = new DOMDocument('1.0', 'utf-8'); $xpath = new DOMXPath($doc); $lists = $xpath->query("//table[contains(concat(' ',normalize-space(@class),' '),' forumng-discussionlist ')]"); // Remove all links. foreach ($lists as $list) { $links = $xpath->query("//a|//form", $list); foreach ($links as $node) { if ($node->nodeName == 'a') { // Disable links. $node->removeAttribute('href'); } else { // Remove any forms. $node->parentNode->removeChild($node); } } // Add in discussion select. $rows = $xpath->query("//table[@class='generaltable forumng-discussionlist']\n //tr[not(@class) or @class!='forumng-divider']", $list); for ($a = 0, $len = $rows->length; $a < $len; $a++) { // Add in select options for each row, checking types. $row = $rows->item($a); if ($a == 0) { $newcell = $doc->createElement('th', get_string('selectorselectdisc', 'mod_forumng')); $newcell->setAttribute('class', 'header'); $newcell->setAttribute('scope', 'col'); $row->appendChild($newcell); } else { $id = $row->getAttribute('id'); if (strpos($id, 'discrow') === false) { continue; } // Get discussion id from row id as added by renderer. $id = str_replace('discrow_', '', $id); // Check if we include checkbox or not. $classar = explode(' ', $row->getAttribute('class')); $includematches = array_intersect($selector->only_discussion_types(), $classar); $excludematches = array_intersect($selector->exclude_discussion_types(), $classar); if ((count($selector->only_discussion_types()) == 0 || count($includematches) > 0) && count($excludematches) == 0) { // OK to include, add checkbox and label. $select = $doc->createElement('input'); $select->setAttribute('type', 'checkbox'); $select->setAttribute('name', "selectd{$id}"); $select->setAttribute('id', "selectd{$id}"); $label = $doc->createElement('label', get_string('selectorselectdisc', 'mod_forumng')); $label->setAttribute('for', "selectd{$id}"); $label->setAttribute('class', 'accesshide'); $newcell = $doc->createElement('td'); $newcell->setAttribute('class', 'dselect'); $newcell->appendChild($select); $newcell->appendChild($label); $row->appendChild($newcell); } else { $newcell = $doc->createElement('td', ' '); $row->appendChild($newcell); } } } // Keep only discussion list by moving to new xml doc. $newnode = $docnew->importNode($list, true); $docnew->appendChild($newnode); } print $docnew->saveHTML(); } print html_writer::start_tag('div', array('class' => 'forumng-selectoutro')); print html_writer::empty_tag('input', array('type' => 'submit', 'value' => get_string('confirmselection', 'forumng'))); print html_writer::empty_tag('input', array('type' => 'submit', 'name' => 'cancel', 'value' => get_string('cancel'))); print html_writer::end_tag('div'); print html_writer::end_tag('div'); print html_writer::end_tag('form'); } // Display footer. print $out->footer(); } else { // Call types 3, 4, and 5 use the form (and may include list of postids). $postids = array(); $selectedids = array(); foreach ($_POST as $field => $value) { $matches = array(); if (!is_array($value) && (string) $value !== '0' && preg_match('~^selectd([0-9]+)$~', $field, $matches)) { $selectedids[] = $matches[1]; } } if (!empty($selectedids)) { // Check access. foreach ($selectedids as $id) { $discuss = mod_forumng_discussion::get_from_id($id, $cloneid); if ($forum->get_type()->can_view_discussion($discuss)) { $postids[] = $id; } } } else { if (!$all) { // No slections made. redirect('../../view.php?' . $forum->get_link_params(mod_forumng::PARAM_PLAIN)); } // Work out discussion list for this page (e.g. selected All). $sortorder = optional_param('sort', 'd', PARAM_ALPHA); if (isset($SESSION->forumng_discussionlist[$forumngid]->sort)) { $sortorder = $SESSION->forumng_discussionlist[$forumngid]->sort; } $page = optional_param('page', 1, PARAM_INT); if (isset($SESSION->forumng_discussionlist[$forumngid]->page)) { $page = $SESSION->forumng_discussionlist[$forumngid]->page; } $sortchar = substr($sortorder, 0, 1); if (strlen($sortorder) == 2) { $sortreverse = substr($sortorder, 1, 1) == 'r' ? true : false; } else { $sortreverse = false; } $sort = mod_forumng::get_sort_code($sortchar); $list = $forum->get_discussion_list($groupid, $forum->can_view_hidden(), $page, $sort, $sortreverse); $discussionsarr = array_merge($list->get_sticky_discussions(), $list->get_normal_discussions()); // Double check ID is valid and user can view. for ($a = 0; $a < count($discussionsarr); $a++) { if ($forum->get_type()->can_view_discussion($discussionsarr[$a])) { $postids[] = $discussionsarr[$a]->get_id(); } } } $out = $forum->init_page(new moodle_url('/mod/forumng/view.php', $forum->get_link_params_array()), $pagename); // Get form to use. $mform = $selector->get_form($forum, $all, $postids); if (!$mform) { // Some options do not need a confirmation form; in that case, // just apply the action immediately. $selector->apply($forum, $all, $postids, null); exit; } // Check cancel. if ($mform->is_cancelled()) { redirect('../../view.php?' . $forum->get_link_params(mod_forumng::PARAM_PLAIN)); } if ($fromform = $mform->get_data()) { // User submitted form to confirm process, which should now be // applied by selector. $selector->apply($forum, $all, $postids, $fromform); exit; } else { print $out->header(); // User requested form either via JavaScript or the other way, and // either with all messages or the whole discussion. // Print form. print $mform->display(); // Print optional content that goes after form. print $selector->get_content_after_form($forum, $all, $postids, $fromform); // Display footer. print $out->footer(); } } }
// Set up page $pagename = get_string('merge', 'forumngfeature_merge'); $url = new moodle_url('/mod/forumng/feature/merge/merge.php', $pageparams); $out = $discussion->init_page($url, $pagename); // Require that you can see this discussion (etc) and merge them $discussion->require_view(); if (!$discussion->can_split($whynot)) { print_error($whynot, 'forumng'); } if ($stage == 2) { if (!confirm_sesskey()) { print_error('invalidsesskey'); } if (!isset($_POST['cancel'])) { // Get source discussion and check permissions $sourcediscussion = mod_forumng_discussion::get_from_id($SESSION->forumng_mergefrom->discussionid, $SESSION->forumng_mergefrom->cloneid); $sourcediscussion->require_view(); if (!$sourcediscussion->can_split($whynot)) { print_error($whynot, 'forumng'); } if ($sourcediscussion->get_forum()->get_id() != $discussion->get_forum()->get_id()) { print_error('error_wrongforum', 'forumngfeature_merge'); } // Do actual merge $sourcediscussion->merge_into($discussion); } unset($SESSION->forumng_mergefrom); redirect('../../discuss.php?' . $discussion->get_link_params(mod_forumng::PARAM_PLAIN)); } // Create form require_once 'merge_form.php';
public function test_tag_discussion() { global $DB, $USER, $SITE, $CFG; require_once $CFG->dirroot . '/tag/lib.php'; $this->resetAfterTest(true); $this->setAdminUser(); // Create the generator object and do standard checks. $generator = self::getDataGenerator()->get_plugin_generator('mod_forumng'); // Create course. $record = new stdClass(); $record->shortname = 'testcourse'; $course = self::getDataGenerator()->create_course($record); // Create groups. $group1 = $this->get_new_group($course->id); $group2 = $this->get_new_group($course->id); // Create forum. $forumrecord = $generator->create_instance(array('course' => $course->id, 'tags' => true, 'groupmode' => VISIBLEGROUPS)); $forum = mod_forumng::get_from_id($forumrecord->id, mod_forumng::CLONE_DIRECT, true); // Set use tag. $CFG->usetags = true; // Set forum to tag enabling. $this->assertTrue($CFG->usetags); $this->assertEquals(true, $forum->get_tags_enabled()); // Start a discussion in forum (group1). $record = new stdClass(); $record->course = $course->id; $record->forum = $forum->get_id(); $record->groupid = $group1->id; $record->userid = $USER->id; $record->timestart = time(); $ids1 = $generator->create_discussion($record); // Start a second discussion in forum (group1). $record = new stdClass(); $record->course = $course->id; $record->forum = $forum->get_id(); $record->groupid = $group1->id; $record->userid = $USER->id; $record->timestart = time(); $ids2 = $generator->create_discussion($record); // Start a third discussion in forum (group2). $record = new stdClass(); $record->course = $course->id; $record->forum = $forum->get_id(); $record->groupid = $group2->id; $record->userid = $USER->id; $record->timestart = time(); $ids3 = $generator->create_discussion($record); // Set up tags in each discussion. $discussionid = $ids1[0]; $discussion = mod_forumng_discussion::get_from_id($discussionid, 0); $this->assertEmpty($discussion->get_tags()); // Edit discussion settings. $discussion->edit_settings($discussion::NOCHANGE, $discussion::NOCHANGE, $discussion::NOCHANGE, $discussion::NOCHANGE, $discussion::NOCHANGE, array('tag1', 'tag2', 'tag3')); $tags1 = $discussion->get_tags(); $this->assertCount(3, $tags1); $discussion1 = $discussion; $discussionid = $ids2[0]; $discussion = mod_forumng_discussion::get_from_id($discussionid, 0); $this->assertEmpty($discussion->get_tags()); // Edit discussion settings. $discussion->edit_settings(mod_forumng_discussion::NOCHANGE, mod_forumng_discussion::NOCHANGE, mod_forumng_discussion::NOCHANGE, mod_forumng_discussion::NOCHANGE, mod_forumng_discussion::NOCHANGE, array('tag1', 'tag2')); $tags2 = $discussion->get_tags(); $this->assertCount(2, $tags2); $discussion2 = $discussion; $discussionid = $ids3[0]; $discussion = mod_forumng_discussion::get_from_id($discussionid, 0); $this->assertEmpty($discussion->get_tags()); // Edit discussion settings. $discussion->edit_settings(mod_forumng_discussion::NOCHANGE, mod_forumng_discussion::NOCHANGE, mod_forumng_discussion::NOCHANGE, mod_forumng_discussion::NOCHANGE, mod_forumng_discussion::NOCHANGE, array('tag1')); $tags3 = $discussion->get_tags(); $this->assertCount(1, $tags3); $discussion3 = $discussion; // Create a discussion with no tags for later use. $record = new stdClass(); $record->course = $course->id; $record->forum = $forum->get_id(); $record->groupid = $group2->id; $record->userid = $USER->id; $record->timestart = time(); $ids4 = $generator->create_discussion($record); // Get id of 'tag1'. $tagid = array_search('tag1', $tags3); // Get all tags and check on numbers for each tag. $tagsused = $forum->get_tags_used(); $this->assertCount(3, $tagsused); $tagsused1 = $forum->get_tags_used($group1->id); $this->assertCount(3, $tagsused1); $tagsused2 = $forum->get_tags_used($group2->id); $this->assertCount(1, $tagsused2); $this->assertArrayHasKey($tagid, $tagsused2); $this->assertObjectHasAttribute('displayname', $tagsused2[$tagid]); $this->assertObjectHasAttribute('count', $tagsused2[$tagid]); $this->assertEquals('tag1', $tagsused2[$tagid]->displayname); $this->assertEquals(1, $tagsused2[$tagid]->count); // Get all discussions featuring 'tag1'. $list = $forum->get_discussion_list(mod_forumng::ALL_GROUPS, $forum->can_view_hidden(), 1, mod_forumng::SORT_DATE, false, 0, true, $tagid); $taggedlist = $list->get_normal_discussions(); $this->assertCount(3, $taggedlist); // Get all discussions featuring 'tag1'.for group1. $list1 = $forum->get_discussion_list($group1->id, $forum->can_view_hidden(), 1, mod_forumng::SORT_DATE, false, 0, true, $tagid); $taggedlist1 = $list1->get_normal_discussions(); $this->assertCount(2, $taggedlist1); // Get all discussions featuring 'tag1'.for group2. $list2 = $forum->get_discussion_list($group2->id, $forum->can_view_hidden(), 1, mod_forumng::SORT_DATE, false, 0, true, $tagid); $taggedlist2 = $list2->get_normal_discussions(); $this->assertCount(1, $taggedlist2); // Get all discussions featuring 'tag3'.for group2 - which should be none. $tagid = array_search('tag3', $tags1); $list = $forum->get_discussion_list($group2->id, $forum->can_view_hidden(), 1, mod_forumng::SORT_DATE, false, 0, true, $tagid); $taggedlist = $list->get_normal_discussions(); $this->assertCount(0, $taggedlist); // Set tags specifically for group 1. $forumng = new stdClass(); $forumng->settags = array('g1 vamp', 'g1 zomb', 'g1 mumm', 'g1 damm'); $forumng->id = $forum->get_id(); $forumng->instance = $forum->get_id(); $forumng->tags = 1; forumng_update_instance($forumng); $context = $forum->get_context(); mod_forumng::set_group_tags($forum->get_id(), $group1->id, $forumng->settags); $tagsused1 = $forum::get_set_tags($forumng->id, $group1->id); $this->assertCount(4, $tagsused1); // Set tags for group 2 (should return main set tags also). $g2tags = array('g2 ghost', 'g2 ghoul', 'g2 googl', 'g2 welf', 'g2 gobb'); mod_forumng::set_group_tags($forum->get_id(), $group2->id, $g2tags); $tagsused2 = $forum::get_set_tags($forumng->id, $group2->id); $this->assertCount(9, $tagsused2); $tagsused3 = $forum::get_set_tags($forumng->id); $this->assertCount(4, $tagsused3); // Test that group only tags can be returned. $tagsused1 = $forum::get_set_tags($forumng->id, $group1->id, true); $this->assertCount(4, $tagsused1); $tagsused2 = $forum::get_set_tags($forumng->id, $group2->id, true); $this->assertCount(5, $tagsused2); // Need to test permanently delete. $discussionid = $ids4[0]; $discussion = mod_forumng_discussion::get_from_id($discussionid, 0); $this->assertEmpty($discussion->get_tags()); // Edit discussion settings. $discussion->edit_settings(mod_forumng_discussion::NOCHANGE, mod_forumng_discussion::NOCHANGE, mod_forumng_discussion::NOCHANGE, mod_forumng_discussion::NOCHANGE, mod_forumng_discussion::NOCHANGE, array('t1', 't2', 't3')); $tags4 = $discussion->get_tags(); $this->assertCount(3, $tags4); $discussion4 = $discussion; // Delete discussion. $discussion4->permanently_delete(false); $this->assertFalse($DB->get_record('forumng_discussions', array('id' => $discussion->get_id()))); $this->assertEmpty($DB->get_records('tag_instance', array('itemid' => $discussion->get_id(), 'itemtype' => 'forumng discussions'))); // Test group tag setting. $user2 = $this->get_new_user(); $this->setUser($user2); mod_forumng::set_group_tags($forumng->id, $group1->id, array('t1', 'tnew')); $tagsused = $forum::get_set_tags($forumng->id, $group1->id, true); $this->assertCount(2, $tagsused); mod_forumng::set_group_tags($forumng->id, $group1->id, array('t1')); $tagsused = $forum::get_set_tags($forumng->id, $group1->id, true); $this->assertCount(1, $tagsused); // Create a new forum and add same group tags. $forumrecord2 = $generator->create_instance(array('course' => $course->id, 'tags' => true, 'groupmode' => VISIBLEGROUPS)); $forum2 = mod_forumng::get_from_id($forumrecord2->id, mod_forumng::CLONE_DIRECT, true); mod_forumng::set_group_tags($forumrecord2->id, $group1->id, array('t1')); $tagsused = $forum::get_set_tags($forumrecord2->id, $group1->id, true); $this->assertCount(1, $tagsused); // Create a new forum and add same group tags (should use another user). $forumrecord2 = $generator->create_instance(array('course' => $course->id, 'tags' => true, 'groupmode' => VISIBLEGROUPS)); $forum2 = mod_forumng::get_from_id($forumrecord2->id, mod_forumng::CLONE_DIRECT, true); mod_forumng::set_group_tags($forumrecord2->id, $group1->id, array('t1')); $tagsused = $forum::get_set_tags($forumrecord2->id, $group1->id, true); $this->assertCount(1, $tagsused); // Create a new forum and add same group tags (should fail as ou of users). $forumrecord2 = $generator->create_instance(array('course' => $course->id, 'tags' => true, 'groupmode' => VISIBLEGROUPS)); $forum2 = mod_forumng::get_from_id($forumrecord2->id, mod_forumng::CLONE_DIRECT, true); $this->setExpectedException('moodle_exception'); mod_forumng::set_group_tags($forumrecord2->id, $group1->id, array('t1')); // Do not add any tests after this point as exception called above. }
array_push($tags, ''); } $customdata = array('options' => array(), 'cmid' => $cm->id, 'group' => $groupid, 'tags' => $tags, 'params' => $urlparams); // Set up page. $pagename = get_string('editdiscussiontags', 'forumngfeature_edittags'); $url = new moodle_url('/mod/forumng/feature/edittags/edittags.php', $pageparams); $out = $discussion->init_page($url, $pagename); $mform = new mod_forumng_edittags_form($url, $customdata); if ($mform->is_cancelled()) { // Form is cancelled, redirect back to the discussion. redirect('../../discuss.php?' . $discussion->get_link_params(mod_forumng::PARAM_PLAIN)); } else { if ($fromform = $mform->get_data()) { if (!isset($fromform->tags)) { $fromform->tags = null; } $discussion = mod_forumng_discussion::get_from_id($d, $cloneid); $discussion->edit_settings(mod_forumng_discussion::NOCHANGE, mod_forumng_discussion::NOCHANGE, mod_forumng_discussion::NOCHANGE, mod_forumng_discussion::NOCHANGE, mod_forumng_discussion::NOCHANGE, $fromform->tags); redirect('../../discuss.php?' . $discussion->get_link_params(mod_forumng::PARAM_PLAIN)); } else { $navigation = array(); print $out->header(); // Require JavaScript (form.js). $forum->print_form_js(); $mform->display(); $PAGE->requires->yui_module('moodle-mod_forumng-tagselector', 'M.mod_forumng.tagselector.init', array('id_tags_othertags', $forum->get_tags_used($groupid, true))); $PAGE->requires->strings_for_js(array('numberofdiscussions'), 'forumng'); // Display footer. print $out->footer(); } }
/** * This function handles all aspects of page processing and then calls * methods in $selector at the appropriate moments. * @param post_selector $selector Object that extends this base class * @param string $rawurl Raw 'name' part of url e.g. '/mod/forumng/feature/frog/frog.php' */ public static function go($selector) { global $PAGE, $FULLME; $d = required_param('d', PARAM_INT); $cloneid = optional_param('clone', 0, PARAM_INT); $PAGE->set_url($FULLME); $fromselect = optional_param('fromselect', 0, PARAM_INT); $all = optional_param('all', '', PARAM_RAW); $select = optional_param('select', '', PARAM_RAW); // Get basic objects $discussion = mod_forumng_discussion::get_from_id($d, $cloneid); if (optional_param('cancel', '', PARAM_RAW)) { // CALL TYPE 6 redirect('../../discuss.php?' . $discussion->get_link_params(mod_forumng::PARAM_PLAIN)); } $forum = $discussion->get_forum(); $cm = $forum->get_course_module(); $course = $forum->get_course(); $isform = optional_param('postselectform', 0, PARAM_INT); // Page name and permissions $pagename = $selector->get_page_name(); $buttonname = $selector->get_button_name(); $discussion->require_view(); $selector->require_capability($forum->get_context(), $discussion); if (!($fromselect || $isform || $all)) { // Either an initial request (non-JS) to display the 'dialog' box, // or a request to show the list of posts with checkboxes for // selection // Both types share same navigation $out = $discussion->init_page($discussion->get_moodle_url(), $pagename); print $out->header(); if (!$select) { // Show initial dialog print $out->box_start(); print html_writer::tag('h2', $buttonname); print html_writer::start_tag('form', array('action' => $_SERVER['PHP_SELF'], 'method' => 'get')); print html_writer::start_tag('div'); print $discussion->get_link_params(mod_forumng::PARAM_FORM); print html_writer::tag('p', get_string('selectorall', 'forumng')); print html_writer::start_tag('div', array('class' => 'forumng-buttons')); print html_writer::empty_tag('input', array('name' => 'all', 'type' => 'submit', 'value' => get_string('discussion', 'forumng'))); print html_writer::empty_tag('input', array('name' => 'select', 'type' => 'submit', 'value' => get_string('selectedposts', 'forumng'))); print html_writer::end_tag('div'); print html_writer::end_tag('div'); print html_writer::end_tag('form'); print $out->box_end(); } else { // Show list of posts to select print html_writer::start_tag('div', array('class' => 'forumng-selectintro')); print html_writer::tag('p', get_string('selectintro', 'forumng')); print html_writer::end_tag('div'); print html_writer::start_tag('form', array('action' => $_SERVER['PHP_SELF'], 'method' => 'post')); print html_writer::start_tag('div'); print $discussion->get_link_params(mod_forumng::PARAM_FORM); print html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'fromselect', 'value' => '1')); print $out->render_discussion($discussion, array(mod_forumng_post::OPTION_NO_COMMANDS => true, mod_forumng_post::OPTION_CHILDREN_EXPANDED => true, mod_forumng_post::OPTION_SELECTABLE => true)); print html_writer::start_tag('div', array('class' => 'forumng-selectoutro')); print html_writer::empty_tag('input', array('type' => 'submit', 'value' => get_string('confirmselection', 'forumng'))); print html_writer::empty_tag('input', array('type' => 'submit', 'name' => 'cancel', 'value' => get_string('cancel'))); print html_writer::end_tag('div'); print html_writer::end_tag('div'); print html_writer::end_tag('form'); } // Display footer print $out->footer(); } else { // Call types 3, 4, and 5 use the form (and may include list of postids) if ($all) { $postids = false; } else { $postids = array(); foreach ($_POST as $field => $value) { $matches = array(); if (!is_array($value) && (string) $value !== '0' && preg_match('~^selectp([0-9]+)$~', $field, $matches)) { $postids[] = $matches[1]; } } } $out = $discussion->init_page($discussion->get_moodle_url(), $pagename); // Get form to use $mform = $selector->get_form($discussion, $all, $postids); if (!$mform) { // Some options do not need a confirmation form; in that case, // just apply the action immediately. $selector->apply($discussion, $all, $postids, null); exit; } // Check cancel if ($mform->is_cancelled()) { redirect('../../discuss.php?' . $discussion->get_link_params(mod_forumng::PARAM_PLAIN)); } if ($fromform = $mform->get_data()) { // User submitted form to confirm process, which should now be // applied by selector. $selector->apply($discussion, $all, $postids, $fromform); exit; } else { print $out->header(); // User requested form either via JavaScript or the other way, and // either with all messages or the whole discussion. // Print form print $mform->display(); // Print optional content that goes after form print $selector->get_content_after_form($discussion, $all, $postids, $fromform); // Display footer print $out->footer(); } } }
// View posts that have been flagged. $flagged = $DB->get_recordset_sql("\n SELECT COUNT(ff.id) AS count, fp.id\n FROM {forumng_flags} ff\n INNER JOIN {forumng_posts} fp ON fp.id = ff.postid\n INNER JOIN {forumng_discussions} fd ON fd.id = fp.discussionid\n WHERE fd.forumngid = ?\n AND fd.deleted = 0\n AND fp.deleted = 0\n AND fp.oldversion = 0\n {$groupwhere}\n GROUP BY fp.id\n ORDER BY count desc, fp.id desc", array_merge(array($forum->get_id()), $groupparams), 0, 5); $flaggedlist = array(); foreach ($flagged as $apost) { $post = mod_forumng_post::get_from_id($apost->id, $cloneid, true, true); list($content, $user) = $renderer->render_usage_post_info($forum, $post->get_discussion(), $post); $flaggedlist[] = $renderer->render_usage_list_item($forum, $apost->count, $user, $content); } $usageoutput .= html_writer::start_div('forumng_usage_flagged'); $usageoutput .= $renderer->render_usage_list($flaggedlist, 'mostflagged'); $usageoutput .= html_writer::end_div(); // View discussions that have been flagged. $flagged = $DB->get_recordset_sql("\n SELECT COUNT(ff.id) AS count, fd.id\n FROM {forumng_flags} ff\n INNER JOIN {forumng_discussions} fd ON fd.id = ff.discussionid\n WHERE fd.forumngid = ?\n AND fd.deleted = 0\n {$groupwhere}\n GROUP BY fd.id\n ORDER BY count desc, fd.id desc", array_merge(array($forum->get_id()), $groupparams), 0, 5); $flaggedlist = array(); foreach ($flagged as $adiscuss) { $discuss = mod_forumng_discussion::get_from_id($adiscuss->id, $cloneid, 0, true); list($content, $user) = $renderer->render_usage_discussion_info($forum, $discuss); $flaggedlist[] = $renderer->render_usage_list_item($forum, $adiscuss->count, $user, $content); } $usageoutput .= html_writer::start_div('forumng_usage_flagged'); $usageoutput .= $renderer->render_usage_list($flaggedlist, 'mostflaggeddiscussions'); $usageoutput .= html_writer::end_div(); } // Show ratings. if (has_capability('mod/forumng:viewanyrating', $forum->get_context())) { $gradingstr = ''; $ratingtype = $forum->get_enableratings(); if ($ratingtype && $forum->get_rating_scale() != 0) { // Get grading type from forum. $gradingtype = $forum->get_grading(); $counttype = '';
public function prepare_package() { global $CFG; /* * decoding the array from letters to numbers, see export.php */ if ($this->posts !== '') { $selected = $this->decode_string_to_array(); } else { $selected = false; } // Set up the start of the XHTML file. $allhtml = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" ' . '"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">' . html_writer::start_tag('html', array('xmlns' => 'http://www.w3.org/1999/xhtml')); $allhtml .= html_writer::tag('head', html_writer::empty_tag('meta', array('http-equiv' => 'Content-Type', 'content' => 'text/html; charset=utf-8')) . html_writer::tag('title', get_string('export', 'forumngfeature_export'))); $allhtml .= html_writer::start_tag('body') . "\n"; $poststext = ''; $postshtml = ''; // we need a discussion object $discussion = mod_forumng_discussion::get_from_id($this->discussionid, $this->cloneid); $discussion->build_selected_posts_email($selected, $poststext, $postshtml, array(mod_forumng_post::OPTION_EXPORT => true)); $allhtml .= $postshtml; // Finish the file. $allhtml .= html_writer::end_tag('body') . html_writer::end_tag('html'); // Remove embedded img and attachment paths. $plugin = $this->get('exporter')->get('instance')->get('plugin'); $portfolioformat = $this->get('exporter')->get('format'); foreach ($this->files as $file) { $filename = $file->get_filename(); $urlencfilename = rawurlencode($filename); $portfoliofiledir = $portfolioformat->get_file_directory(); if ($plugin == 'download') { // non-encoded embedded image filenames $pattern = '/src=.*?' . preg_quote($filename) . '\\"/'; $replace = 'src="' . $portfoliofiledir . $filename . '"'; $allhtml = preg_replace($pattern, $replace, $allhtml); // urlencoded embedded image filenames $pattern = '/src=.*?' . preg_quote($urlencfilename) . '\\"/'; $replace = 'src="' . $portfoliofiledir . $urlencfilename . '"'; $allhtml = preg_replace($pattern, $replace, $allhtml); // non-encoded attached filenames $pattern = '/href=.*?' . preg_quote($filename) . '\\"/'; $replace = 'href="' . $portfoliofiledir . $filename . '"'; $allhtml = preg_replace($pattern, $replace, $allhtml); // urlencoded attached filenames $pattern = '/href=.*?' . preg_quote($urlencfilename) . '\\"/'; $replace = 'href="' . $portfoliofiledir . $urlencfilename . '"'; $allhtml = preg_replace($pattern, $replace, $allhtml); } if ($plugin == 'rtf') { $pattern = '/src=.*?' . $filename . '\\"/'; $replace = 'src="' . $portfoliofiledir . $filename . '"'; $allhtml = preg_replace($pattern, $replace, $allhtml); $pattern = '/src=\\"http:\\/\\/.*?' . preg_quote($filename) . '.*?\\"/'; $replace = 'src="' . $portfoliofiledir . $filename . '"'; $allhtml = preg_replace($pattern, $replace, $allhtml); $pattern = '/src=\\"http:\\/\\/.*?' . preg_quote($urlencfilename) . '.*?\\"/'; $replace = 'src="' . $portfoliofiledir . $filename . '"'; $allhtml = preg_replace($pattern, $replace, $allhtml); } } $content = $allhtml; $name = $this->make_filename_safe('forum_discussion') . '.html'; $manifest = $this->exporter->get('format') instanceof PORTFOLIO_FORMAT_RICH; $this->copy_files($this->multifiles); $this->get('exporter')->write_new_file($content, $name, $manifest); }