Example #1
0
function make_post($discussion, &$allposts, &$userids, $ratingpercent)
{
    // Make reply
    static $index = 0;
    $index++;
    $replyto = $allposts[rand(0, count($allposts) - 1)];
    $newpostid = $replyto->reply(my_random_percentage(25) ? 'Reply ' . $index : null, get_post_text(), FORMAT_HTML, array(), false, $userids[mt_rand(0, count($userids) - 1)], false);
    $newpost = mod_forumng_post::get_from_id($newpostid, mod_forumng::CLONE_DIRECT);
    $allposts[] = $newpost;
    // Add ratings
    for ($i = 0; $i < count($userids); $i++) {
        if (my_random_percentage($ratingpercent)) {
            $newpost->rate(2, $userids[$i]);
        }
    }
}
Example #2
0
            // Old forumng ratings (obsolete).
            $postid = ' r.postid AS postid ';
            $from = ' {forumng_ratings} r';
            $postjoin = 'INNER JOIN {forumng_posts} fp ON r.postid = fp.id';
            $having = 'HAVING COUNT(r.rating) >= ?';
            $havingparams[] = $forum->get_rating_threshold();
            $groupby = ' GROUP BY r.postid';
        }
        $conditionsparams = array_merge($conditionsparams, $groupparams, $havingparams);
        $ratingsl = $DB->get_recordset_sql("SELECT {$counttype}, {$postid}\n                FROM {$from}\n                {$postjoin}\n                INNER JOIN  {forumng_discussions} fd ON fp.discussionid = fd.id\n                INNER JOIN  {forumng} f ON f.id = fd.forumngid\n                WHERE {$conditions}\n                AND fd.deleted = 0\n                AND fp.deleted = 0\n                AND fp.oldversion = 0\n                {$groupwhere}\n                {$groupby}\n                {$having}\n                ORDER BY rawgrade DESC\n                ", $conditionsparams, 0, 5);
        // Get the ratings.
        foreach ($ratingsl as $apost) {
            if ($gradingtype == mod_forumng::GRADING_AVERAGE) {
                $apost->rawgrade = round($apost->rawgrade, 2);
            }
            $post = mod_forumng_post::get_from_id($apost->postid, $cloneid, true, true);
            list($content, $user) = $renderer->render_usage_post_info($forum, $post->get_discussion(), $post);
            $ratingslist[] = $renderer->render_usage_list_item($forum, $apost->rawgrade, $user, $content);
        }
        // Print out ratings usage.
        $usageoutput .= $renderer->render_usage_ratings($ratingslist, $forum, $gradingstr, $gradingtype);
    }
}
if (!empty($usageoutput)) {
    echo html_writer::start_div('forumng_usage_section');
    echo $OUTPUT->heading(get_string('usage', 'forumngfeature_usage'), 4, 'forumng_usage_sectitle');
    echo $usageoutput;
    echo html_writer::start_div('clearer') . html_writer::end_div();
    echo html_writer::end_div();
}
echo $OUTPUT->footer();
 * @subpackage deletedposts
 * @copyright 2012 The Open University
 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 */
require_once '../../../../config.php';
require_once $CFG->dirroot . '/mod/forumng/mod_forumng.php';
require_once $CFG->dirroot . '/mod/forumng/feature/deletedposts/locallib.php';
// Redirect to deletepostlist.php.
$postid = required_param('p', PARAM_INT);
$pageparams = array('p' => $postid);
$pageparams['p'] = $postid;
$cloneid = optional_param('clone', 0, PARAM_INT);
if ($cloneid) {
    $pageparams['clone'] = $cloneid;
}
$post = mod_forumng_post::get_from_id($postid, $cloneid);
// Get convenience variables.
$discussion = $post->get_discussion();
$forum = $post->get_forum();
$course = $forum->get_course();
$cm = $forum->get_course_module();
$pageparams['id'] = $cm->id;
$delete = optional_param('delete', 0, PARAM_INT);
$groupid = optional_param('group', 0, PARAM_INT);
$pageparams['group'] = $groupid;
// Set up page.
$pagename = get_string($delete ? 'deletepost' : 'undeletepost', 'forumng', $post->get_effective_subject(true));
$url = new moodle_url('/mod/forumng/feature/deletedposts/deletepost.php', $pageparams);
$out = $discussion->init_page($url, $pagename);
// Do all access security checks.
$post->require_view();
 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);
 }
Example #5
0
/**
 * Return post subject or current discussion title
 * @param char $item
 * @param int $id
 * @returns string
 */
function forumng_oualerts_custom_info($item, $id)
{
    global $CFG;
    require_once $CFG->dirroot . '/mod/forumng/mod_forumng.php';
    require_once $CFG->dirroot . '/mod/forumng/mod_forumng_post.php';
    $title = '';
    if ($item == 'post') {
        $post = mod_forumng_post::get_from_id($id, mod_forumng::CLONE_DIRECT);
    }
    if ($post) {
        $title = $post->get_subject();
        if ($title == null) {
            // We need to get the last previous post that has a subject field.
            $title = $post->get_effective_subject(true);
        }
    }
    return $title;
}
 /**
  * Creates a new discussion in this forum.
  * @param int $groupid Group ID for the discussion or null if it should show
  *   to all groups
  * @param string $subject Subject of message
  * @param string $message Message content
  * @param int $format Format of message content
  * @param bool $attachments True if discussion contains attachments
  * @param bool $mailnow True to mail ASAP, else false
  * @param int $timestart Visibility time of discussion (seconds since epoch) or null
  * @param int $timeend Time at which discussion disappears (seconds since epoch) or null
  * @param bool $locked True if discussion should be locked
  * @param bool $sticky True if discussion should be sticky
  * @param int $userid User ID or 0 for current user
  * @param bool $log True to log this
  * @param int $asmoderator values are ASMODERATOR_NO, ASMODERATOR_IDENTIFY or ASMODERATOR_ANON
  * @param array $tags array of tags to add to a discussion
  * @return array Array with 2 elements ($discussionid, $postid)
  */
 public function create_discussion($groupid, $subject, $message, $format, $attachments = false, $mailnow = false, $timestart = 0, $timeend = 0, $locked = false, $sticky = false, $userid = 0, $log = true, $asmoderator = self::ASMODERATOR_NO, $tags = null)
 {
     global $DB, $CFG;
     require_once $CFG->dirroot . '/tag/lib.php';
     $userid = mod_forumng_utils::get_real_userid($userid);
     // Prepare discussion object
     $discussionobj = new StdClass();
     $discussionobj->forumngid = $this->forumfields->id;
     $discussionobj->groupid = $groupid == self::ALL_GROUPS || $groupid == self::NO_GROUPS ? null : $groupid;
     $discussionobj->postid = null;
     // Temporary until we create that first post
     $discussionobj->lastpostid = null;
     $discussionobj->timestart = $timestart;
     $discussionobj->timeend = $timeend;
     $discussionobj->deleted = 0;
     $discussionobj->locked = $locked ? 1 : 0;
     $discussionobj->sticky = $sticky ? 1 : 0;
     // Create discussion
     $transaction = $DB->start_delegated_transaction();
     $discussionobj->id = $DB->insert_record('forumng_discussions', $discussionobj);
     $newdiscussion = new mod_forumng_discussion($this, $discussionobj, false, -1);
     // Create initial post.
     $postid = $newdiscussion->create_root_post($subject, $message, $format, $attachments, $mailnow, $userid, $asmoderator);
     // Update discussion so that it contains the post id
     $changes = new StdClass();
     $changes->id = $discussionobj->id;
     $changes->postid = $postid;
     $changes->lastpostid = $postid;
     $DB->update_record('forumng_discussions', $changes);
     $newdiscussion->log('add discussion');
     if (self::search_installed()) {
         mod_forumng_post::get_from_id($postid, $this->get_course_module_id())->search_update();
     }
     // If tags add to tag_instance records.
     if ($tags != null) {
         tag_set('forumng_discussions', $discussionobj->id, $tags, 'mod_forumng', $this->context->id);
     }
     $transaction->allow_commit();
     return array($newdiscussion->get_id(), $postid);
 }
Example #7
0
function mod_forumng_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload)
{
    global $CFG, $USER;
    require_once $CFG->dirroot . '/mod/forumng/mod_forumng.php';
    // Check remaining slash arguments
    if (count($args) != 2) {
        send_file_not_found();
    }
    list($itemid, $filename) = $args;
    if ($filearea == 'attachment' || $filearea == 'message') {
        // Get post object and check permissions
        $cloneid = optional_param('clone', 0, PARAM_INT);
        $post = mod_forumng_post::get_from_id($itemid, $cloneid);
        $post->require_view();
        if ($cloneid) {
            // File is actually in other context
            $context = $post->get_forum()->get_context(true);
        }
    } else {
        if ($filearea == 'draft' || $filearea == 'draftmessage') {
            // Get draft object and check it's yours (note: I'm not sure whether it is possible to
            // ever access draft attachments in this manner, as while editing, this access is not
            // used; maybe from the X view, but I don't think it works there, however perhaps in
            // future).
            $draft = mod_forumng_draft::get_from_id($itemid);
            if ($draft->get_user_id() !== $USER->id) {
                send_file_not_found();
            }
        } else {
            send_file_not_found();
        }
    }
    // Get file object and send it
    $fs = get_file_storage();
    $file = $fs->get_file($context->id, 'mod_forumng', $filearea, $itemid, '/', $filename);
    if (!$file || $file->is_directory()) {
        send_file_not_found();
    }
    $lifetime = isset($CFG->filelifetime) ? $CFG->filelifetime : 86400;
    send_stored_file($file, $lifetime, 0);
}
 /**
  * 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());
 }
 /**
  * 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());
 }
 /**
  * Internal function that obtains HTML of a single post.
  * @param mixed $postorid Post object or ID of post
  * @param int $cloneid If $postorid is an id, a clone id may be necessary
  *   to construct the post
  * @param array $options Post options if any
  * @return string HTML of post
  */
 private static function get_post_html($postorid, $cloneid = null, $options = array())
 {
     if (is_object($postorid)) {
         $post = $postorid;
     } else {
         $post = mod_forumng_post::get_from_id($postorid, $cloneid, true);
     }
     return trim($post->display(true, $options));
 }
 /**
  * Tests the grading functions in mod_forumng.
  * Note manual grading is handled in feature/user posts and not tested here...
  */
 public function test_grading()
 {
     global $USER, $DB;
     $this->resetAfterTest(true);
     $this->setAdminUser();
     $adminid = $USER->id;
     $generator = $this->getDataGenerator()->get_plugin_generator('mod_forumng');
     $course = $this->get_new_course();
     $user1 = $this->get_new_user('editingteacher', $course->id);
     $forum1 = $this->get_new_forumng($course->id, array('grading' => mod_forumng::GRADING_MANUAL, 'gradingscale' => 50));
     $forum1->update_grades($USER->id);
     // Should do nothing and throw no excpetion...
     $forum2 = $this->get_new_forumng($course->id, array('grading' => mod_forumng::GRADING_COUNT, 'gradingscale' => 5, 'ratingscale' => 5));
     list($discuss, $postid) = $generator->create_discussion(array('course' => $course->id, 'forum' => $forum2->get_id(), 'userid' => $USER->id));
     $post = mod_forumng_post::get_from_id($postid, 0);
     $post->rate(1);
     // Calls update_grades().
     $post = $generator->create_post(array('discussionid' => $discuss, 'userid' => $USER->id, 'parentpostid' => $postid));
     $post = mod_forumng_post::get_from_id($post->id, 0);
     $post->rate(3);
     // Calls update_grades().
     $grades = grade_get_grades($course->id, 'mod', 'forumng', $forum2->get_id(), $USER->id);
     $this->assertEquals(2, abs($grades->items[0]->grades[$USER->id]->grade));
     // Try another grading type, forumng_update_instance() should update grades.
     forumng_update_instance((object) array('instance' => $forum2->get_id(), 'grading' => mod_forumng::GRADING_MAX));
     $grades = grade_get_grades($course->id, 'mod', 'forumng', $forum2->get_id(), $USER->id);
     $this->assertEquals(3, abs($grades->items[0]->grades[$USER->id]->grade));
     // Try another grading type, forumng_update_instance() should update grades.
     forumng_update_instance((object) array('instance' => $forum2->get_id(), 'grading' => mod_forumng::GRADING_MIN));
     $grades = grade_get_grades($course->id, 'mod', 'forumng', $forum2->get_id(), $USER->id);
     $this->assertEquals(1, abs($grades->items[0]->grades[$USER->id]->grade));
     // Try another grading type, forumng_update_instance() should update grades.
     forumng_update_instance((object) array('instance' => $forum2->get_id(), 'grading' => mod_forumng::GRADING_SUM));
     $grades = grade_get_grades($course->id, 'mod', 'forumng', $forum2->get_id(), $USER->id);
     $this->assertEquals(4, abs($grades->items[0]->grades[$USER->id]->grade));
     // Try another grading type, forumng_update_instance() should update grades.
     forumng_update_instance((object) array('instance' => $forum2->get_id(), 'grading' => mod_forumng::GRADING_AVERAGE));
     $grades = grade_get_grades($course->id, 'mod', 'forumng', $forum2->get_id(), $USER->id);
     $this->assertEquals(2, abs($grades->items[0]->grades[$USER->id]->grade));
     // Try another grading type, forumng_update_instance() should update grades.
     forumng_update_instance((object) array('instance' => $forum2->get_id(), 'grading' => mod_forumng::GRADING_NONE));
     $grades = grade_get_grades($course->id, 'mod', 'forumng', $forum2->get_id(), $USER->id);
     $this->assertEmpty($grades->items[0]->grades[$USER->id]->grade);
 }