return $DB->record_exists_sql($sql, $params);
}
+/**
+ * Returns any courses shared by the two users
+ *
+ * The courses has to be visible and enrolments has to be active,
+ * timestart and timeend restrictions are ignored.
+ *
+ * @param stdClass|int $user1
+ * @param stdClass|int $user2
+ * @return array An array of courses that both users are enrolled in
+ */
+function enrol_get_shared_courses($user1, $user2, $preloadcontexts = false) {
+ global $DB, $CFG;
+
+ $user1 = !empty($user1->id) ? $user1->id : $user1;
+ $user2 = !empty($user2->id) ? $user2->id : $user2;
+
+ if (empty($user1) or empty($user2)) {
+ return false;
+ }
+
+ if (!$plugins = explode(',', $CFG->enrol_plugins_enabled)) {
+ return false;
+ }
+
+ list($plugins, $params) = $DB->get_in_or_equal($plugins, SQL_PARAMS_NAMED, 'ee');
+ $params['enabled'] = ENROL_INSTANCE_ENABLED;
+ $params['active1'] = ENROL_USER_ACTIVE;
+ $params['active2'] = ENROL_USER_ACTIVE;
+ $params['user1'] = $user1;
+ $params['user2'] = $user2;
+
+ $ctxselect = '';
+ $ctxjoin = '';
+ if ($preloadcontexts) {
+ list($ctxselect, $ctxjoin) = context_instance_preload_sql('c.id', CONTEXT_COURSE, 'ctx');
+ }
+
+ $sql = "SELECT c.* $ctxselect
+ FROM {course} c
+ JOIN (
+ SELECT DISTINCT c.id
+ FROM {enrol} e
+ JOIN {user_enrolments} ue1 ON (ue1.enrolid = e.id AND ue1.status = :active1 AND ue1.userid = :user1)
+ JOIN {user_enrolments} ue2 ON (ue2.enrolid = e.id AND ue2.status = :active2 AND ue2.userid = :user2)
+ JOIN {course} c ON (c.id = e.courseid AND c.visible = 1)
+ WHERE e.status = :enabled AND e.enrol $plugins
+ ) ec ON ec.id = c.id
+ $ctxjoin";
+ $courses = $DB->get_records_sql($sql, $params);
+ if ($preloadcontexts) {
+ array_map('context_instance_preload', $courses);
+ }
+
+ return $courses;
+}
+
/**
* This function adds necessary enrol plugins UI into the course edit form.
*
public function get_bulk_operations() {
return array();
}
-}
\ No newline at end of file
+}
$string['cannotunsubscribe'] = 'Could not unsubscribe you from that forum';
$string['cannotupdatepost'] = 'You can not update this post';
$string['cannotviewpostyet'] = 'You cannot read other students questions in this discussion yet because you haven\'t posted';
+$string['cannotviewusersposts'] = 'There are no posts made by this user that you are able to view.';
$string['cleanreadtime'] = 'Mark old posts as read hour';
$string['completiondiscussions'] = 'Student must create discussions:';
$string['completiondiscussionsgroup'] = 'Require discussions';
$string['discussions'] = 'Discussions';
$string['discussionsstartedby'] = 'Discussions started by {$a}';
$string['discussionsstartedbyrecent'] = 'Discussions recently started by {$a}';
+$string['discussionsstartedbyuserincourse'] = 'Discussions started by {$a->fullname} in {$a->coursename}';
$string['discussthistopic'] = 'Discuss this topic';
$string['displayend'] = 'Display end';
$string['displayend_help'] = 'This setting specifies whether a forum post should be hidden after a certain date. Note that administrators can always view forum posts.';
$string['emptymessage'] = 'Something was wrong with your post. Perhaps you left it blank, or the attachment was too big. Your changes have NOT been saved.';
$string['erroremptymessage'] = 'Post message cannot be empty';
$string['erroremptysubject'] = 'Post subject cannot be empty.';
+$string['errorenrolmentrequired'] = 'You must be enrolled in this course to access this content';
$string['errorwhiledelete'] = 'An error occurred while deleting record.';
$string['everyonecanchoose'] = 'Everyone can choose to be subscribed';
$string['everyonecannowchoose'] = 'Everyone can now choose to be subscribed';
$string['newforumposts'] = 'New forum posts';
$string['noattachments'] = 'There are no attachments to this post';
$string['nodiscussions'] = 'There are no discussion topics yet in this forum';
-$string['nodiscussionsstartedby'] = 'No discussions started by this user';
+$string['nodiscussionsstartedby'] = '{$a} has not started any discussions';
+$string['nodiscussionsstartedbyyou'] = 'You haven\'t started any discussions yet';
$string['noguestpost'] = 'Sorry, guests are not allowed to post.';
$string['noguesttracking'] = 'Sorry, guests are not allowed to set tracking options.';
$string['nomorepostscontaining'] = 'No more posts containing \'{$a}\' were found';
$string['nopermissiontoview'] = 'You do not have permissions to view this post';
$string['nopostforum'] = 'Sorry, you are not allowed to post to this forum';
$string['noposts'] = 'No posts';
+$string['nopostsmadebyuser'] = '{$a} has made no posts';
+$string['nopostsmadebyyou'] = 'You haven\'t made any posts';
$string['nopostscontaining'] = 'No posts containing \'{$a}\' were found';
$string['noquestions'] = 'There are no questions yet in this forum';
$string['nosubscribers'] = 'There are no subscribers yet for this forum';
$string['postrating2'] = 'Separate and connected';
$string['postrating3'] = 'Mostly connected knowing';
$string['posts'] = 'Posts';
+$string['postsmadebyuser'] = 'Posts made by {$a}';
+$string['postsmadebyuserincourse'] = 'Posts made by {$a->fullname} in {$a->coursename}';
$string['posttoforum'] = 'Post to forum';
$string['postupdated'] = 'Your post was updated';
$string['potentialsubscribers'] = 'Potential subscribers';
$user = $USER;
}
- if (isset($cm->cache->caps['mod/forum:viewdiscussion'])) {
- if (!$cm->cache->caps['mod/forum:viewdiscussion']) {
- return false;
- }
- } else {
- $modcontext = get_context_instance(CONTEXT_MODULE, $cm->id);
- if (!has_capability('mod/forum:viewdiscussion', $modcontext, $user->id)) {
- return false;
+ if (!has_all_capabilities(array('moodle/user:viewdetails', 'moodle/user:readuserposts'), get_context_instance(CONTEXT_USER, $post->userid))) {
+ if (isset($cm->cache->caps['mod/forum:viewdiscussion'])) {
+ if (!$cm->cache->caps['mod/forum:viewdiscussion']) {
+ return false;
+ }
+ } else {
+ $modcontext = get_context_instance(CONTEXT_MODULE, $cm->id);
+ if (!has_capability('mod/forum:viewdiscussion', $modcontext, $user->id)) {
+ return false;
+ }
}
}
);
return $forum_pagetype;
}
+
+/**
+ * Gets all of the courses where the provided user has posted in a forum.
+ *
+ * @global moodle_database $DB The database connection
+ * @param stdClass $user The user who's posts we are looking for
+ * @param bool $discussionsonly If true only look for discussions started by the user
+ * @param bool $includecontexts If set to trye contexts for the courses will be preloaded
+ * @param type $limitfrom The offset of records to return
+ * @param type $limitnum The number of records to return
+ * @return array An array of courses
+ */
+function forum_get_courses_user_posted_in($user, $discussionsonly = false, $includecontexts = true, $limitfrom = null, $limitnum = null) {
+ global $DB;
+
+ // If we are only after discussions we need only look at the forum_discussions
+ // table and join to the userid there. If we are looking for posts then we need
+ // to join to the forum_posts table.
+ if (!$discussionsonly) {
+ $joinsql = 'JOIN {forum_discussions} fd ON fd.course = c.id
+ JOIN {forum_posts} fp ON fp.discussion = fd.id';
+ $wheresql = 'fp.userid = :userid';
+ $params = array('userid' => $user->id);
+ } else {
+ $joinsql = 'JOIN {forum_discussions} fd ON fd.course = c.id';
+ $wheresql = 'fd.userid = :userid';
+ $params = array('userid' => $user->id);
+ }
+
+ // Join to the context table so that we can preload contexts if required.
+ if ($includecontexts) {
+ list($ctxselect, $ctxjoin) = context_instance_preload_sql('c.id', CONTEXT_COURSE, 'ctx');
+ } else {
+ $ctxselect = '';
+ $ctxjoin = '';
+ }
+
+ // Now we need to get all of the courses to search.
+ // All courses where the user has posted within a forum will be returned.
+ $sql = "SELECT DISTINCT c.* $ctxselect
+ FROM {course} c
+ $joinsql
+ $ctxjoin
+ WHERE $wheresql";
+ $courses = $DB->get_records_sql($sql, $params, $limitfrom, $limitnum);
+ if ($includecontexts) {
+ array_map('context_instance_preload', $courses);
+ }
+ return $courses;
+}
+
+/**
+ * Gets all of the forums a user has posted in for one or more courses.
+ *
+ * @global moodle_database $DB
+ * @param stdClass $user
+ * @param array $courseids An array of courseids to search or if not provided
+ * all courses the user has posted within
+ * @param bool $discussionsonly If true then only forums where the user has started
+ * a discussion will be returned.
+ * @param type $limitfrom The offset of records to return
+ * @param type $limitnum The number of records to return
+ * @return array An array of forums the user has posted within in the provided courses
+ */
+function forum_get_forums_user_posted_in($user, array $courseids = null, $discussionsonly = false, $limitfrom = null, $limitnum = null) {
+ global $DB;
+
+ $where = array("m.name = 'forum'");
+ $params = array();
+ if (!is_null($courseids)) {
+ list($coursewhere, $params) = $DB->get_in_or_equal($courseids, SQL_PARAMS_NAMED, 'courseid');
+ $where[] = 'f.course '.$coursewhere;
+ }
+ if (!$discussionsonly) {
+ $joinsql = 'JOIN {forum_discussions} fd ON fd.forum = f.id
+ JOIN {forum_posts} fp ON fp.discussion = fd.id';
+ $where[] = 'fp.userid = :userid';
+ } else {
+ $joinsql = 'JOIN {forum_discussions} fd ON fd.forum = f.id';
+ $where[] = 'fd.userid = :userid';
+ }
+ $params['userid'] = $user->id;
+ $wheresql = join(' AND ', $where);
+
+ $sql = "SELECT DISTINCT f.*, cm.id AS cmid
+ FROM {forum} f
+ JOIN {course_modules} cm ON cm.instance = f.id
+ JOIN {modules} m ON m.id = cm.module
+ $joinsql
+ WHERE $wheresql";
+ $courseforums = $DB->get_records_sql($sql, $params, $limitfrom, $limitnum);
+ return $courseforums;
+}
+
+/**
+ * Returns posts made by the selected user in the requested courses.
+ *
+ * This method can be used to return all of the posts made by the requested user
+ * within the given courses.
+ * For each course the access of the current user and requested user is checked
+ * and then for each post access to the post and forum is checked as well.
+ *
+ * This function is safe to use with usercapabilities.
+ *
+ * @global moodle_database $DB
+ * @param stdClass $user The user whose posts we want to get
+ * @param array $courses The courses to search
+ * @param bool $musthaveaccess If set to true errors will be thrown if the user
+ * cannot access one or more of the courses to search
+ * @param bool $discussionsonly If set to true only discussion starting posts
+ * will be returned.
+ * @return stdClass An object the following properties
+ * ->totalcount: the total number of posts made by the requested user
+ * that the current user can see.
+ * ->courses: An array of courses the current user can see that the
+ * requested user has posted in.
+ * ->forums: An array of forums relating to the posts returned in the
+ * property below.
+ * ->posts: An array containing the posts to show for this request.
+ */
+function forum_get_posts_by_user($user, array $courses, $musthaveaccess = false, $discussionsonly = false, $limitfrom = 0, $limitnum = 50) {
+ global $DB, $USER;
+
+ $return = new stdClass;
+ $return->totalcount = 0; // The total number of posts that the current user is able to view
+ $return->courses = array(); // The courses the current user can access
+ $return->forums = array(); // The forums that the current user can access that contain posts
+ $return->posts = array(); // The posts to display
+
+ // First up a small sanity check. If there are no courses to check we can
+ // return immediately, there is obviously nothing to search.
+ if (empty($courses)) {
+ return $return;
+ }
+
+ // A couple of quick setups
+ $isloggedin = isloggedin();
+ $isguestuser = $isloggedin && isguestuser();
+ $iscurrentuser = $isloggedin && $USER->id == $user->id;
+
+ // Checkout whether or not the current user has capabilities over the requested
+ // user and if so they have the capabilities required to view the requested
+ // users content.
+ $usercontext = get_context_instance(CONTEXT_USER, $user->id, MUST_EXIST);
+ $hascapsonuser = !$iscurrentuser && $DB->record_exists('role_assignments', array('userid' => $USER->id, 'contextid' => $usercontext->id));
+ $hascapsonuser = $hascapsonuser && has_all_capabilities(array('moodle/user:viewdetails', 'moodle/user:readuserposts'), $usercontext);
+
+ // Before we actually search each course we need to check the user's access to the
+ // course. If the user doesn't have the appropraite access then we either throw an
+ // error if a particular course was requested or we just skip over the course.
+ foreach ($courses as $course) {
+ $coursecontext = get_context_instance(CONTEXT_COURSE, $course->id, MUST_EXIST);
+ if ($iscurrentuser || $hascapsonuser) {
+ // If it is the current user, or the current user has capabilities to the
+ // requested user then all we need to do is check the requested users
+ // current access to the course.
+ // Note: There is no need to check group access or anything of the like
+ // as either the current user is the requested user, or has granted
+ // capabilities on the requested user. Either way they can see what the
+ // requested user posted, although its VERY unlikely in the `parent` situation
+ // that the current user will be able to view the posts in context.
+ if (!is_viewing($coursecontext, $user) && !is_enrolled($coursecontext, $user)) {
+ // Need to have full access to a course to see the rest of own info
+ if ($musthaveaccess) {
+ print_error('errorenrolmentrequired', 'forum');
+ }
+ continue;
+ }
+ } else {
+ // Check whether the current user is enrolled or has access to view the course
+ // if they don't we immediately have a problem.
+ if (!can_access_course($coursecontext)) {
+ if ($musthaveaccess) {
+ print_error('errorenrolmentrequired', 'forum');
+ }
+ continue;
+ }
+
+ // Check whether the requested user is enrolled or has access to view the course
+ // if they don't we immediately have a problem.
+ if (!can_access_course($coursecontext, $user)) {
+ if ($musthaveaccess) {
+ print_error('notenrolled', 'forum');
+ }
+ continue;
+ }
+
+ // If groups are in use and enforced throughout the course then make sure
+ // we can meet in at least one course level group.
+ // Note that we check if either the current user or the requested user have
+ // the capability to access all groups. This is because with that capability
+ // a user in group A could post in the group B forum. Grrrr.
+ if (groups_get_course_groupmode($course) == SEPARATEGROUPS && $course->groupmodeforce
+ && !has_capability('moodle/site:accessallgroups', $coursecontext) && !has_capability('moodle/site:accessallgroups', $coursecontext, $user->id)) {
+ // If its the guest user to bad... the guest user cannot access groups
+ if (!$isloggedin or $isguestuser) {
+ // do not use require_login() here because we might have already used require_login($course)
+ if ($musthaveaccess) {
+ redirect(get_login_url());
+ }
+ continue;
+ }
+ // Get the groups of the current user
+ $mygroups = array_keys(groups_get_all_groups($course->id, $USER->id, $course->defaultgroupingid, 'g.id, g.name'));
+ // Get the groups the requested user is a member of
+ $usergroups = array_keys(groups_get_all_groups($course->id, $user->id, $course->defaultgroupingid, 'g.id, g.name'));
+ // Check whether they are members of the same group. If they are great.
+ if (!array_intersect($mygroups, $usergroups)) {
+ // But they're not... if it was a specific course throw an error otherwise
+ // just skip this course so that it is not searched.
+ if ($musthaveaccess) {
+ print_error("groupnotamember", '', $CFG->wwwroot."/course/view.php?id=$course->id");
+ }
+ continue;
+ }
+ }
+ }
+ // Woo hoo we got this far which means the current user can search this
+ // this course for the requested user. Although this is only the course accessibility
+ // handling that is complete, the forum accessibility tests are yet to come.
+ $return->courses[$course->id] = $course;
+ }
+ // No longer beed $courses array - lose it not it may be big
+ unset($courses);
+
+ // Make sure that we have some courses to search
+ if (empty($return->courses)) {
+ // If we don't have any courses to search then the reality is that the current
+ // user doesn't have access to any courses is which the requested user has posted.
+ // Although we do know at this point that the requested user has posts.
+ if ($musthaveaccess) {
+ print_error('permissiondenied');
+ } else {
+ return $return;
+ }
+ }
+
+ // Next step: Collect all of the forums that we will want to search.
+ // It is important to note that this step isn't actually about searching, it is
+ // about determining which forums we can search by testing accessibility.
+ $forums = forum_get_forums_user_posted_in($user, array_keys($return->courses), $discussionsonly);
+
+ // Will be used to build the where conditions for the search
+ $forumsearchwhere = array();
+ // Will be used to store the where condition params for the search
+ $forumsearchparams = array();
+ // Will record forums where the user can freely access everything
+ $forumsearchfullaccess = array();
+ // For each course to search we want to find the forums the user has posted in
+ // and providing the current user can access the forum create a search condition
+ // for the forum to get the requested users posts.
+ foreach ($return->courses as $course) {
+ // Now we need to get the forums
+ $modinfo = get_fast_modinfo($course);
+ if (empty($modinfo->instances['forum'])) {
+ // hmmm, no forums? well at least its easy... skip!
+ continue;
+ }
+ // Iterate
+ foreach ($modinfo->get_instances_of('forum') as $forumid => $cm) {
+ if (!$cm->uservisible or !isset($forums[$forumid])) {
+ continue;
+ }
+ // Get the forum in question
+ $forum = $forums[$forumid];
+ // This is needed for functionality later on in the forum code....
+ $forum->cm = $cm;
+
+ // Check that either the current user can view the forum, or that the
+ // current user has capabilities over the requested user and the requested
+ // user can view the discussion
+ if (!has_capability('mod/forum:viewdiscussion', $cm->context) && !($hascapsonuser && has_capability('mod/forum:viewdiscussion', $cm->context, $user->id))) {
+ continue;
+ }
+
+ // This will contain forum specific where clauses
+ $forumsearchselect = array();
+ if (!$iscurrentuser && !$hascapsonuser) {
+ // Make sure we check group access
+ if (groups_get_activity_groupmode($cm, $course) == SEPARATEGROUPS and !has_capability('moodle/site:accessallgroups', $cm->context)) {
+ $groups = $modinfo->get_groups($cm->groupingid);
+ $groups[] = -1;
+ list($groupid_sql, $groupid_params) = $DB->get_in_or_equal($groups, SQL_PARAMS_NAMED, 'grps'.$forumid.'_');
+ $forumsearchparams = array_merge($forumsearchparams, $groupid_params);
+ $forumsearchselect[] = "d.groupid $groupid_sql";
+ }
+
+ // hidden timed discussions
+ if (!empty($CFG->forum_enabletimedposts) && !has_capability('mod/forum:viewhiddentimedposts', $cm->context)) {
+ $forumsearchselect[] = "(d.userid = :userid{$forumid} OR (d.timestart < :timestart{$forumid} AND (d.timeend = 0 OR d.timeend > :timeend{$forumid})))";
+ $forumsearchparams['userid'.$forumid] = $user->id;
+ $forumsearchparams['timestart'.$forumid] = $now;
+ $forumsearchparams['timeend'.$forumid] = $now;
+ }
+
+ // qanda access
+ if ($forum->type == 'qanda' && !has_capability('mod/forum:viewqandawithoutposting', $cm->context)) {
+ // We need to check whether the user has posted in the qanda forum.
+ $discussionspostedin = forum_discussions_user_has_posted_in($forum->id, $user->id);
+ if (!empty($discussionspostedin)) {
+ $forumonlydiscussions = array(); // Holds discussion ids for the discussions the user is allowed to see in this forum.
+ foreach ($discussionspostedin as $d) {
+ $forumonlydiscussions[] = $d->id;
+ }
+ list($discussionid_sql, $discussionid_params) = $DB->get_in_or_equal($forumonlydiscussions, SQL_PARAMS_NAMED, 'qanda'.$forumid.'_');
+ $forumsearchparams = array_merge($forumsearchparams, $discussionid_params);
+ $forumsearchselect[] = "(d.id $discussionid_sql OR p.parent = 0)";
+ } else {
+ $forumsearchselect[] = "p.parent = 0";
+ }
+
+ }
+
+ if (count($forumsearchselect) > 0) {
+ $forumsearchwhere[] = "(d.forum = :forum{$forumid} AND ".implode(" AND ", $forumsearchselect).")";
+ $forumsearchparams['forum'.$forumid] = $forumid;
+ } else {
+ $forumsearchfullaccess[] = $forumid;
+ }
+ } else {
+ // The current user/parent can see all of their own posts
+ $forumsearchfullaccess[] = $forumid;
+ }
+ }
+ }
+
+ // If we dont have any search conditions, and we don't have any forums where
+ // the user has full access then we just return the default.
+ if (empty($forumsearchwhere) && empty($forumsearchfullaccess)) {
+ return $return;
+ }
+
+ // Prepare a where condition for the full access forums.
+ if (count($forumsearchfullaccess) > 0) {
+ list($fullidsql, $fullidparams) = $DB->get_in_or_equal($forumsearchfullaccess, SQL_PARAMS_NAMED, 'fula');
+ $forumsearchparams = array_merge($forumsearchparams, $fullidparams);
+ $forumsearchwhere[] = "(d.forum $fullidsql)";
+ }
+
+ // Prepare SQL to both count and search
+ $userfields = user_picture::fields('u', null, 'userid');
+ $countsql = 'SELECT COUNT(*) ';
+ $selectsql = 'SELECT p.*, d.forum, d.name AS discussionname, '.$userfields.' ';
+ $wheresql = implode(" OR ", $forumsearchwhere);
+
+ if ($discussionsonly) {
+ if ($wheresql == '') {
+ $wheresql = 'p.parent = 0';
+ } else {
+ $wheresql = 'p.parent = 0 AND ('.$wheresql.')';
+ }
+ }
+
+ $sql = "FROM {forum_posts} p
+ JOIN {forum_discussions} d ON d.id = p.discussion
+ JOIN {user} u ON u.id = p.userid
+ WHERE ($wheresql)
+ AND p.userid = :userid ";
+ $orderby = "ORDER BY p.modified DESC";
+ $forumsearchparams['userid'] = $user->id;
+
+ // Set the total number posts made by the requested user that the current user can see
+ $return->totalcount = $DB->count_records_sql($countsql.$sql, $forumsearchparams);
+ // Set the collection of posts that has been requested
+ $return->posts = $DB->get_records_sql($selectsql.$sql.$orderby, $forumsearchparams, $limitfrom, $limitnum);
+
+ // We need to build an array of forums for which posts will be displayed.
+ // We do this here to save the caller needing to retrieve them themselves before
+ // printing these forums posts. Given we have the forums already there is
+ // practically no overhead here.
+ foreach ($return->posts as $post) {
+ if (!array_key_exists($post->forum, $return->forums)) {
+ $return->forums[$post->forum] = $forums[$post->forum];
+ }
+ }
+
+ return $return;
+}
\ No newline at end of file
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
-require_once('../../config.php');
-require_once('lib.php');
-
-// Course ID
-$course = optional_param('course', SITEID, PARAM_INT);
-// User ID
-$id = optional_param('id', 0, PARAM_INT);
-$mode = optional_param('mode', 'posts', PARAM_ALPHA);
-$page = optional_param('page', 0, PARAM_INT);
-$perpage = optional_param('perpage', 5, PARAM_INT);
-
-$url = new moodle_url('/mod/forum/user.php');
-if ($course !== SITEID) {
- $url->param('course', $course);
-}
-if ($id !== 0) {
- $url->param('id', $id);
-}
-if ($mode !== 'posts') {
- $url->param('mode', $mode);
+require_once(dirname(dirname(dirname(__FILE__))).'/config.php');
+require_once($CFG->dirroot.'/mod/forum/lib.php');
+require_once($CFG->dirroot.'/rating/lib.php');
+
+$courseid = optional_param('course', null, PARAM_INT); // Limit the posts to just this course
+$userid = optional_param('id', $USER->id, PARAM_INT); // User id whose posts we want to view
+$mode = optional_param('mode', 'posts', PARAM_ALPHA); // The mode to use. Either posts or discussions
+$page = optional_param('page', 0, PARAM_INT); // The page number to display
+$perpage = optional_param('perpage', 5, PARAM_INT); // The number of posts to display per page
+
+if (empty($userid)) {
+ if (!isloggedin()) {
+ require_login();
+ }
+ $userid = $USER->id;
}
+
+$discussionsonly = ($mode !== 'posts');
+$isspecificcourse = !is_null($courseid);
+$iscurrentuser = ($USER->id == $userid);
+
+$url = new moodle_url('/mod/forum/user.php', array('id' => $userid));
+if ($isspecificcourse) $url->param('course', $courseid);
+if ($discussionsonly) $url->param('mode', 'discussions');
+
$PAGE->set_url($url);
$PAGE->set_pagelayout('standard');
-if (empty($id)) { // See your own profile by default
- require_login();
- $id = $USER->id;
-}
-
-$user = $DB->get_record("user", array("id" => $id), '*', MUST_EXIST);
-$course = $DB->get_record("course", array("id" => $course), '*', MUST_EXIST);
+if ($page != 0) $url->param('page', $page);
+if ($perpage != 5) $url->param('perpage', $perpage);
-$syscontext = get_context_instance(CONTEXT_SYSTEM);
-$usercontext = get_context_instance(CONTEXT_USER, $id);
+add_to_log(($isspecificcourse)?$courseid:SITEID, "forum", "user report", 'user.php?'.$url->get_query_string(), $userid);
-// do not force parents to enrol
-if (!$DB->get_record('role_assignments', array('userid' => $USER->id, 'contextid' => $usercontext->id))) {
- require_course_login($course);
-} else {
- $PAGE->set_course($course);
+$user = $DB->get_record("user", array("id" => $userid), '*', MUST_EXIST);
+$usercontext = get_context_instance(CONTEXT_USER, $user->id, MUST_EXIST);
+// Check if the requested user is the guest user
+if (isguestuser($user)) {
+ // The guest user cannot post, so it is not possible to view any posts.
+ // May as well just bail aggressively here.
+ print_error('invaliduserid');
}
-
+// Make sure the user has not been deleted
if ($user->deleted) {
+ $PAGE->set_title(get_string('userdeleted'));
+ $PAGE->set_context(get_system_context());
echo $OUTPUT->header();
- echo $OUTPUT->heading(get_string('userdeleted'));
+ echo $OUTPUT->heading($PAGE->title);
echo $OUTPUT->footer();
die;
}
-add_to_log($course->id, "forum", "user report",
- "user.php?course=$course->id&id=$user->id&mode=$mode", "$user->id");
-
-$strforumposts = get_string('forumposts', 'forum');
-$strparticipants = get_string('participants');
-$strmode = get_string($mode, 'forum');
-$fullname = fullname($user, has_capability('moodle/site:viewfullnames', $syscontext));
-
-$link = null;
-if (has_capability('moodle/course:viewparticipants', get_context_instance(CONTEXT_COURSE, $course->id)) || has_capability('moodle/site:viewparticipants', $syscontext)) {
- $link = new moodle_url('/user/index.php',array('id'=>$course->id));
-}
-
-$PAGE->navigation->extend_for_user($user);
-$PAGE->navigation->set_userid_for_parent_checks($id); // see MDL-25805 for reasons and for full commit reference for reversal when fixed.
-$PAGE->set_title("$course->shortname: $fullname: $strmode");
-$PAGE->set_heading($course->fullname);
-echo $OUTPUT->header();
-echo $OUTPUT->heading($fullname);
-
-switch ($mode) {
- case 'posts' :
- $searchterms = array('userid:'.$user->id);
- $extrasql = '';
- break;
-
- default:
- $searchterms = array('userid:'.$user->id);
- $extrasql = 'AND p.parent = 0';
- break;
-}
-
-echo '<div class="user-content">';
-
-if ($course->id == SITEID) {
- $searchcourse = SITEID;
- if (empty($CFG->forceloginforprofiles) or (isloggedin() and !isguestuser() and !is_web_crawler())) {
- // Search throughout the whole site.
- $searchcourse = 0;
+$isloggedin = isloggedin();
+$isguestuser = $isloggedin && isguestuser();
+$isparent = !$iscurrentuser && $DB->record_exists('role_assignments', array('userid'=>$USER->id, 'contextid'=>$usercontext->id));
+$hasparentaccess = $isparent && has_all_capabilities(array('moodle/user:viewdetails', 'moodle/user:readuserposts'), $usercontext);
+
+// Check whether a specific course has been requested
+if ($isspecificcourse) {
+ // Get the requested course and its context
+ $course = $DB->get_record('course', array('id' => $courseid), '*', MUST_EXIST);
+ $coursecontext = get_context_instance(CONTEXT_COURSE, $courseid, MUST_EXIST);
+ // We have a specific course to search, which we will also assume we are within.
+ if ($hasparentaccess) {
+ // A `parent` role won't likely have access to the course so we won't attempt
+ // to enter it. We will however still make them jump through the normal
+ // login hoops
+ require_login();
+ $PAGE->set_context($coursecontext);
+ $PAGE->set_course($course);
+ } else {
+ // Enter the course we are searching
+ require_login($course);
}
+ // Get the course ready for access checks
+ $courses = array($courseid => $course);
} else {
- // Search only for posts the user made in this course.
- $searchcourse = $course->id;
-}
-
-// Get the posts.
-$posts = forum_search_posts($searchterms, $searchcourse, $page*$perpage, $perpage, $totalcount, $extrasql);
-if ($posts) {
-
- require_once($CFG->dirroot.'/rating/lib.php');
+ // We are going to search for all of the users posts in all courses!
+ // a general require login here as we arn't actually within any course.
+ require_login();
+ $PAGE->set_context(get_system_context());
- $baseurl = new moodle_url('user.php', array('id' => $user->id, 'course' => $course->id, 'mode' => $mode, 'perpage' => $perpage));
- echo $OUTPUT->paging_bar($totalcount, $page, $perpage, $baseurl);
+ // Now we need to get all of the courses to search.
+ // All courses where the user has posted within a forum will be returned.
+ $courses = forum_get_courses_user_posted_in($user, $discussionsonly);
+}
- $discussions = array();
- $forums = array();
+// Get the posts by the requested user that the current user can access.
+$result = forum_get_posts_by_user($user, $courses, $isspecificcourse, $discussionsonly, ($page * $perpage), $perpage);
+
+// Check whether there are not posts to display.
+if (empty($result->posts)) {
+ // Ok no posts to display means that either the user has not posted or there
+ // are no posts made by the requested user that the current user is able to
+ // see.
+ // In either case we need to decide whether we can show personal information
+ // about the requested user to the current user so we will execute some checks
+
+ // First check the obvious, its the current user, a specific course has been
+ // provided (require_login has been called), or they have a course contact role.
+ // True to any of those and the current user can see the details of the
+ // requested user.
+ $canviewuser = ($iscurrentuser || $isspecificcourse || empty($CFG->forceloginforprofiles) || has_coursecontact_role($userid));
+ // Next we'll check the caps, if the current user has the view details and a
+ // specific course has been requested, or if they have the view all details
+ $canviewuser = ($canviewuser || ($isspecificcourse && has_capability('moodle/user:viewdetails', $coursecontext) || has_capability('moodle/user:viewalldetails', $usercontext)));
+
+ // If none of the above was true the next step is to check a shared relation
+ // through some course
+ if (!$canviewuser) {
+ // Get all of the courses that the users have in common
+ $sharedcourses = enrol_get_shared_courses($USER->id, $user->id, true);
+ foreach ($sharedcourses as $sharedcourse) {
+ // Check the view cap within the course context
+ if (has_capability('moodle/user:viewdetails', get_context_instance(CONTEXT_COURSE, $sharedcourse->id))) {
+ $canviewuser = true;
+ break;
+ }
+ }
+ unset($sharedcourses);
+ }
- //todo Rather than retrieving the ratings for each post individually it would be nice to do them in groups
- //however this requires creating arrays of posts with each array containing all of the posts from a particular forum,
- //retrieving the ratings then reassembling them all back into a single array sorted by post.modified (descending)
- $rm = new rating_manager();
- $ratingoptions = new stdClass;
- $ratingoptions->component = 'mod_forum';
- $ratingoptions->ratingarea = 'post';
+ // Prepare the page title
+ $pagetitle = get_string('noposts', 'mod_forum');
- foreach ($posts as $post) {
+ // Get the page heading
+ if ($isspecificcourse) {
+ $pageheading = format_string($course->shortname, true, array('context' => $coursecontext));
+ } else {
+ $pageheading = get_string('pluginname', 'mod_forum');
+ }
- if (!isset($discussions[$post->discussion])) {
- if (! $discussion = $DB->get_record('forum_discussions', array('id' => $post->discussion))) {
- print_error('invaliddiscussionid', 'forum');
- }
- $discussions[$post->discussion] = $discussion;
+ // Next we need to set up the loading of the navigation and choose a message
+ // to display to the current user.
+ if ($iscurrentuser) {
+ // No need to extend the navigation it happens automatically for the
+ // current user.
+ if ($discussionsonly) {
+ $notification = get_string('nodiscussionsstartedbyyou', 'forum');
} else {
- $discussion = $discussions[$post->discussion];
+ $notification = get_string('nopostsmadebyyou', 'forum');
}
-
- if (!isset($forums[$discussion->forum])) {
- $forum = $DB->get_record('forum', array('id' => $discussion->forum), '*', MUST_EXIST);
- $forum->cm = get_coursemodule_from_instance('forum', $forum->id, 0, false, MUST_EXIST);
- $forum->context = get_context_instance(CONTEXT_MODULE, $forum->cm->id);
- $forums[$discussion->forum] = $forum;
+ } else if ($canviewuser) {
+ $PAGE->navigation->extend_for_user($user);
+ $PAGE->navigation->set_userid_for_parent_checks($user->id); // see MDL-25805 for reasons and for full commit reference for reversal when fixed.
+ $fullname = fullname($user);
+ if ($discussionsonly) {
+ $notification = get_string('nodiscussionsstartedby', 'forum', $fullname);
} else {
- $forum = $forums[$discussion->forum];
+ $notification = get_string('nopostsmadebyuser', 'forum', $fullname);
}
+ } else {
+ // Don't extend the navigation it would be giving out information that
+ // the current uesr doesn't have access to.
+ $notification = get_string('cannotviewusersposts', 'forum');
+ if ($isspecificcourse) {
+ $url = new moodle_url('/course/view.php', array('id' => $courseid));
+ } else {
+ $url = new moodle_url('/');
+ }
+ navigation_node::override_active_url($url);
+ }
- $forumurl = new moodle_url('/mod/forum/view.php', array('id' => $forum->cm->id));
- $discussionurl = new moodle_url('/mod/forum/discuss.php', array('d' => $discussion->id));
-
- // load ratings
- if ($forum->assessed != RATING_AGGREGATE_NONE) {
- $ratingoptions->context = $forum->context;
- $ratingoptions->items = array($post);
- $ratingoptions->aggregate = $forum->assessed;//the aggregation method
- $ratingoptions->scaleid = $forum->scale;
- $ratingoptions->userid = $user->id;
- $ratingoptions->assesstimestart = $forum->assesstimestart;
- $ratingoptions->assesstimefinish = $forum->assesstimefinish;
- if ($forum->type == 'single' or !$discussion->id) {
- $ratingoptions->returnurl = $forumurl;
- } else {
- $ratingoptions->returnurl = $discussionurl;
- }
+ // Display a page letting the user know that there's nothing to display;
+ $PAGE->set_title($pagetitle);
+ $PAGE->set_heading($pageheading);
+ echo $OUTPUT->header();
+ echo $OUTPUT->heading($pagetitle);
+ echo $OUTPUT->notification($notification);
+ echo $OUTPUT->continue_button($url);
+ echo $OUTPUT->footer();
+ die;
+}
+
+// Post output will contain an entry containing HTML to display each post by the
+// time we are done.
+$postoutput = array();
- $updatedpost = $rm->get_ratings($ratingoptions);
- //updating the array this way because we're iterating over a collection and updating them one by one
- $posts[$updatedpost[0]->id] = $updatedpost[0];
+$discussions = array();
+foreach ($result->posts as $post) {
+ $discussions[] = $post->discussion;
+}
+$discussions = $DB->get_records_list('forum_discussions', 'id', array_unique($discussions));
+
+//todo Rather than retrieving the ratings for each post individually it would be nice to do them in groups
+//however this requires creating arrays of posts with each array containing all of the posts from a particular forum,
+//retrieving the ratings then reassembling them all back into a single array sorted by post.modified (descending)
+$rm = new rating_manager();
+$ratingoptions = new stdClass;
+$ratingoptions->component = 'mod_forum';
+$ratingoptions->ratingarea = 'post';
+foreach ($result->posts as $post) {
+ if (!isset($result->forums[$post->forum]) || !isset($discussions[$post->discussion])) {
+ // Something very VERY dodgy has happened if we end up here
+ continue;
+ }
+ $forum = $result->forums[$post->forum];
+ $cm = $forum->cm;
+ $discussion = $discussions[$post->discussion];
+ $course = $result->courses[$discussion->course];
+
+ $forumurl = new moodle_url('/mod/forum/view.php', array('id' => $cm->id));
+ $discussionurl = new moodle_url('/mod/forum/discuss.php', array('d' => $post->discussion));
+
+ // load ratings
+ if ($forum->assessed != RATING_AGGREGATE_NONE) {
+ $ratingoptions->context = $cm->context;
+ $ratingoptions->items = array($post);
+ $ratingoptions->aggregate = $forum->assessed;//the aggregation method
+ $ratingoptions->scaleid = $forum->scale;
+ $ratingoptions->userid = $user->id;
+ $ratingoptions->assesstimestart = $forum->assesstimestart;
+ $ratingoptions->assesstimefinish = $forum->assesstimefinish;
+ if ($forum->type == 'single' or !$post->discussion) {
+ $ratingoptions->returnurl = $forumurl;
+ } else {
+ $ratingoptions->returnurl = $discussionurl;
}
- $fullsubjects = array();
- if ($course->id == SITEID && has_capability('moodle/site:config', $syscontext)) {
- $postcoursename = $DB->get_field('course', 'shortname', array('id'=>$forum->course));
- $courseurl = new moodle_url('/course/view.php', array('id' => $forum->course));
- $fullsubjects[] = html_writer::link($courseurl, $postcoursename);
+ $updatedpost = $rm->get_ratings($ratingoptions);
+ //updating the array this way because we're iterating over a collection and updating them one by one
+ $result->posts[$updatedpost[0]->id] = $updatedpost[0];
+ }
+
+ $courseshortname = format_string($course->shortname, true, array('context' => get_context_instance(CONTEXT_COURSE, $course->id)));
+ $forumname = format_string($forum->name, true, array('context' => $cm->context));
+
+ $fullsubjects = array();
+ if (!$isspecificcourse && !$hasparentaccess) {
+ $fullsubjects[] = html_writer::link(new moodle_url('/course/view.php', array('id' => $course->id)), $courseshortname);
+ $fullsubjects[] = html_writer::link($forumurl, $forumname);
+ } else {
+ $fullsubjects[] = html_writer::tag('span', $courseshortname);
+ $fullsubjects[] = html_writer::tag('span', $forumname);
+ }
+ if ($forum->type != 'single') {
+ $discussionname = format_string($discussion->name, true, array('context' => $cm->context));
+ if (!$isspecificcourse && !$hasparentaccess) {
+ $fullsubjects[] .= html_writer::link($discussionurl, $discussionname);
+ } else {
+ $fullsubjects[] .= html_writer::tag('span', $discussionname);
}
- $fullsubjects[] = html_writer::link($forumurl, format_string($forum->name, true));
- if ($forum->type != 'single') {
- $fullsubjects[] .= html_writer::link($discussionurl, format_string($discussion->name, true));
- if ($post->parent != 0) {
- $parenturl = new moodle_url('/mod/forum/discuss.php', array('d' => $post->discussion, 'parent' => $post->id));
- $fullsubjects[] .= html_writer::link($parenturl, format_string($post->subject, true));
+ if ($post->parent != 0) {
+ $postname = format_string($post->subject, true, array('context' => $cm->context));
+ if (!$isspecificcourse && !$hasparentaccess) {
+ $fullsubjects[] .= html_writer::link(new moodle_url('/mod/forum/discuss.php', array('d' => $post->discussion, 'parent' => $post->id)), $postname);
+ } else {
+ $fullsubjects[] .= html_writer::tag('span', $postname);
}
}
-
- $post->subject = join(' -> ', $fullsubjects);
- $discussionurl->set_anchor('p'.$post->id);
- $fulllink = html_writer::link($discussionurl, get_string("postincontext", "forum"));
-
- forum_print_post($post, $discussion, $forum, $forum->cm, $course, false, false, false, $fulllink);
- echo "<br />";
}
+ $post->subject = join(' -> ', $fullsubjects);
+ // This is really important, if the strings are formatted again all the links
+ // we've added will be lost.
+ $post->subjectnoformat = true;
+ $discussionurl->set_anchor('p'.$post->id);
+ $fulllink = html_writer::link($discussionurl, get_string("postincontext", "forum"));
+
+ $postoutput[] = forum_print_post($post, $discussion, $forum, $cm, $course, false, false, false, $fulllink, '', null, true, null, true);
+}
- echo $OUTPUT->paging_bar($totalcount, $page, $perpage, $baseurl);
+$userfullname = fullname($user);
+
+if ($discussionsonly) {
+ $inpageheading = get_string('discussionsstartedby', 'mod_forum', $userfullname);
} else {
- if ($mode == 'posts') {
- echo $OUTPUT->heading(get_string('noposts', 'forum'));
+ $inpageheading = get_string('postsmadebyuser', 'mod_forum', $userfullname);
+}
+if ($isspecificcourse) {
+ $a = new stdClass;
+ $a->fullname = $userfullname;
+ $a->coursename = format_string($course->shortname, true, array('context' => $coursecontext));
+ $pageheading = $a->coursename;
+ if ($discussionsonly) {
+ $pagetitle = get_string('discussionsstartedbyuserincourse', 'mod_forum', $a);
} else {
- echo $OUTPUT->heading(get_string('nodiscussionsstartedby', 'forum'));
+ $pagetitle = get_string('postsmadebyuserincourse', 'mod_forum', $a);
}
+} else {
+ $pagetitle = $inpageheading;
+ $pageheading = $userfullname;
}
-echo '</div>';
-echo $OUTPUT->footer();
+$PAGE->set_title($pagetitle);
+$PAGE->set_heading($pagetitle);
+$PAGE->navigation->extend_for_user($user);
+$PAGE->navigation->set_userid_for_parent_checks($user->id); // see MDL-25805 for reasons and for full commit reference for reversal when fixed.
+
+echo $OUTPUT->header();
+echo $OUTPUT->heading($inpageheading);
+echo html_writer::start_tag('div', array('class' => 'user-content'));
+
+if (!empty($postoutput)) {
+ echo $OUTPUT->paging_bar($result->totalcount, $page, $perpage, $url);
+ foreach ($postoutput as $post) {
+ echo $post;
+ echo html_writer::empty_tag('br');
+ }
+ echo $OUTPUT->paging_bar($result->totalcount, $page, $perpage, $url);
+} else if ($discussionsonly) {
+ echo $OUTPUT->heading(get_string('nodiscussionsstartedby', 'forum', $userfullname));
+} else {
+ echo $OUTPUT->heading(get_string('noposts', 'forum'));
+}
+
+echo html_writer::end_tag('div');
+echo $OUTPUT->footer();
if (!empty($CFG->forceloginforprofiles)) {
require_login(); // we can not log in to course due to the parent hack bellow
- if (isguestuser()) {
- $SESSION->wantsurl = $PAGE->url->out(false);
- redirect(get_login_url());
- }
}
$PAGE->set_context($coursecontext);
/// Now test the actual capabilities and enrolment in course
if ($currentuser) {
// me
- if (!is_enrolled($coursecontext) and !is_viewing($coursecontext)) { // Need to have full access to a course to see the rest of own info
+ if (!is_viewing($coursecontext) && !is_enrolled($coursecontext)) { // Need to have full access to a course to see the rest of own info
echo $OUTPUT->header();
echo $OUTPUT->heading(get_string('notenrolled', '', $fullname));
if (!empty($_SERVER['HTTP_REFERER'])) {