Commit | Line | Data |
---|---|---|
cd4e6b17 | 1 | <?php |
f9a0ea69 | 2 | |
8f685009 SH |
3 | // This file is part of Moodle - http://moodle.org/ |
4 | // | |
5 | // Moodle is free software: you can redistribute it and/or modify | |
6 | // it under the terms of the GNU General Public License as published by | |
7 | // the Free Software Foundation, either version 3 of the License, or | |
8 | // (at your option) any later version. | |
9 | // | |
10 | // Moodle is distributed in the hope that it will be useful, | |
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | // GNU General Public License for more details. | |
14 | // | |
15 | // You should have received a copy of the GNU General Public License | |
16 | // along with Moodle. If not, see <http://www.gnu.org/licenses/>. | |
17 | ||
18 | /** | |
19 | * Display user activity reports for a course | |
20 | * | |
21 | * @package mod-forum | |
22 | * @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com} | |
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | |
24 | */ | |
f9a0ea69 | 25 | |
4b715423 SH |
26 | require_once(dirname(dirname(dirname(__FILE__))).'/config.php'); |
27 | require_once($CFG->dirroot.'/mod/forum/lib.php'); | |
28 | require_once($CFG->dirroot.'/rating/lib.php'); | |
29 | ||
30 | $courseid = optional_param('course', null, PARAM_INT); // Limit the posts to just this course | |
31 | $userid = optional_param('id', $USER->id, PARAM_INT); // User id whose posts we want to view | |
32 | $mode = optional_param('mode', 'posts', PARAM_ALPHA); // The mode to use. Either posts or discussions | |
33 | $page = optional_param('page', 0, PARAM_INT); // The page number to display | |
34 | $perpage = optional_param('perpage', 5, PARAM_INT); // The number of posts to display per page | |
35 | ||
36 | if (empty($userid)) { | |
37 | if (!isloggedin()) { | |
38 | require_login(); | |
39 | } | |
40 | $userid = $USER->id; | |
cd4e6b17 | 41 | } |
4b715423 SH |
42 | |
43 | $discussionsonly = ($mode !== 'posts'); | |
44 | $isspecificcourse = !is_null($courseid); | |
45 | $iscurrentuser = ($USER->id == $userid); | |
46 | ||
47 | $url = new moodle_url('/mod/forum/user.php', array('id' => $userid)); | |
48 | if ($isspecificcourse) $url->param('course', $courseid); | |
49 | if ($discussionsonly) $url->param('mode', 'discussions'); | |
50 | ||
cd4e6b17 | 51 | $PAGE->set_url($url); |
241ce9c4 | 52 | $PAGE->set_pagelayout('standard'); |
cd4e6b17 | 53 | |
4b715423 SH |
54 | if ($page != 0) $url->param('page', $page); |
55 | if ($perpage != 5) $url->param('perpage', $perpage); | |
bb8f3759 | 56 | |
4b715423 | 57 | add_to_log(($isspecificcourse)?$courseid:SITEID, "forum", "user report", 'user.php?'.$url->get_query_string(), $userid); |
bb8f3759 | 58 | |
4b715423 SH |
59 | $user = $DB->get_record("user", array("id" => $userid), '*', MUST_EXIST); |
60 | $usercontext = get_context_instance(CONTEXT_USER, $user->id, MUST_EXIST); | |
61 | // Check if the requested user is the guest user | |
62 | if (isguestuser($user)) { | |
63 | // The guest user cannot post, so it is not possible to view any posts. | |
64 | // May as well just bail aggressively here. | |
65 | print_error('invaliduserid'); | |
bb8f3759 | 66 | } |
4b715423 | 67 | // Make sure the user has not been deleted |
bb8f3759 | 68 | if ($user->deleted) { |
4b715423 SH |
69 | $PAGE->set_title(get_string('userdeleted')); |
70 | $PAGE->set_context(get_system_context()); | |
15ca5e5e | 71 | echo $OUTPUT->header(); |
4b715423 | 72 | echo $OUTPUT->heading($PAGE->title); |
396fb912 | 73 | echo $OUTPUT->footer(); |
bb8f3759 | 74 | die; |
75 | } | |
f9a0ea69 | 76 | |
4b715423 SH |
77 | $isloggedin = isloggedin(); |
78 | $isguestuser = $isloggedin && isguestuser(); | |
79 | $isparent = !$iscurrentuser && $DB->record_exists('role_assignments', array('userid'=>$USER->id, 'contextid'=>$usercontext->id)); | |
80 | $hasparentaccess = $isparent && has_all_capabilities(array('moodle/user:viewdetails', 'moodle/user:readuserposts'), $usercontext); | |
81 | ||
82 | // Check whether a specific course has been requested | |
83 | if ($isspecificcourse) { | |
84 | // Get the requested course and its context | |
85 | $course = $DB->get_record('course', array('id' => $courseid), '*', MUST_EXIST); | |
86 | $coursecontext = get_context_instance(CONTEXT_COURSE, $courseid, MUST_EXIST); | |
87 | // We have a specific course to search, which we will also assume we are within. | |
88 | if ($hasparentaccess) { | |
89 | // A `parent` role won't likely have access to the course so we won't attempt | |
90 | // to enter it. We will however still make them jump through the normal | |
91 | // login hoops | |
92 | require_login(); | |
93 | $PAGE->set_context($coursecontext); | |
94 | $PAGE->set_course($course); | |
95 | } else { | |
96 | // Enter the course we are searching | |
97 | require_login($course); | |
67875aa1 | 98 | } |
4b715423 SH |
99 | // Get the course ready for access checks |
100 | $courses = array($courseid => $course); | |
bb8f3759 | 101 | } else { |
4b715423 SH |
102 | // We are going to search for all of the users posts in all courses! |
103 | // a general require login here as we arn't actually within any course. | |
104 | require_login(); | |
105 | $PAGE->set_context(get_system_context()); | |
99fa9889 | 106 | |
4b715423 SH |
107 | // Now we need to get all of the courses to search. |
108 | // All courses where the user has posted within a forum will be returned. | |
109 | $courses = forum_get_courses_user_posted_in($user, $discussionsonly); | |
110 | } | |
65bcf17b | 111 | |
4b715423 SH |
112 | // Get the posts by the requested user that the current user can access. |
113 | $result = forum_get_posts_by_user($user, $courses, $isspecificcourse, $discussionsonly, ($page * $perpage), $perpage); | |
114 | ||
115 | // Check whether there are not posts to display. | |
116 | if (empty($result->posts)) { | |
117 | // Ok no posts to display means that either the user has not posted or there | |
118 | // are no posts made by the requested user that the current user is able to | |
119 | // see. | |
120 | // In either case we need to decide whether we can show personal information | |
121 | // about the requested user to the current user so we will execute some checks | |
122 | ||
123 | // First check the obvious, its the current user, a specific course has been | |
124 | // provided (require_login has been called), or they have a course contact role. | |
125 | // True to any of those and the current user can see the details of the | |
126 | // requested user. | |
127 | $canviewuser = ($iscurrentuser || $isspecificcourse || empty($CFG->forceloginforprofiles) || has_coursecontact_role($userid)); | |
128 | // Next we'll check the caps, if the current user has the view details and a | |
129 | // specific course has been requested, or if they have the view all details | |
130 | $canviewuser = ($canviewuser || ($isspecificcourse && has_capability('moodle/user:viewdetails', $coursecontext) || has_capability('moodle/user:viewalldetails', $usercontext))); | |
131 | ||
132 | // If none of the above was true the next step is to check a shared relation | |
133 | // through some course | |
134 | if (!$canviewuser) { | |
135 | // Get all of the courses that the users have in common | |
136 | $sharedcourses = enrol_get_shared_courses($USER->id, $user->id, true); | |
137 | foreach ($sharedcourses as $sharedcourse) { | |
138 | // Check the view cap within the course context | |
139 | if (has_capability('moodle/user:viewdetails', get_context_instance(CONTEXT_COURSE, $sharedcourse->id))) { | |
140 | $canviewuser = true; | |
141 | break; | |
142 | } | |
143 | } | |
144 | unset($sharedcourses); | |
145 | } | |
2011a95b | 146 | |
4b715423 SH |
147 | // Prepare the page title |
148 | $pagetitle = get_string('noposts', 'mod_forum'); | |
99fa9889 | 149 | |
4b715423 SH |
150 | // Get the page heading |
151 | if ($isspecificcourse) { | |
152 | $pageheading = format_string($course->shortname, true, array('context' => $coursecontext)); | |
153 | } else { | |
154 | $pageheading = get_string('pluginname', 'mod_forum'); | |
155 | } | |
65bcf17b | 156 | |
4b715423 SH |
157 | // Next we need to set up the loading of the navigation and choose a message |
158 | // to display to the current user. | |
159 | if ($iscurrentuser) { | |
160 | // No need to extend the navigation it happens automatically for the | |
161 | // current user. | |
162 | if ($discussionsonly) { | |
163 | $notification = get_string('nodiscussionsstartedbyyou', 'forum'); | |
bb8f3759 | 164 | } else { |
4b715423 | 165 | $notification = get_string('nopostsmadebyyou', 'forum'); |
bb8f3759 | 166 | } |
4b715423 SH |
167 | } else if ($canviewuser) { |
168 | $PAGE->navigation->extend_for_user($user); | |
169 | $PAGE->navigation->set_userid_for_parent_checks($user->id); // see MDL-25805 for reasons and for full commit reference for reversal when fixed. | |
170 | $fullname = fullname($user); | |
171 | if ($discussionsonly) { | |
172 | $notification = get_string('nodiscussionsstartedby', 'forum', $fullname); | |
bb8f3759 | 173 | } else { |
4b715423 | 174 | $notification = get_string('nopostsmadebyuser', 'forum', $fullname); |
bb8f3759 | 175 | } |
4b715423 SH |
176 | } else { |
177 | // Don't extend the navigation it would be giving out information that | |
178 | // the current uesr doesn't have access to. | |
179 | $notification = get_string('cannotviewusersposts', 'forum'); | |
180 | if ($isspecificcourse) { | |
181 | $url = new moodle_url('/course/view.php', array('id' => $courseid)); | |
182 | } else { | |
183 | $url = new moodle_url('/'); | |
184 | } | |
185 | navigation_node::override_active_url($url); | |
186 | } | |
65bcf17b | 187 | |
4b715423 SH |
188 | // Display a page letting the user know that there's nothing to display; |
189 | $PAGE->set_title($pagetitle); | |
190 | $PAGE->set_heading($pageheading); | |
191 | echo $OUTPUT->header(); | |
192 | echo $OUTPUT->heading($pagetitle); | |
193 | echo $OUTPUT->notification($notification); | |
194 | echo $OUTPUT->continue_button($url); | |
195 | echo $OUTPUT->footer(); | |
196 | die; | |
197 | } | |
198 | ||
199 | // Post output will contain an entry containing HTML to display each post by the | |
200 | // time we are done. | |
201 | $postoutput = array(); | |
99fa9889 | 202 | |
4b715423 SH |
203 | $discussions = array(); |
204 | foreach ($result->posts as $post) { | |
205 | $discussions[] = $post->discussion; | |
206 | } | |
207 | $discussions = $DB->get_records_list('forum_discussions', 'id', array_unique($discussions)); | |
208 | ||
209 | //todo Rather than retrieving the ratings for each post individually it would be nice to do them in groups | |
210 | //however this requires creating arrays of posts with each array containing all of the posts from a particular forum, | |
211 | //retrieving the ratings then reassembling them all back into a single array sorted by post.modified (descending) | |
212 | $rm = new rating_manager(); | |
213 | $ratingoptions = new stdClass; | |
214 | $ratingoptions->component = 'mod_forum'; | |
215 | $ratingoptions->ratingarea = 'post'; | |
216 | foreach ($result->posts as $post) { | |
217 | if (!isset($result->forums[$post->forum]) || !isset($discussions[$post->discussion])) { | |
218 | // Something very VERY dodgy has happened if we end up here | |
219 | continue; | |
220 | } | |
221 | $forum = $result->forums[$post->forum]; | |
222 | $cm = $forum->cm; | |
223 | $discussion = $discussions[$post->discussion]; | |
224 | $course = $result->courses[$discussion->course]; | |
225 | ||
226 | $forumurl = new moodle_url('/mod/forum/view.php', array('id' => $cm->id)); | |
227 | $discussionurl = new moodle_url('/mod/forum/discuss.php', array('d' => $post->discussion)); | |
228 | ||
229 | // load ratings | |
230 | if ($forum->assessed != RATING_AGGREGATE_NONE) { | |
231 | $ratingoptions->context = $cm->context; | |
232 | $ratingoptions->items = array($post); | |
233 | $ratingoptions->aggregate = $forum->assessed;//the aggregation method | |
234 | $ratingoptions->scaleid = $forum->scale; | |
235 | $ratingoptions->userid = $user->id; | |
236 | $ratingoptions->assesstimestart = $forum->assesstimestart; | |
237 | $ratingoptions->assesstimefinish = $forum->assesstimefinish; | |
238 | if ($forum->type == 'single' or !$post->discussion) { | |
239 | $ratingoptions->returnurl = $forumurl; | |
240 | } else { | |
241 | $ratingoptions->returnurl = $discussionurl; | |
bb8f3759 | 242 | } |
2011a95b | 243 | |
4b715423 SH |
244 | $updatedpost = $rm->get_ratings($ratingoptions); |
245 | //updating the array this way because we're iterating over a collection and updating them one by one | |
246 | $result->posts[$updatedpost[0]->id] = $updatedpost[0]; | |
247 | } | |
248 | ||
249 | $courseshortname = format_string($course->shortname, true, array('context' => get_context_instance(CONTEXT_COURSE, $course->id))); | |
250 | $forumname = format_string($forum->name, true, array('context' => $cm->context)); | |
251 | ||
252 | $fullsubjects = array(); | |
253 | if (!$isspecificcourse && !$hasparentaccess) { | |
254 | $fullsubjects[] = html_writer::link(new moodle_url('/course/view.php', array('id' => $course->id)), $courseshortname); | |
255 | $fullsubjects[] = html_writer::link($forumurl, $forumname); | |
256 | } else { | |
257 | $fullsubjects[] = html_writer::tag('span', $courseshortname); | |
258 | $fullsubjects[] = html_writer::tag('span', $forumname); | |
259 | } | |
260 | if ($forum->type != 'single') { | |
261 | $discussionname = format_string($discussion->name, true, array('context' => $cm->context)); | |
262 | if (!$isspecificcourse && !$hasparentaccess) { | |
263 | $fullsubjects[] .= html_writer::link($discussionurl, $discussionname); | |
264 | } else { | |
265 | $fullsubjects[] .= html_writer::tag('span', $discussionname); | |
bb8f3759 | 266 | } |
4b715423 SH |
267 | if ($post->parent != 0) { |
268 | $postname = format_string($post->subject, true, array('context' => $cm->context)); | |
269 | if (!$isspecificcourse && !$hasparentaccess) { | |
270 | $fullsubjects[] .= html_writer::link(new moodle_url('/mod/forum/discuss.php', array('d' => $post->discussion, 'parent' => $post->id)), $postname); | |
271 | } else { | |
272 | $fullsubjects[] .= html_writer::tag('span', $postname); | |
f9a0ea69 | 273 | } |
bb8f3759 | 274 | } |
bb8f3759 | 275 | } |
4b715423 SH |
276 | $post->subject = join(' -> ', $fullsubjects); |
277 | // This is really important, if the strings are formatted again all the links | |
278 | // we've added will be lost. | |
279 | $post->subjectnoformat = true; | |
280 | $discussionurl->set_anchor('p'.$post->id); | |
281 | $fulllink = html_writer::link($discussionurl, get_string("postincontext", "forum")); | |
282 | ||
283 | $postoutput[] = forum_print_post($post, $discussion, $forum, $cm, $course, false, false, false, $fulllink, '', null, true, null, true); | |
284 | } | |
2011a95b | 285 | |
4b715423 SH |
286 | $userfullname = fullname($user); |
287 | ||
288 | if ($discussionsonly) { | |
289 | $inpageheading = get_string('discussionsstartedby', 'mod_forum', $userfullname); | |
bb8f3759 | 290 | } else { |
4b715423 SH |
291 | $inpageheading = get_string('postsmadebyuser', 'mod_forum', $userfullname); |
292 | } | |
293 | if ($isspecificcourse) { | |
294 | $a = new stdClass; | |
295 | $a->fullname = $userfullname; | |
296 | $a->coursename = format_string($course->shortname, true, array('context' => $coursecontext)); | |
297 | $pageheading = $a->coursename; | |
298 | if ($discussionsonly) { | |
299 | $pagetitle = get_string('discussionsstartedbyuserincourse', 'mod_forum', $a); | |
f9a0ea69 | 300 | } else { |
4b715423 | 301 | $pagetitle = get_string('postsmadebyuserincourse', 'mod_forum', $a); |
f9a0ea69 | 302 | } |
4b715423 SH |
303 | } else { |
304 | $pagetitle = $inpageheading; | |
305 | $pageheading = $userfullname; | |
bb8f3759 | 306 | } |
f9a0ea69 | 307 | |
4b715423 SH |
308 | $PAGE->set_title($pagetitle); |
309 | $PAGE->set_heading($pagetitle); | |
310 | $PAGE->navigation->extend_for_user($user); | |
311 | $PAGE->navigation->set_userid_for_parent_checks($user->id); // see MDL-25805 for reasons and for full commit reference for reversal when fixed. | |
312 | ||
313 | echo $OUTPUT->header(); | |
314 | echo $OUTPUT->heading($inpageheading); | |
315 | echo html_writer::start_tag('div', array('class' => 'user-content')); | |
316 | ||
317 | if (!empty($postoutput)) { | |
318 | echo $OUTPUT->paging_bar($result->totalcount, $page, $perpage, $url); | |
319 | foreach ($postoutput as $post) { | |
320 | echo $post; | |
321 | echo html_writer::empty_tag('br'); | |
322 | } | |
323 | echo $OUTPUT->paging_bar($result->totalcount, $page, $perpage, $url); | |
324 | } else if ($discussionsonly) { | |
325 | echo $OUTPUT->heading(get_string('nodiscussionsstartedby', 'forum', $userfullname)); | |
326 | } else { | |
327 | echo $OUTPUT->heading(get_string('noposts', 'forum')); | |
328 | } | |
329 | ||
330 | echo html_writer::end_tag('div'); | |
331 | echo $OUTPUT->footer(); |