/** * Generate the second options array for hierselect form element * * For all discussions, allow the All option. If the current * user has posted in the discussion, then allow exporting * of their own posts. * * @param array $discussions The result from get_discussion_options * @return array */ public function get_anonymous_discussion_user_options($discussions) { global $USER; $posted = hsuforum_discussions_user_has_posted_in($this->_customdata->forum->id, $USER->id); $options = array(0 => array(0 => get_string('all', 'hsuforum'))); if (!empty($posted)) { $options[0][$USER->id] = $this->get_fullname($USER); } foreach (array_keys($discussions) as $discussionid) { if (empty($discussionid)) { continue; // This is the zero (AKA All) option, skip! } $useropts = array(0 => get_string('all', 'hsuforum')); if (array_key_exists($discussionid, $posted)) { $useropts[$USER->id] = $this->get_fullname($USER); } $options[$discussionid] = $useropts; } return $options; }
/** * 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. * @param int $limitfrom The offset of records to return * @param int $limitnum The number of records to return * @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 hsuforum_get_posts_by_user($user, array $courses, $musthaveaccess = false, $discussionsonly = false, $limitfrom = 0, $limitnum = 50) { global $DB, $USER, $CFG; $config = get_config('hsuforum'); $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 = context_user::instance($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 = context_course::instance($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', 'hsuforum'); } 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($course)) { if ($musthaveaccess) { print_error('errorenrolmentrequired', 'hsuforum'); } 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($course, $user) && !is_enrolled($coursecontext, $user)) { if ($musthaveaccess) { print_error('notenrolled', 'hsuforum'); } 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. $intersect = array_intersect($mygroups, $usergroups); if (empty($intersect)) { // 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 = hsuforum_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(); // DB caching friendly $now = round(time(), -2); // 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['hsuforum'])) { // hmmm, no forums? well at least its easy... skip! continue; } // Iterate foreach ($modinfo->get_instances_of('hsuforum') 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. It is converted to an object // because the cm_info is readonly from 2.6. This is a dirty hack because some other parts of the // code were expecting an writeable object. $forum->cm = new stdClass(); foreach ($cm as $key => $value) { $forum->cm->{$key} = $value; } // 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/hsuforum:viewdiscussion', $cm->context) && !($hascapsonuser && has_capability('mod/hsuforum: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($config->enabletimedposts) && !has_capability('mod/hsuforum: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/hsuforum:viewqandawithoutposting', $cm->context)) { // We need to check whether the user has posted in the qanda forum. $discussionspostedin = hsuforum_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. // We alias user.id to useridx because we hsuforum_posts already has a userid field and not aliasing this would break // oracle and mssql. $userfields = user_picture::fields('u', null, 'useridx'); $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 {hsuforum_posts} p\n JOIN {hsuforum_discussions} d ON d.id = p.discussion\n JOIN {hsuforum} f ON f.id = d.forum\n JOIN {user} u ON u.id = p.userid\n WHERE ({$wheresql})\n AND p.userid = :userid\n AND f.anonymous = 0 "; $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; }