Commit | Line | Data |
---|---|---|
cae83708 | 1 | <?php |
cae83708 | 2 | // This file is part of Moodle - http://moodle.org/ |
3 | // | |
4 | // Moodle is free software: you can redistribute it and/or modify | |
5 | // it under the terms of the GNU General Public License as published by | |
6 | // the Free Software Foundation, either version 3 of the License, or | |
7 | // (at your option) any later version. | |
8 | // | |
9 | // Moodle is distributed in the hope that it will be useful, | |
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | // GNU General Public License for more details. | |
13 | // | |
14 | // You should have received a copy of the GNU General Public License | |
15 | // along with Moodle. If not, see <http://www.gnu.org/licenses/>. | |
16 | ||
cae83708 | 17 | /** |
18 | * Core global functions for Blog. | |
19 | * | |
20 | * @package moodlecore | |
21 | * @subpackage blog | |
22 | * @copyright 2009 Nicolas Connault | |
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | |
24 | */ | |
25 | ||
35716b86 PS |
26 | defined('MOODLE_INTERNAL') || die(); |
27 | ||
2b6e53e8 | 28 | /* |
cae83708 | 29 | * Library of functions and constants for blog |
30 | */ | |
31 | require_once($CFG->dirroot .'/blog/rsslib.php'); | |
cae83708 | 32 | |
cae83708 | 33 | /** |
34 | * User can edit a blog entry if this is their own blog entry and they have | |
35 | * the capability moodle/blog:create, or if they have the capability | |
36 | * moodle/blog:manageentries. | |
37 | * | |
38 | * This also applies to deleting of entries. | |
39 | */ | |
1c7b8b93 NC |
40 | function blog_user_can_edit_entry($blogentry) { |
41 | global $USER; | |
6524adcf | 42 | |
41b38360 | 43 | $sitecontext = context_system::instance(); |
4a173181 | 44 | |
cae83708 | 45 | if (has_capability('moodle/blog:manageentries', $sitecontext)) { |
2b6e53e8 | 46 | return true; // Can edit any blog entry. |
cae83708 | 47 | } |
c2ee4e87 | 48 | |
1c7b8b93 | 49 | if ($blogentry->userid == $USER->id && has_capability('moodle/blog:create', $sitecontext)) { |
2b6e53e8 | 50 | return true; // Can edit own when having blog:create capability. |
cae83708 | 51 | } |
4a173181 | 52 | |
cae83708 | 53 | return false; |
54 | } | |
d02240f3 | 55 | |
3bfcfdca | 56 | |
cae83708 | 57 | /** |
58 | * Checks to see if a user can view the blogs of another user. | |
59 | * Only blog level is checked here, the capabilities are enforced | |
60 | * in blog/index.php | |
61 | */ | |
1c7b8b93 | 62 | function blog_user_can_view_user_entry($targetuserid, $blogentry=null) { |
cae83708 | 63 | global $CFG, $USER, $DB; |
c2ee4e87 | 64 | |
850d2db8 | 65 | if (empty($CFG->enableblogs)) { |
89f5e430 | 66 | return false; // Blog system disabled. |
cae83708 | 67 | } |
68 | ||
2c27b6ae | 69 | if (isloggedin() && $USER->id == $targetuserid) { |
89f5e430 | 70 | return true; // Can view own entries in any case. |
cae83708 | 71 | } |
72 | ||
41b38360 | 73 | $sitecontext = context_system::instance(); |
cae83708 | 74 | if (has_capability('moodle/blog:manageentries', $sitecontext)) { |
89f5e430 | 75 | return true; // Can manage all entries. |
cae83708 | 76 | } |
c2ee4e87 | 77 | |
89f5e430 | 78 | // If blog is in draft state, then make sure user have proper capability. |
1c7b8b93 | 79 | if ($blogentry && $blogentry->publishstate == 'draft' && !has_capability('moodle/blog:viewdrafts', $sitecontext)) { |
89f5e430 | 80 | return false; // Can not view draft of others. |
cae83708 | 81 | } |
82 | ||
9a909b1a | 83 | // If blog entry is not public, make sure user is logged in. |
1c7b8b93 | 84 | if ($blogentry && $blogentry->publishstate != 'public' && !isloggedin()) { |
cae83708 | 85 | return false; |
86 | } | |
d02240f3 | 87 | |
89f5e430 | 88 | // If blogentry is not passed or all above checks pass, then check capability based on system config. |
cae83708 | 89 | switch ($CFG->bloglevel) { |
90 | case BLOG_GLOBAL_LEVEL: | |
91 | return true; | |
92 | break; | |
c2ee4e87 | 93 | |
cae83708 | 94 | case BLOG_SITE_LEVEL: |
89f5e430 | 95 | if (isloggedin()) { // Not logged in viewers forbidden. |
cae83708 | 96 | return true; |
c2ee4e87 | 97 | } |
cae83708 | 98 | return false; |
99 | break; | |
d02240f3 | 100 | |
cae83708 | 101 | case BLOG_USER_LEVEL: |
102 | default: | |
89f5e430 | 103 | // If user is viewing other user blog, then user should have user:readuserblogs capability. |
41b38360 | 104 | $personalcontext = context_user::instance($targetuserid); |
cae83708 | 105 | return has_capability('moodle/user:readuserblogs', $personalcontext); |
106 | break; | |
4a173181 | 107 | |
cae83708 | 108 | } |
109 | } | |
110 | ||
111 | /** | |
112 | * remove all associations for the blog entries of a particular user | |
113 | * @param int userid - id of user whose blog associations will be deleted | |
114 | */ | |
115 | function blog_remove_associations_for_user($userid) { | |
1c7b8b93 | 116 | global $DB; |
d91181dc PS |
117 | throw new coding_exception('function blog_remove_associations_for_user() is not finished'); |
118 | /* | |
1c7b8b93 NC |
119 | $blogentries = blog_fetch_entries(array('user' => $userid), 'lasmodified DESC'); |
120 | foreach ($blogentries as $entry) { | |
121 | if (blog_user_can_edit_entry($entry)) { | |
122 | blog_remove_associations_for_entry($entry->id); | |
123 | } | |
b0e90a0c | 124 | } |
d91181dc | 125 | */ |
cae83708 | 126 | } |
127 | ||
128 | /** | |
1c7b8b93 NC |
129 | * remove all associations for the blog entries of a particular course |
130 | * @param int courseid - id of user whose blog associations will be deleted | |
cae83708 | 131 | */ |
1c7b8b93 NC |
132 | function blog_remove_associations_for_course($courseid) { |
133 | global $DB; | |
41b38360 | 134 | $context = context_course::instance($courseid); |
1c7b8b93 | 135 | $DB->delete_records('blog_association', array('contextid' => $context->id)); |
cae83708 | 136 | } |
137 | ||
c69a43f2 MG |
138 | /** |
139 | * Remove module associated blogs and blog tag instances. | |
140 | * | |
141 | * @param int $modcontextid Module context ID. | |
142 | */ | |
143 | function blog_remove_associations_for_module($modcontextid) { | |
144 | global $DB; | |
145 | ||
146 | if (!empty($assocblogids = $DB->get_fieldset_select('blog_association', 'blogid', | |
147 | 'contextid = :contextid', ['contextid' => $modcontextid]))) { | |
148 | list($sql, $params) = $DB->get_in_or_equal($assocblogids, SQL_PARAMS_NAMED); | |
149 | ||
150 | $DB->delete_records_select('tag_instance', "itemid $sql", $params); | |
151 | $DB->delete_records_select('post', "id $sql AND module = :module", | |
152 | array_merge($params, ['module' => 'blog'])); | |
153 | $DB->delete_records('blog_association', ['contextid' => $modcontextid]); | |
154 | } | |
155 | } | |
156 | ||
cae83708 | 157 | /** |
158 | * Given a record in the {blog_external} table, checks the blog's URL | |
b7c1da93 | 159 | * for new entries not yet copied into Moodle. |
50ff50da | 160 | * Also attempts to identify and remove deleted blog entries |
cae83708 | 161 | * |
1c7b8b93 NC |
162 | * @param object $externalblog |
163 | * @return boolean False if the Feed is invalid | |
cae83708 | 164 | */ |
1c7b8b93 | 165 | function blog_sync_external_entries($externalblog) { |
cae83708 | 166 | global $CFG, $DB; |
e14de6f9 | 167 | require_once($CFG->libdir . '/simplepie/moodle_simplepie.php'); |
4a173181 | 168 | |
d958e6bd PS |
169 | $rss = new moodle_simplepie(); |
170 | $rssfile = $rss->registry->create('File', array($externalblog->url)); | |
171 | $filetest = $rss->registry->create('Locator', array($rssfile)); | |
1c7b8b93 NC |
172 | |
173 | if (!$filetest->is_feed($rssfile)) { | |
174 | $externalblog->failedlastsync = 1; | |
175 | $DB->update_record('blog_external', $externalblog); | |
176 | return false; | |
8397492b | 177 | } else if (!empty($externalblog->failedlastsync)) { |
1c7b8b93 NC |
178 | $externalblog->failedlastsync = 0; |
179 | $DB->update_record('blog_external', $externalblog); | |
c2ee4e87 | 180 | } |
4a173181 | 181 | |
d958e6bd PS |
182 | $rss->set_feed_url($externalblog->url); |
183 | $rss->init(); | |
c2ee4e87 | 184 | |
e14de6f9 | 185 | if (empty($rss->data)) { |
cae83708 | 186 | return null; |
187 | } | |
2b6e53e8 | 188 | // Used to identify blog posts that have been deleted from the source feed. |
cc52e53d | 189 | $oldesttimestamp = null; |
50ff50da | 190 | $uniquehashes = array(); |
b13ee30e | 191 | |
e14de6f9 | 192 | foreach ($rss->get_items() as $entry) { |
2b6e53e8 | 193 | // If filtertags are defined, use them to filter the entries by RSS category. |
1c7b8b93 NC |
194 | if (!empty($externalblog->filtertags)) { |
195 | $containsfiltertag = false; | |
196 | $categories = $entry->get_categories(); | |
197 | $filtertags = explode(',', $externalblog->filtertags); | |
198 | $filtertags = array_map('trim', $filtertags); | |
199 | $filtertags = array_map('strtolower', $filtertags); | |
200 | ||
153b3ad0 SL |
201 | if (!empty($categories)) { |
202 | foreach ($categories as $category) { | |
203 | if (in_array(trim(strtolower($category->term)), $filtertags)) { | |
204 | $containsfiltertag = true; | |
205 | } | |
1c7b8b93 NC |
206 | } |
207 | } | |
208 | ||
209 | if (!$containsfiltertag) { | |
210 | continue; | |
c2ee4e87 | 211 | } |
212 | } | |
c484c852 | 213 | |
50ff50da | 214 | $uniquehashes[] = $entry->get_permalink(); |
1c7b8b93 | 215 | |
e463f508 | 216 | $newentry = new stdClass(); |
1c7b8b93 NC |
217 | $newentry->userid = $externalblog->userid; |
218 | $newentry->module = 'blog_external'; | |
219 | $newentry->content = $externalblog->id; | |
220 | $newentry->uniquehash = $entry->get_permalink(); | |
221 | $newentry->publishstate = 'site'; | |
222 | $newentry->format = FORMAT_HTML; | |
2b6e53e8 | 223 | // Clean subject of html, just in case. |
a537e507 | 224 | $newentry->subject = clean_param($entry->get_title(), PARAM_TEXT); |
2b6e53e8 AD |
225 | // Observe 128 max chars in DB. |
226 | // TODO: +1 to raise this to 255. | |
2f1e464a PS |
227 | if (core_text::strlen($newentry->subject) > 128) { |
228 | $newentry->subject = core_text::substr($newentry->subject, 0, 125) . '...'; | |
a537e507 | 229 | } |
1c7b8b93 | 230 | $newentry->summary = $entry->get_description(); |
c484c852 | 231 | |
2b6e53e8 AD |
232 | // Used to decide whether to insert or update. |
233 | // Uses enty permalink plus creation date if available. | |
bb8a75e7 | 234 | $existingpostconditions = array('uniquehash' => $entry->get_permalink()); |
99cd408f | 235 | |
2b6e53e8 | 236 | // Our DB doesnt allow null creation or modified timestamps so check the external blog supplied one. |
99cd408f | 237 | $entrydate = $entry->get_date('U'); |
afce96f0 | 238 | if (!empty($entrydate)) { |
239 | $existingpostconditions['created'] = $entrydate; | |
240 | } | |
c484c852 | 241 | |
2b6e53e8 | 242 | // The post ID or false if post not found in DB. |
afce96f0 | 243 | $postid = $DB->get_field('post', 'id', $existingpostconditions); |
c484c852 | 244 | |
afce96f0 | 245 | $timestamp = null; |
99cd408f | 246 | if (empty($entrydate)) { |
afce96f0 | 247 | $timestamp = time(); |
99cd408f | 248 | } else { |
afce96f0 | 249 | $timestamp = $entrydate; |
99cd408f | 250 | } |
c484c852 | 251 | |
2b6e53e8 | 252 | // Only set created if its a new post so we retain the original creation timestamp if the post is edited. |
bb8a75e7 | 253 | if ($postid === false) { |
afce96f0 | 254 | $newentry->created = $timestamp; |
255 | } | |
256 | $newentry->lastmodified = $timestamp; | |
694fb770 | 257 | |
bb8a75e7 | 258 | if (empty($oldesttimestamp) || $timestamp < $oldesttimestamp) { |
2b6e53e8 | 259 | // Found an older post. |
cc52e53d | 260 | $oldesttimestamp = $timestamp; |
261 | } | |
1c7b8b93 | 262 | |
2f1e464a | 263 | if (core_text::strlen($newentry->uniquehash) > 255) { |
3b59524d SH |
264 | // The URL for this item is too long for the field. Rather than add |
265 | // the entry without the link we will skip straight over it. | |
266 | // RSS spec says recommended length 500, we use 255. | |
267 | debugging('External blog entry skipped because of oversized URL', DEBUG_DEVELOPER); | |
268 | continue; | |
269 | } | |
270 | ||
bb8a75e7 | 271 | if ($postid === false) { |
9829e3d8 | 272 | $id = $DB->insert_record('post', $newentry); |
1c7b8b93 | 273 | |
2b6e53e8 | 274 | // Set tags. |
abea2c5d MG |
275 | if ($tags = core_tag_tag::get_item_tags_array('core', 'blog_external', $externalblog->id)) { |
276 | core_tag_tag::set_item_tags('core', 'post', $id, context_user::instance($externalblog->userid), $tags); | |
9829e3d8 | 277 | } |
278 | } else { | |
279 | $newentry->id = $postid; | |
afce96f0 | 280 | $DB->update_record('post', $newentry); |
1c7b8b93 | 281 | } |
cae83708 | 282 | } |
c484c852 | 283 | |
ed79b89b DM |
284 | // Look at the posts we have in the database to check if any of them have been deleted from the feed. |
285 | // Only checking posts within the time frame returned by the rss feed. Older items may have been deleted or | |
286 | // may just not be returned anymore. We can't tell the difference so we leave older posts alone. | |
287 | $sql = "SELECT id, uniquehash | |
288 | FROM {post} | |
289 | WHERE module = 'blog_external' | |
290 | AND " . $DB->sql_compare_text('content') . " = " . $DB->sql_compare_text(':blogid') . " | |
291 | AND created > :ts"; | |
42291c61 AD |
292 | $dbposts = $DB->get_records_sql($sql, array('blogid' => $externalblog->id, 'ts' => $oldesttimestamp)); |
293 | ||
50ff50da | 294 | $todelete = array(); |
2b6e53e8 | 295 | foreach ($dbposts as $dbpost) { |
29487578 | 296 | if ( !in_array($dbpost->uniquehash, $uniquehashes) ) { |
50ff50da | 297 | $todelete[] = $dbpost->id; |
298 | } | |
299 | } | |
300 | $DB->delete_records_list('post', 'id', $todelete); | |
c2ee4e87 | 301 | |
e5137f24 | 302 | $DB->update_record('blog_external', array('id' => $externalblog->id, 'timefetched' => time())); |
1c7b8b93 NC |
303 | } |
304 | ||
305 | /** | |
306 | * Given an external blog object, deletes all related blog entries from the post table. | |
307 | * NOTE: The external blog's id is saved as post.content, a field that is not oterhwise used by blog entries. | |
308 | * @param object $externablog | |
309 | */ | |
310 | function blog_delete_external_entries($externalblog) { | |
311 | global $DB; | |
41b38360 | 312 | require_capability('moodle/blog:manageexternal', context_system::instance()); |
a742eb1f EL |
313 | $DB->delete_records_select('post', |
314 | "module='blog_external' AND " . $DB->sql_compare_text('content') . " = ?", | |
315 | array($externalblog->id)); | |
cae83708 | 316 | } |
d02240f3 | 317 | |
27bad0a6 | 318 | /** |
593270c6 | 319 | * This function checks that blogs are enabled, and that the user can see blogs at all |
27bad0a6 SH |
320 | * @return bool |
321 | */ | |
322 | function blog_is_enabled_for_user() { | |
323 | global $CFG; | |
850d2db8 | 324 | return (!empty($CFG->enableblogs) && (isloggedin() || ($CFG->bloglevel == BLOG_GLOBAL_LEVEL))); |
27bad0a6 SH |
325 | } |
326 | ||
327 | /** | |
328 | * This function gets all of the options available for the current user in respect | |
329 | * to blogs. | |
897aa80c | 330 | * |
27bad0a6 SH |
331 | * It loads the following if applicable: |
332 | * - Module options {@see blog_get_options_for_module} | |
333 | * - Course options {@see blog_get_options_for_course} | |
334 | * - User specific options {@see blog_get_options_for_user} | |
335 | * - General options (BLOG_LEVEL_GLOBAL) | |
336 | * | |
337 | * @param moodle_page $page The page to load for (normally $PAGE) | |
338 | * @param stdClass $userid Load for a specific user | |
339 | * @return array An array of options organised by type. | |
340 | */ | |
341 | function blog_get_all_options(moodle_page $page, stdClass $userid = null) { | |
342 | global $CFG, $DB, $USER; | |
343 | ||
344 | $options = array(); | |
345 | ||
2b6e53e8 | 346 | // If blogs are enabled and the user is logged in and not a guest. |
27bad0a6 | 347 | if (blog_is_enabled_for_user()) { |
2b6e53e8 | 348 | // If the context is the user then assume we want to load for the users context. |
27bad0a6 SH |
349 | if (is_null($userid) && $page->context->contextlevel == CONTEXT_USER) { |
350 | $userid = $page->context->instanceid; | |
351 | } | |
2b6e53e8 | 352 | // Check the userid var. |
0e32a565 | 353 | if (!is_null($userid) && $userid !== $USER->id) { |
27bad0a6 | 354 | // Load the user from the userid... it MUST EXIST throw a wobbly if it doesn't! |
0e32a565 | 355 | $user = $DB->get_record('user', array('id' => $userid), '*', MUST_EXIST); |
27bad0a6 SH |
356 | } else { |
357 | $user = null; | |
358 | } | |
359 | ||
360 | if ($CFG->useblogassociations && $page->cm !== null) { | |
2b6e53e8 | 361 | // Load for the module associated with the page. |
27bad0a6 SH |
362 | $options[CONTEXT_MODULE] = blog_get_options_for_module($page->cm, $user); |
363 | } else if ($CFG->useblogassociations && $page->course->id != SITEID) { | |
2b6e53e8 | 364 | // Load the options for the course associated with the page. |
27bad0a6 SH |
365 | $options[CONTEXT_COURSE] = blog_get_options_for_course($page->course, $user); |
366 | } | |
367 | ||
2b6e53e8 | 368 | // Get the options for the user. |
5b183f51 | 369 | if ($user !== null and !isguestuser($user)) { |
2b6e53e8 | 370 | // Load for the requested user. |
0e32a565 | 371 | $options[CONTEXT_USER + 1] = blog_get_options_for_user($user); |
27bad0a6 | 372 | } |
2b6e53e8 | 373 | // Load for the current user. |
5b183f51 PS |
374 | if (isloggedin() and !isguestuser()) { |
375 | $options[CONTEXT_USER] = blog_get_options_for_user(); | |
376 | } | |
27bad0a6 SH |
377 | } |
378 | ||
2b6e53e8 AD |
379 | // If blog level is global then display a link to view all site entries. |
380 | if (!empty($CFG->enableblogs) | |
381 | && $CFG->bloglevel >= BLOG_GLOBAL_LEVEL | |
382 | && has_capability('moodle/blog:view', context_system::instance())) { | |
383 | ||
27bad0a6 SH |
384 | $options[CONTEXT_SYSTEM] = array('viewsite' => array( |
385 | 'string' => get_string('viewsiteentries', 'blog'), | |
386 | 'link' => new moodle_url('/blog/index.php') | |
387 | )); | |
388 | } | |
389 | ||
2b6e53e8 | 390 | // Return the options. |
27bad0a6 SH |
391 | return $options; |
392 | } | |
393 | ||
394 | /** | |
395 | * Get all of the blog options that relate to the passed user. | |
396 | * | |
397 | * If no user is passed the current user is assumed. | |
398 | * | |
399 | * @staticvar array $useroptions Cache so we don't have to regenerate multiple times | |
400 | * @param stdClass $user | |
401 | * @return array The array of options for the requested user | |
402 | */ | |
403 | function blog_get_options_for_user(stdClass $user=null) { | |
404 | global $CFG, $USER; | |
2b6e53e8 | 405 | // Cache. |
27bad0a6 SH |
406 | static $useroptions = array(); |
407 | ||
408 | $options = array(); | |
2b6e53e8 | 409 | // Blogs must be enabled and the user must be logged in. |
27bad0a6 SH |
410 | if (!blog_is_enabled_for_user()) { |
411 | return $options; | |
412 | } | |
413 | ||
2b6e53e8 | 414 | // Sort out the user var. |
27bad0a6 SH |
415 | if ($user === null || $user->id == $USER->id) { |
416 | $user = $USER; | |
417 | $iscurrentuser = true; | |
418 | } else { | |
419 | $iscurrentuser = false; | |
420 | } | |
421 | ||
2b6e53e8 | 422 | // If we've already generated serve from the cache. |
27bad0a6 SH |
423 | if (array_key_exists($user->id, $useroptions)) { |
424 | return $useroptions[$user->id]; | |
425 | } | |
426 | ||
41b38360 | 427 | $sitecontext = context_system::instance(); |
27bad0a6 SH |
428 | $canview = has_capability('moodle/blog:view', $sitecontext); |
429 | ||
430 | if (!$iscurrentuser && $canview && ($CFG->bloglevel >= BLOG_SITE_LEVEL)) { | |
2b6e53e8 | 431 | // Not the current user, but we can view and its blogs are enabled for SITE or GLOBAL. |
27bad0a6 SH |
432 | $options['userentries'] = array( |
433 | 'string' => get_string('viewuserentries', 'blog', fullname($user)), | |
0e32a565 | 434 | 'link' => new moodle_url('/blog/index.php', array('userid' => $user->id)) |
27bad0a6 SH |
435 | ); |
436 | } else { | |
2b6e53e8 | 437 | // It's the current user. |
27bad0a6 | 438 | if ($canview) { |
2b6e53e8 | 439 | // We can view our own blogs .... BIG surprise. |
27bad0a6 | 440 | $options['view'] = array( |
4887d152 | 441 | 'string' => get_string('blogentries', 'blog'), |
0e32a565 | 442 | 'link' => new moodle_url('/blog/index.php', array('userid' => $USER->id)) |
27bad0a6 SH |
443 | ); |
444 | } | |
445 | if (has_capability('moodle/blog:create', $sitecontext)) { | |
2b6e53e8 | 446 | // We can add to our own blog. |
27bad0a6 SH |
447 | $options['add'] = array( |
448 | 'string' => get_string('addnewentry', 'blog'), | |
0e32a565 | 449 | 'link' => new moodle_url('/blog/edit.php', array('action' => 'add')) |
27bad0a6 SH |
450 | ); |
451 | } | |
452 | } | |
0f4c6067 | 453 | if ($canview && $CFG->enablerssfeeds) { |
c000545d JF |
454 | $options['rss'] = array( |
455 | 'string' => get_string('rssfeed', 'blog'), | |
456 | 'link' => new moodle_url(rss_get_url($sitecontext->id, $USER->id, 'blog', 'user/'.$user->id)) | |
2b6e53e8 | 457 | ); |
c000545d JF |
458 | } |
459 | ||
2b6e53e8 | 460 | // Cache the options. |
27bad0a6 | 461 | $useroptions[$user->id] = $options; |
2b6e53e8 | 462 | // Return the options. |
27bad0a6 SH |
463 | return $options; |
464 | } | |
465 | ||
466 | /** | |
467 | * Get the blog options that relate to the given course for the given user. | |
468 | * | |
469 | * @staticvar array $courseoptions A cache so we can save regenerating multiple times | |
470 | * @param stdClass $course The course to load options for | |
471 | * @param stdClass $user The user to load options for null == current user | |
472 | * @return array The array of options | |
473 | */ | |
474 | function blog_get_options_for_course(stdClass $course, stdClass $user=null) { | |
475 | global $CFG, $USER; | |
2b6e53e8 | 476 | // Cache. |
27bad0a6 | 477 | static $courseoptions = array(); |
897aa80c | 478 | |
27bad0a6 SH |
479 | $options = array(); |
480 | ||
2b6e53e8 | 481 | // User must be logged in and blogs must be enabled. |
27bad0a6 SH |
482 | if (!blog_is_enabled_for_user()) { |
483 | return $options; | |
484 | } | |
485 | ||
2b6e53e8 | 486 | // Check that the user can associate with the course. |
41b38360 | 487 | $sitecontext = context_system::instance(); |
2b6e53e8 | 488 | // Generate the cache key. |
27bad0a6 SH |
489 | $key = $course->id.':'; |
490 | if (!empty($user)) { | |
491 | $key .= $user->id; | |
492 | } else { | |
493 | $key .= $USER->id; | |
494 | } | |
2b6e53e8 | 495 | // Serve from the cache if we've already generated for this course. |
27bad0a6 | 496 | if (array_key_exists($key, $courseoptions)) { |
af8fe217 | 497 | return $courseoptions[$key]; |
27bad0a6 | 498 | } |
897aa80c | 499 | |
4ef08298 | 500 | if (has_capability('moodle/blog:view', $sitecontext)) { |
27bad0a6 SH |
501 | // We can view! |
502 | if ($CFG->bloglevel >= BLOG_SITE_LEVEL) { | |
2b6e53e8 | 503 | // View entries about this course. |
27bad0a6 SH |
504 | $options['courseview'] = array( |
505 | 'string' => get_string('viewcourseblogs', 'blog'), | |
4ef08298 | 506 | 'link' => new moodle_url('/blog/index.php', array('courseid' => $course->id)) |
27bad0a6 SH |
507 | ); |
508 | } | |
2b6e53e8 | 509 | // View MY entries about this course. |
27bad0a6 SH |
510 | $options['courseviewmine'] = array( |
511 | 'string' => get_string('viewmyentriesaboutcourse', 'blog'), | |
4ef08298 | 512 | 'link' => new moodle_url('/blog/index.php', array('courseid' => $course->id, 'userid' => $USER->id)) |
27bad0a6 SH |
513 | ); |
514 | if (!empty($user) && ($CFG->bloglevel >= BLOG_SITE_LEVEL)) { | |
2b6e53e8 | 515 | // View the provided users entries about this course. |
27bad0a6 SH |
516 | $options['courseviewuser'] = array( |
517 | 'string' => get_string('viewentriesbyuseraboutcourse', 'blog', fullname($user)), | |
4ef08298 | 518 | 'link' => new moodle_url('/blog/index.php', array('courseid' => $course->id, 'userid' => $user->id)) |
27bad0a6 SH |
519 | ); |
520 | } | |
521 | } | |
522 | ||
4ef08298 | 523 | if (has_capability('moodle/blog:create', $sitecontext)) { |
2b6e53e8 | 524 | // We can blog about this course. |
27bad0a6 | 525 | $options['courseadd'] = array( |
cfa11fd6 | 526 | 'string' => get_string('blogaboutthiscourse', 'blog'), |
4ef08298 | 527 | 'link' => new moodle_url('/blog/edit.php', array('action' => 'add', 'courseid' => $course->id)) |
27bad0a6 SH |
528 | ); |
529 | } | |
530 | ||
2b6e53e8 | 531 | // Cache the options for this course. |
27bad0a6 | 532 | $courseoptions[$key] = $options; |
2b6e53e8 | 533 | // Return the options. |
27bad0a6 SH |
534 | return $options; |
535 | } | |
536 | ||
537 | /** | |
538 | * Get the blog options relating to the given module for the given user | |
539 | * | |
540 | * @staticvar array $moduleoptions Cache | |
78f0f64d | 541 | * @param stdClass|cm_info $module The module to get options for |
27bad0a6 SH |
542 | * @param stdClass $user The user to get options for null == currentuser |
543 | * @return array | |
544 | */ | |
78f0f64d | 545 | function blog_get_options_for_module($module, $user=null) { |
27bad0a6 | 546 | global $CFG, $USER; |
2b6e53e8 | 547 | // Cache. |
27bad0a6 SH |
548 | static $moduleoptions = array(); |
549 | ||
550 | $options = array(); | |
2b6e53e8 | 551 | // User must be logged in, blogs must be enabled. |
27bad0a6 SH |
552 | if (!blog_is_enabled_for_user()) { |
553 | return $options; | |
554 | } | |
555 | ||
41b38360 | 556 | $sitecontext = context_system::instance(); |
27bad0a6 | 557 | |
2b6e53e8 | 558 | // Generate the cache key. |
27bad0a6 SH |
559 | $key = $module->id.':'; |
560 | if (!empty($user)) { | |
561 | $key .= $user->id; | |
562 | } else { | |
563 | $key .= $USER->id; | |
564 | } | |
565 | if (array_key_exists($key, $moduleoptions)) { | |
2b6e53e8 | 566 | // Serve from the cache so we don't have to regenerate. |
46a710e9 | 567 | return $moduleoptions[$key]; |
27bad0a6 SH |
568 | } |
569 | ||
4ef08298 | 570 | if (has_capability('moodle/blog:view', $sitecontext)) { |
dc9fa9cb RT |
571 | // Save correct module name for later usage. |
572 | $modulename = get_string('modulename', $module->modname); | |
4eaf120a | 573 | |
27bad0a6 SH |
574 | // We can view! |
575 | if ($CFG->bloglevel >= BLOG_SITE_LEVEL) { | |
2b6e53e8 | 576 | // View all entries about this module. |
27bad0a6 | 577 | $a = new stdClass; |
dc9fa9cb | 578 | $a->type = $modulename; |
27bad0a6 SH |
579 | $options['moduleview'] = array( |
580 | 'string' => get_string('viewallmodentries', 'blog', $a), | |
0e32a565 | 581 | 'link' => new moodle_url('/blog/index.php', array('modid' => $module->id)) |
27bad0a6 SH |
582 | ); |
583 | } | |
2b6e53e8 | 584 | // View MY entries about this module. |
27bad0a6 | 585 | $options['moduleviewmine'] = array( |
dc9fa9cb | 586 | 'string' => get_string('viewmyentriesaboutmodule', 'blog', $modulename), |
0e32a565 | 587 | 'link' => new moodle_url('/blog/index.php', array('modid' => $module->id, 'userid' => $USER->id)) |
27bad0a6 SH |
588 | ); |
589 | if (!empty($user) && ($CFG->bloglevel >= BLOG_SITE_LEVEL)) { | |
2b6e53e8 | 590 | // View the given users entries about this module. |
27bad0a6 | 591 | $a = new stdClass; |
dc9fa9cb | 592 | $a->mod = $modulename; |
27bad0a6 SH |
593 | $a->user = fullname($user); |
594 | $options['moduleviewuser'] = array( | |
595 | 'string' => get_string('blogentriesbyuseraboutmodule', 'blog', $a), | |
0e32a565 | 596 | 'link' => new moodle_url('/blog/index.php', array('modid' => $module->id, 'userid' => $user->id)) |
27bad0a6 SH |
597 | ); |
598 | } | |
599 | } | |
600 | ||
4ef08298 | 601 | if (has_capability('moodle/blog:create', $sitecontext)) { |
2b6e53e8 | 602 | // The user can blog about this module. |
27bad0a6 | 603 | $options['moduleadd'] = array( |
dc9fa9cb | 604 | 'string' => get_string('blogaboutthismodule', 'blog', $modulename), |
0e32a565 | 605 | 'link' => new moodle_url('/blog/edit.php', array('action' => 'add', 'modid' => $module->id)) |
27bad0a6 SH |
606 | ); |
607 | } | |
2b6e53e8 | 608 | // Cache the options. |
27bad0a6 | 609 | $moduleoptions[$key] = $options; |
2b6e53e8 | 610 | // Return the options. |
27bad0a6 SH |
611 | return $options; |
612 | } | |
613 | ||
cae83708 | 614 | /** |
615 | * This function encapsulates all the logic behind the complex | |
616 | * navigation, titles and headings of the blog listing page, depending | |
1c7b8b93 NC |
617 | * on URL params. It looks at URL params and at the current context level. |
618 | * It builds and returns an array containing: | |
619 | * | |
620 | * 1. heading: The heading displayed above the blog entries | |
621 | * 2. stradd: The text to be used as the "Add entry" link | |
622 | * 3. strview: The text to be used as the "View entries" link | |
623 | * 4. url: The moodle_url object used as the base for add and view links | |
624 | * 5. filters: An array of parameters used to filter blog listings. Used by index.php and the Recent blogs block | |
cae83708 | 625 | * |
c5dc10ee | 626 | * All other variables are set directly in $PAGE |
cae83708 | 627 | * |
628 | * It uses the current URL to build these variables. | |
629 | * A number of mutually exclusive use cases are used to structure this function. | |
630 | * | |
9de44021 JL |
631 | * @param int $courseid course id the the blog is associated to (can be null). |
632 | * @param int $groupid group id to filter blogs I can see (can be null) | |
633 | * @param int $userid blog author id (can be null) | |
634 | * @param int $tagid tag id to filter (can be null) | |
635 | * @param string $tag tag name to filter (can be null) | |
636 | * @param int $modid module id the blog is associated to (can be null). | |
637 | * @param int $entryid blog entry id to filter(can be null) | |
638 | * @param string $search string to search (can be null) | |
cae83708 | 639 | * @return array |
640 | */ | |
9de44021 JL |
641 | function blog_get_headers($courseid=null, $groupid=null, $userid=null, $tagid=null, $tag=null, $modid=null, $entryid=null, |
642 | $search = null) { | |
cae83708 | 643 | global $CFG, $PAGE, $DB, $USER; |
644 | ||
9366362a | 645 | $id = optional_param('id', null, PARAM_INT); |
9de44021 | 646 | $tag = optional_param('tag', $tag, PARAM_NOTAGS); |
451f1e38 AD |
647 | $tagid = optional_param('tagid', $tagid, PARAM_INT); |
648 | $userid = optional_param('userid', $userid, PARAM_INT); | |
9de44021 JL |
649 | $modid = optional_param('modid', $modid, PARAM_INT); |
650 | $entryid = optional_param('entryid', $entryid, PARAM_INT); | |
451f1e38 AD |
651 | $groupid = optional_param('groupid', $groupid, PARAM_INT); |
652 | $courseid = optional_param('courseid', $courseid, PARAM_INT); | |
9de44021 | 653 | $search = optional_param('search', $search, PARAM_RAW); |
cae83708 | 654 | $action = optional_param('action', null, PARAM_ALPHA); |
655 | $confirm = optional_param('confirm', false, PARAM_BOOL); | |
656 | ||
2b6e53e8 | 657 | // Ignore userid when action == add. |
1c7b8b93 NC |
658 | if ($action == 'add' && $userid) { |
659 | unset($userid); | |
660 | $PAGE->url->remove_params(array('userid')); | |
661 | } else if ($action == 'add' && $entryid) { | |
662 | unset($entryid); | |
663 | $PAGE->url->remove_params(array('entryid')); | |
664 | } | |
665 | ||
666 | $headers = array('title' => '', 'heading' => '', 'cm' => null, 'filters' => array()); | |
cae83708 | 667 | |
a6855934 | 668 | $blogurl = new moodle_url('/blog/index.php'); |
1c7b8b93 | 669 | |
1c7b8b93 NC |
670 | $headers['stradd'] = get_string('addnewentry', 'blog'); |
671 | $headers['strview'] = null; | |
cae83708 | 672 | |
1c7b8b93 | 673 | $site = $DB->get_record('course', array('id' => SITEID)); |
41b38360 | 674 | $sitecontext = context_system::instance(); |
2b6e53e8 | 675 | // Common Lang strings. |
cae83708 | 676 | $strparticipants = get_string("participants"); |
677 | $strblogentries = get_string("blogentries", 'blog'); | |
678 | ||
2b6e53e8 | 679 | // Prepare record objects as needed. |
cae83708 | 680 | if (!empty($courseid)) { |
1c7b8b93 | 681 | $headers['filters']['course'] = $courseid; |
cae83708 | 682 | $course = $DB->get_record('course', array('id' => $courseid)); |
683 | } | |
e96f2a77 | 684 | |
cae83708 | 685 | if (!empty($userid)) { |
1c7b8b93 | 686 | $headers['filters']['user'] = $userid; |
cae83708 | 687 | $user = $DB->get_record('user', array('id' => $userid)); |
516194d0 | 688 | } |
bbbf2d40 | 689 | |
2b6e53e8 | 690 | if (!empty($groupid)) { // The groupid always overrides courseid. |
1c7b8b93 | 691 | $headers['filters']['group'] = $groupid; |
cae83708 | 692 | $group = $DB->get_record('groups', array('id' => $groupid)); |
693 | $course = $DB->get_record('course', array('id' => $group->courseid)); | |
694 | } | |
bbbf2d40 | 695 | |
897aa80c | 696 | $PAGE->set_pagelayout('standard'); |
27bad0a6 | 697 | |
2b6e53e8 | 698 | // The modid always overrides courseid, so the $course object may be reset here. |
1b30a9fa DM |
699 | if (!empty($modid) && $CFG->useblogassociations) { |
700 | ||
1c7b8b93 | 701 | $headers['filters']['module'] = $modid; |
2b6e53e8 | 702 | // A groupid param may conflict with this coursemod's courseid. Ignore groupid in that case. |
0e32a565 | 703 | $courseid = $DB->get_field('course_modules', 'course', array('id' => $modid)); |
1c7b8b93 | 704 | $course = $DB->get_record('course', array('id' => $courseid)); |
cae83708 | 705 | $cm = $DB->get_record('course_modules', array('id' => $modid)); |
706 | $cm->modname = $DB->get_field('modules', 'name', array('id' => $cm->module)); | |
707 | $cm->name = $DB->get_field($cm->modname, 'name', array('id' => $cm->instance)); | |
e463f508 | 708 | $a = new stdClass(); |
1c7b8b93 | 709 | $a->type = get_string('modulename', $cm->modname); |
c5dc10ee | 710 | $PAGE->set_cm($cm, $course); |
1c7b8b93 NC |
711 | $headers['stradd'] = get_string('blogaboutthis', 'blog', $a); |
712 | $headers['strview'] = get_string('viewallmodentries', 'blog', $a); | |
cae83708 | 713 | } |
b73d1ca4 | 714 | |
1c7b8b93 | 715 | // Case 1: No entry, mod, course or user params: all site entries to be shown (filtered by search and tag/tagid) |
2b6e53e8 | 716 | // Note: if action is set to 'add' or 'edit', we do this at the end. |
1c7b8b93 NC |
717 | if (empty($entryid) && empty($modid) && empty($courseid) && empty($userid) && !in_array($action, array('edit', 'add'))) { |
718 | $PAGE->navbar->add($strblogentries, $blogurl); | |
4e1f6047 DW |
719 | $PAGE->set_title($site->fullname); |
720 | $PAGE->set_heading($site->fullname); | |
721 | $headers['heading'] = get_string('siteblogheading', 'blog'); | |
4a8b890a | 722 | } |
c2ee4e87 | 723 | |
2b6e53e8 | 724 | // Case 2: only entryid is requested, ignore all other filters. courseid is used to give more contextual information. |
cae83708 | 725 | if (!empty($entryid)) { |
1c7b8b93 NC |
726 | $headers['filters']['entry'] = $entryid; |
727 | $sql = 'SELECT u.* FROM {user} u, {post} p WHERE p.id = ? AND p.userid = u.id'; | |
cae83708 | 728 | $user = $DB->get_record_sql($sql, array($entryid)); |
1c7b8b93 | 729 | $entry = $DB->get_record('post', array('id' => $entryid)); |
c2ee4e87 | 730 | |
1c7b8b93 | 731 | $blogurl->param('userid', $user->id); |
c2ee4e87 | 732 | |
cae83708 | 733 | if (!empty($course)) { |
9366362a | 734 | $mycourseid = $course->id; |
1c7b8b93 | 735 | $blogurl->param('courseid', $mycourseid); |
c2ee4e87 | 736 | } else { |
9366362a | 737 | $mycourseid = $site->id; |
c2ee4e87 | 738 | } |
41b38360 | 739 | $shortname = format_string($site->shortname, true, array('context' => context_course::instance(SITEID))); |
e14de6f9 | 740 | |
1c7b8b93 NC |
741 | $PAGE->navbar->add($strblogentries, $blogurl); |
742 | ||
743 | $blogurl->remove_params('userid'); | |
744 | $PAGE->navbar->add($entry->subject, $blogurl); | |
8ebbb06a SH |
745 | $PAGE->set_title("$shortname: " . fullname($user) . ": $entry->subject"); |
746 | $PAGE->set_heading("$shortname: " . fullname($user) . ": $entry->subject"); | |
cae83708 | 747 | $headers['heading'] = get_string('blogentrybyuser', 'blog', fullname($user)); |
748 | ||
2b6e53e8 | 749 | // We ignore tag and search params. |
1c7b8b93 NC |
750 | if (empty($action) || !$CFG->useblogassociations) { |
751 | $headers['url'] = $blogurl; | |
9366362a | 752 | return $headers; |
753 | } | |
c2ee4e87 | 754 | } |
240075cd | 755 | |
1c7b8b93 | 756 | if (!empty($userid) && empty($entryid) && ((empty($courseid) && empty($modid)) || !$CFG->useblogassociations)) { |
2b6e53e8 AD |
757 | // Case 3: A user's blog entries. |
758 | ||
41b38360 | 759 | $shortname = format_string($site->shortname, true, array('context' => context_course::instance(SITEID))); |
1c7b8b93 | 760 | $blogurl->param('userid', $userid); |
8ebbb06a SH |
761 | $PAGE->set_title("$shortname: " . fullname($user) . ": " . get_string('blog', 'blog')); |
762 | $PAGE->set_heading("$shortname: " . fullname($user) . ": " . get_string('blog', 'blog')); | |
cae83708 | 763 | $headers['heading'] = get_string('userblog', 'blog', fullname($user)); |
27bad0a6 | 764 | $headers['strview'] = get_string('viewuserentries', 'blog', fullname($user)); |
1c7b8b93 | 765 | |
2b6e53e8 AD |
766 | } else if (!$CFG->useblogassociations && empty($userid) && !in_array($action, array('edit', 'add'))) { |
767 | // Case 4: No blog associations, no userid. | |
cae83708 | 768 | |
4e1f6047 DW |
769 | $PAGE->set_title($site->fullname); |
770 | $PAGE->set_heading($site->fullname); | |
771 | $headers['heading'] = get_string('siteblogheading', 'blog'); | |
2b6e53e8 AD |
772 | } else if (!empty($userid) && !empty($modid) && empty($entryid)) { |
773 | // Case 5: Blog entries associated with an activity by a specific user (courseid ignored). | |
cae83708 | 774 | |
41b38360 | 775 | $shortname = format_string($site->shortname, true, array('context' => context_course::instance(SITEID))); |
1c7b8b93 NC |
776 | $blogurl->param('userid', $userid); |
777 | $blogurl->param('modid', $modid); | |
cae83708 | 778 | |
2b6e53e8 | 779 | // Course module navigation is handled by build_navigation as the second param. |
cae83708 | 780 | $headers['cm'] = $cm; |
c5dc10ee | 781 | $PAGE->navbar->add(fullname($user), "$CFG->wwwroot/user/view.php?id=$user->id"); |
1c7b8b93 | 782 | $PAGE->navbar->add($strblogentries, $blogurl); |
cae83708 | 783 | |
8ebbb06a SH |
784 | $PAGE->set_title("$shortname: $cm->name: " . fullname($user) . ': ' . get_string('blogentries', 'blog')); |
785 | $PAGE->set_heading("$shortname: $cm->name: " . fullname($user) . ': ' . get_string('blogentries', 'blog')); | |
cae83708 | 786 | |
e463f508 | 787 | $a = new stdClass(); |
cae83708 | 788 | $a->user = fullname($user); |
789 | $a->mod = $cm->name; | |
1c7b8b93 | 790 | $a->type = get_string('modulename', $cm->modname); |
cae83708 | 791 | $headers['heading'] = get_string('blogentriesbyuseraboutmodule', 'blog', $a); |
1c7b8b93 NC |
792 | $headers['stradd'] = get_string('blogaboutthis', 'blog', $a); |
793 | $headers['strview'] = get_string('viewallmodentries', 'blog', $a); | |
2b6e53e8 AD |
794 | } else if (!empty($userid) && !empty($courseid) && empty($modid) && empty($entryid)) { |
795 | // Case 6: Blog entries associated with a course by a specific user. | |
cae83708 | 796 | |
1c7b8b93 NC |
797 | $blogurl->param('userid', $userid); |
798 | $blogurl->param('courseid', $courseid); | |
2c27b6ae | 799 | |
4e1f6047 DW |
800 | $PAGE->set_title($course->fullname); |
801 | $PAGE->set_heading($course->fullname); | |
cae83708 | 802 | |
e463f508 | 803 | $a = new stdClass(); |
cae83708 | 804 | $a->user = fullname($user); |
41b38360 | 805 | $a->course = format_string($course->fullname, true, array('context' => context_course::instance($course->id))); |
1c7b8b93 | 806 | $a->type = get_string('course'); |
cae83708 | 807 | $headers['heading'] = get_string('blogentriesbyuseraboutcourse', 'blog', $a); |
1c7b8b93 NC |
808 | $headers['stradd'] = get_string('blogaboutthis', 'blog', $a); |
809 | $headers['strview'] = get_string('viewblogentries', 'blog', $a); | |
810 | ||
2b6e53e8 | 811 | // Remove the userid from the URL to inform the blog_menu block correctly. |
1c7b8b93 | 812 | $blogurl->remove_params(array('userid')); |
2b6e53e8 AD |
813 | } else if (!empty($groupid) && empty($modid) && empty($entryid)) { |
814 | // Case 7: Blog entries by members of a group, associated with that group's course. | |
cae83708 | 815 | |
1c7b8b93 | 816 | $blogurl->param('courseid', $course->id); |
e14de6f9 | 817 | |
1c7b8b93 NC |
818 | $PAGE->navbar->add($strblogentries, $blogurl); |
819 | $blogurl->remove_params(array('courseid')); | |
820 | $blogurl->param('groupid', $groupid); | |
821 | $PAGE->navbar->add($group->name, $blogurl); | |
cae83708 | 822 | |
4e1f6047 DW |
823 | $PAGE->set_title($course->fullname); |
824 | $PAGE->set_heading($course->fullname); | |
cae83708 | 825 | |
e463f508 | 826 | $a = new stdClass(); |
cae83708 | 827 | $a->group = $group->name; |
41b38360 | 828 | $a->course = format_string($course->fullname, true, array('context' => context_course::instance($course->id))); |
1c7b8b93 | 829 | $a->type = get_string('course'); |
cae83708 | 830 | $headers['heading'] = get_string('blogentriesbygroupaboutcourse', 'blog', $a); |
1c7b8b93 NC |
831 | $headers['stradd'] = get_string('blogaboutthis', 'blog', $a); |
832 | $headers['strview'] = get_string('viewblogentries', 'blog', $a); | |
2b6e53e8 AD |
833 | } else if (!empty($groupid) && !empty($modid) && empty($entryid)) { |
834 | // Case 8: Blog entries by members of a group, associated with an activity in that course. | |
cae83708 | 835 | |
cae83708 | 836 | $headers['cm'] = $cm; |
1c7b8b93 NC |
837 | $blogurl->param('modid', $modid); |
838 | $PAGE->navbar->add($strblogentries, $blogurl); | |
cae83708 | 839 | |
1c7b8b93 NC |
840 | $blogurl->param('groupid', $groupid); |
841 | $PAGE->navbar->add($group->name, $blogurl); | |
cae83708 | 842 | |
4e1f6047 DW |
843 | $PAGE->set_title($course->fullname); |
844 | $PAGE->set_heading($course->fullname); | |
cae83708 | 845 | |
e463f508 | 846 | $a = new stdClass(); |
cae83708 | 847 | $a->group = $group->name; |
848 | $a->mod = $cm->name; | |
1c7b8b93 | 849 | $a->type = get_string('modulename', $cm->modname); |
cae83708 | 850 | $headers['heading'] = get_string('blogentriesbygroupaboutmodule', 'blog', $a); |
1c7b8b93 NC |
851 | $headers['stradd'] = get_string('blogaboutthis', 'blog', $a); |
852 | $headers['strview'] = get_string('viewallmodentries', 'blog', $a); | |
cae83708 | 853 | |
2b6e53e8 AD |
854 | } else if (!empty($modid) && empty($userid) && empty($groupid) && empty($entryid)) { |
855 | // Case 9: All blog entries associated with an activity. | |
cae83708 | 856 | |
c5dc10ee | 857 | $PAGE->set_cm($cm, $course); |
1c7b8b93 NC |
858 | $blogurl->param('modid', $modid); |
859 | $PAGE->navbar->add($strblogentries, $blogurl); | |
4e1f6047 DW |
860 | $PAGE->set_title($course->fullname); |
861 | $PAGE->set_heading($course->fullname); | |
cae83708 | 862 | $headers['heading'] = get_string('blogentriesabout', 'blog', $cm->name); |
e463f508 | 863 | $a = new stdClass(); |
1c7b8b93 NC |
864 | $a->type = get_string('modulename', $cm->modname); |
865 | $headers['stradd'] = get_string('blogaboutthis', 'blog', $a); | |
866 | $headers['strview'] = get_string('viewallmodentries', 'blog', $a); | |
2b6e53e8 AD |
867 | } else if (!empty($courseid) && empty($userid) && empty($groupid) && empty($modid) && empty($entryid)) { |
868 | // Case 10: All blog entries associated with a course. | |
cae83708 | 869 | |
1c7b8b93 NC |
870 | $blogurl->param('courseid', $courseid); |
871 | $PAGE->navbar->add($strblogentries, $blogurl); | |
4e1f6047 DW |
872 | $PAGE->set_title($course->fullname); |
873 | $PAGE->set_heading($course->fullname); | |
e463f508 | 874 | $a = new stdClass(); |
1c7b8b93 | 875 | $a->type = get_string('course'); |
2b6e53e8 AD |
876 | $headers['heading'] = get_string('blogentriesabout', |
877 | 'blog', | |
878 | format_string($course->fullname, | |
879 | true, | |
880 | array('context' => context_course::instance($course->id)))); | |
1c7b8b93 NC |
881 | $headers['stradd'] = get_string('blogaboutthis', 'blog', $a); |
882 | $headers['strview'] = get_string('viewblogentries', 'blog', $a); | |
883 | $blogurl->remove_params(array('userid')); | |
884 | } | |
885 | ||
886 | if (!in_array($action, array('edit', 'add'))) { | |
2b6e53e8 | 887 | // Append Tag info. |
1c7b8b93 NC |
888 | if (!empty($tagid)) { |
889 | $headers['filters']['tag'] = $tagid; | |
890 | $blogurl->param('tagid', $tagid); | |
0e32a565 | 891 | $tagrec = $DB->get_record('tag', array('id' => $tagid)); |
1c7b8b93 | 892 | $PAGE->navbar->add($tagrec->name, $blogurl); |
2b6e53e8 | 893 | } else if (!empty($tag)) { |
1af9063e AA |
894 | if ($tagrec = $DB->get_record('tag', array('name' => $tag))) { |
895 | $tagid = $tagrec->id; | |
896 | $headers['filters']['tag'] = $tagid; | |
897 | $blogurl->param('tag', $tag); | |
898 | $PAGE->navbar->add(get_string('tagparam', 'blog', $tag), $blogurl); | |
899 | } | |
1c7b8b93 | 900 | } |
240075cd | 901 | |
2b6e53e8 | 902 | // Append Search info. |
99fbcc7b | 903 | if (!empty($search) && has_capability('moodle/blog:search', $sitecontext)) { |
1c7b8b93 NC |
904 | $headers['filters']['search'] = $search; |
905 | $blogurl->param('search', $search); | |
906 | $PAGE->navbar->add(get_string('searchterm', 'blog', $search), $blogurl->out()); | |
907 | } | |
ee00eb8c | 908 | } |
909 | ||
2b6e53e8 | 910 | // Append edit mode info. |
cae83708 | 911 | if (!empty($action) && $action == 'add') { |
f36b47ef | 912 | |
cae83708 | 913 | } else if (!empty($action) && $action == 'edit') { |
c5dc10ee | 914 | $PAGE->navbar->add(get_string('editentry', 'blog')); |
240075cd | 915 | } |
ee00eb8c | 916 | |
1c7b8b93 NC |
917 | if (empty($headers['url'])) { |
918 | $headers['url'] = $blogurl; | |
919 | } | |
cae83708 | 920 | return $headers; |
921 | } | |
23677261 | 922 | |
1c7b8b93 NC |
923 | /** |
924 | * Shortcut function for getting a count of blog entries associated with a course or a module | |
925 | * @param int $courseid The ID of the course | |
926 | * @param int $cmid The ID of the course_modules | |
927 | * @return string The number of associated entries | |
928 | */ | |
929 | function blog_get_associated_count($courseid, $cmid=null) { | |
930 | global $DB; | |
41b38360 | 931 | $context = context_course::instance($courseid); |
1c7b8b93 | 932 | if ($cmid) { |
41b38360 | 933 | $context = context_module::instance($cmid); |
1c7b8b93 NC |
934 | } |
935 | return $DB->count_records('blog_association', array('contextid' => $context->id)); | |
593270c6 | 936 | } |
c1951ea9 DC |
937 | |
938 | /** | |
939 | * Running addtional permission check on plugin, for example, plugins | |
940 | * may have switch to turn on/off comments option, this callback will | |
941 | * affect UI display, not like pluginname_comment_validate only throw | |
942 | * exceptions. | |
9a909b1a RT |
943 | * blog_comment_validate will be called before viewing/adding/deleting |
944 | * comment, so don't repeat checks. | |
c1951ea9 DC |
945 | * Capability check has been done in comment->check_permissions(), we |
946 | * don't need to do it again here. | |
947 | * | |
35453657 DC |
948 | * @package core_blog |
949 | * @category comment | |
950 | * | |
0e32a565 | 951 | * @param stdClass $commentparam { |
c1951ea9 DC |
952 | * context => context the context object |
953 | * courseid => int course id | |
954 | * cm => stdClass course module object | |
955 | * commentarea => string comment area | |
956 | * itemid => int itemid | |
957 | * } | |
958 | * @return array | |
959 | */ | |
0e32a565 | 960 | function blog_comment_permissions($commentparam) { |
9a909b1a RT |
961 | global $DB; |
962 | ||
963 | // If blog is public and current user is guest, then don't let him post comments. | |
0e32a565 | 964 | $blogentry = $DB->get_record('post', array('id' => $commentparam->itemid), 'publishstate', MUST_EXIST); |
9a909b1a RT |
965 | |
966 | if ($blogentry->publishstate != 'public') { | |
967 | if (!isloggedin() || isguestuser()) { | |
968 | return array('post' => false, 'view' => true); | |
969 | } | |
970 | } | |
971 | return array('post' => true, 'view' => true); | |
c1951ea9 DC |
972 | } |
973 | ||
974 | /** | |
975 | * Validate comment parameter before perform other comments actions | |
976 | * | |
35453657 DC |
977 | * @package core_blog |
978 | * @category comment | |
979 | * | |
c1951ea9 DC |
980 | * @param stdClass $comment { |
981 | * context => context the context object | |
982 | * courseid => int course id | |
983 | * cm => stdClass course module object | |
984 | * commentarea => string comment area | |
985 | * itemid => int itemid | |
986 | * } | |
987 | * @return boolean | |
988 | */ | |
0e32a565 | 989 | function blog_comment_validate($commentparam) { |
9a909b1a RT |
990 | global $CFG, $DB, $USER; |
991 | ||
992 | // Check if blogs are enabled user can comment. | |
993 | if (empty($CFG->enableblogs) || empty($CFG->blogusecomments)) { | |
994 | throw new comment_exception('nopermissiontocomment'); | |
c1951ea9 | 995 | } |
9a909b1a | 996 | |
89f5e430 | 997 | // Validate comment area. |
0e32a565 | 998 | if ($commentparam->commentarea != 'format_blog') { |
c1951ea9 DC |
999 | throw new comment_exception('invalidcommentarea'); |
1000 | } | |
9a909b1a | 1001 | |
0e32a565 | 1002 | $blogentry = $DB->get_record('post', array('id' => $commentparam->itemid), '*', MUST_EXIST); |
9a909b1a | 1003 | |
89f5e430 | 1004 | // Validation for comment deletion. |
0e32a565 AD |
1005 | if (!empty($commentparam->commentid)) { |
1006 | if ($record = $DB->get_record('comments', array('id' => $commentparam->commentid))) { | |
c1951ea9 DC |
1007 | if ($record->commentarea != 'format_blog') { |
1008 | throw new comment_exception('invalidcommentarea'); | |
1009 | } | |
0e32a565 | 1010 | if ($record->contextid != $commentparam->context->id) { |
c1951ea9 DC |
1011 | throw new comment_exception('invalidcontext'); |
1012 | } | |
0e32a565 | 1013 | if ($record->itemid != $commentparam->itemid) { |
c1951ea9 DC |
1014 | throw new comment_exception('invalidcommentitemid'); |
1015 | } | |
1016 | } else { | |
1017 | throw new comment_exception('invalidcommentid'); | |
1018 | } | |
1019 | } | |
9a909b1a RT |
1020 | |
1021 | // Validate if user has blog view permission. | |
1022 | $sitecontext = context_system::instance(); | |
1023 | return has_capability('moodle/blog:view', $sitecontext) && | |
1024 | blog_user_can_view_user_entry($blogentry->userid, $blogentry); | |
c1951ea9 | 1025 | } |
b1627a92 DC |
1026 | |
1027 | /** | |
1028 | * Return a list of page types | |
1029 | * @param string $pagetype current page type | |
1030 | * @param stdClass $parentcontext Block's parent context | |
1031 | * @param stdClass $currentcontext Current context of block | |
1032 | */ | |
b38e2e28 | 1033 | function blog_page_type_list($pagetype, $parentcontext, $currentcontext) { |
b1627a92 | 1034 | return array( |
0e32a565 AD |
1035 | '*' => get_string('page-x', 'pagetype'), |
1036 | 'blog-*' => get_string('page-blog-x', 'blog'), | |
1037 | 'blog-index' => get_string('page-blog-index', 'blog'), | |
1038 | 'blog-edit' => get_string('page-blog-edit', 'blog') | |
b1627a92 DC |
1039 | ); |
1040 | } | |
b19cc4ef AA |
1041 | |
1042 | /** | |
1043 | * Add nodes to myprofile page. | |
1044 | * | |
1045 | * @param \core_user\output\myprofile\tree $tree Tree object | |
1046 | * @param stdClass $user user object | |
1047 | * @param bool $iscurrentuser | |
1048 | * @param stdClass $course Course object | |
1049 | * | |
1050 | * @return bool | |
1051 | */ | |
1052 | function core_blog_myprofile_navigation(core_user\output\myprofile\tree $tree, $user, $iscurrentuser, $course) { | |
0c713162 | 1053 | global $CFG; |
b19cc4ef AA |
1054 | if (!blog_is_enabled_for_user() || isguestuser($user)) { |
1055 | // The guest user cannot post, so it is not possible to view any posts. | |
1056 | // Also blogs might be disabled. | |
1057 | // May as well just bail aggressively here. | |
1058 | return true; | |
1059 | } | |
c5954f64 | 1060 | if (!blog_user_can_view_user_entry($user->id)) { |
0c713162 AG |
1061 | return true; |
1062 | } | |
b19cc4ef | 1063 | $url = new moodle_url("/blog/index.php", array('userid' => $user->id)); |
6e918b64 AG |
1064 | if (!empty($course)) { |
1065 | $url->param('courseid', $course->id); | |
1066 | } | |
b19cc4ef | 1067 | if ($iscurrentuser) { |
4887d152 | 1068 | $title = get_string('blogentries', 'core_blog'); |
b19cc4ef | 1069 | } else { |
e29866b5 | 1070 | $title = get_string('myprofileuserblogs', 'core_blog'); |
b19cc4ef AA |
1071 | } |
1072 | $blognode = new core_user\output\myprofile\node('miscellaneous', 'blogs', $title, null, $url); | |
1073 | $tree->add_node($blognode); | |
1074 | return true; | |
c1f97c77 | 1075 | } |
abea2c5d MG |
1076 | |
1077 | /** | |
1078 | * Returns posts tagged with a specified tag. | |
1079 | * | |
1080 | * @param core_tag_tag $tag | |
1081 | * @param bool $exclusivemode if set to true it means that no other entities tagged with this tag | |
1082 | * are displayed on the page and the per-page limit may be bigger | |
1083 | * @param int $fromctx context id where the link was displayed, may be used by callbacks | |
1084 | * to display items in the same context first | |
1085 | * @param int $ctx context id where to search for records | |
1086 | * @param bool $rec search in subcontexts as well | |
1087 | * @param int $page 0-based number of page being displayed | |
1088 | * @return \core_tag\output\tagindex | |
1089 | */ | |
1090 | function blog_get_tagged_posts($tag, $exclusivemode = false, $fromctx = 0, $ctx = 0, $rec = true, $page = 0) { | |
1091 | global $CFG, $OUTPUT; | |
1092 | require_once($CFG->dirroot.'/user/lib.php'); | |
1093 | ||
1094 | $systemcontext = context_system::instance(); | |
1095 | $perpage = $exclusivemode ? 20 : 5; | |
1096 | $context = $ctx ? context::instance_by_id($ctx) : context_system::instance(); | |
1097 | ||
1098 | $content = ''; | |
1099 | if (empty($CFG->enableblogs) || !has_capability('moodle/blog:view', $systemcontext)) { | |
1100 | // Blogs are not enabled or are not visible to the current user. | |
1101 | $totalpages = 0; | |
1102 | } else if ($context->contextlevel != CONTEXT_SYSTEM && empty($CFG->useblogassociations)) { | |
1103 | // No blog entries can be associated to the non-system context. | |
1104 | $totalpages = 0; | |
1105 | } else if (!$rec && $context->contextlevel != CONTEXT_COURSE && $context->contextlevel != CONTEXT_MODULE) { | |
1106 | // No blog entries can be associated with category or block context. | |
1107 | $totalpages = 0; | |
1108 | } else { | |
1109 | require_once($CFG->dirroot.'/blog/locallib.php'); | |
1110 | ||
1111 | $filters = array('tag' => $tag->id); | |
1112 | if ($rec) { | |
1113 | if ($context->contextlevel != CONTEXT_SYSTEM) { | |
1114 | $filters['context'] = $context->id; | |
1115 | } | |
1116 | } else if ($context->contextlevel == CONTEXT_COURSE) { | |
1117 | $filters['course'] = $context->instanceid; | |
1118 | } else if ($context->contextlevel == CONTEXT_MODULE) { | |
1119 | $filters['module'] = $context->instanceid; | |
1120 | } | |
1121 | $bloglisting = new blog_listing($filters); | |
1122 | $blogs = $bloglisting->get_entries($page * $perpage, $perpage); | |
1123 | $totalcount = $bloglisting->count_entries(); | |
1124 | $totalpages = ceil($totalcount / $perpage); | |
1125 | if (!empty($blogs)) { | |
1126 | $tagfeed = new core_tag\output\tagfeed(); | |
1127 | foreach ($blogs as $blog) { | |
1128 | $user = fullclone($blog); | |
1129 | $user->id = $blog->userid; | |
1130 | $user->deleted = 0; | |
1131 | $img = $OUTPUT->user_picture($user, array('size' => 35)); | |
1132 | $subject = format_string($blog->subject); | |
1133 | ||
1134 | if ($blog->publishstate == 'draft') { | |
1135 | $class = 'dimmed'; | |
1136 | } else { | |
1137 | $class = ''; | |
1138 | } | |
1139 | ||
1140 | $url = new moodle_url('/blog/index.php', array('entryid' => $blog->id)); | |
1141 | $subject = html_writer::link($url, $subject, array('class' => $class)); | |
1142 | ||
1143 | $fullname = fullname($user); | |
1144 | if (user_can_view_profile($user)) { | |
1145 | $profilelink = new moodle_url('/user/view.php', array('id' => $blog->userid)); | |
1146 | $fullname = html_writer::link($profilelink, $fullname); | |
1147 | } | |
1148 | $details = $fullname . ', ' . userdate($blog->created); | |
1149 | ||
1150 | $tagfeed->add($img, $subject, $details); | |
1151 | } | |
1152 | ||
1153 | $items = $tagfeed->export_for_template($OUTPUT); | |
1154 | $content = $OUTPUT->render_from_template('core_tag/tagfeed', $items); | |
1155 | ||
1156 | $urlparams = array('tagid' => $tag->id); | |
1157 | if ($context->contextlevel == CONTEXT_COURSE) { | |
1158 | $urlparams['courseid'] = $context->instanceid; | |
1159 | } else if ($context->contextlevel == CONTEXT_MODULE) { | |
1160 | $urlparams['modid'] = $context->instanceid; | |
1161 | } | |
1162 | $allblogsurl = new moodle_url('/blog/index.php', $urlparams); | |
1163 | ||
1164 | $rv = new core_tag\output\tagindex($tag, 'core', 'post', | |
1165 | $content, | |
1166 | $exclusivemode, $fromctx, $ctx, $rec, $page, $totalpages); | |
1167 | $rv->exclusiveurl = $allblogsurl; | |
1168 | return $rv; | |
1169 | } | |
1170 | } | |
1171 | ||
1172 | $rv = new core_tag\output\tagindex($tag, 'core', 'post', | |
1173 | $content, | |
1174 | $exclusivemode, $fromctx, $ctx, $rec, $page, $totalpages); | |
1175 | $rv->exclusiveurl = null; | |
1176 | return $rv; | |
1177 | } | |
9de44021 JL |
1178 | |
1179 | /** | |
1180 | * Validate the access to a blog. | |
1181 | * | |
1182 | * @param int $courseid course id the the blog is associated to (can be null). | |
1183 | * @param int $modid module id the blog is associated to (can be null). | |
1184 | * @param int $groupid group id to filter blogs I can see (can be null) | |
1185 | * @param int $entryid blog entry id (can be null) | |
1186 | * @param int $userid blog author id (can be null) | |
1187 | * @return array with the calculated course and id | |
1188 | * @since Moodle 3.6 | |
1189 | */ | |
1190 | function blog_validate_access($courseid, $modid, $groupid, $entryid, $userid) { | |
1191 | global $CFG, $DB, $USER, $COURSE; | |
1192 | ||
1193 | $sitecontext = context_system::instance(); | |
1194 | ||
1195 | // Add courseid if modid or groupid is specified: This is used for navigation and title. | |
1196 | if (!empty($modid) && empty($courseid)) { | |
1197 | $courseid = $DB->get_field('course_modules', 'course', array('id' => $modid)); | |
1198 | } | |
1199 | ||
1200 | if (!empty($groupid) && empty($courseid)) { | |
1201 | $courseid = $DB->get_field('groups', 'courseid', array('id' => $groupid)); | |
1202 | } | |
1203 | ||
1204 | if (!$userid && has_capability('moodle/blog:view', $sitecontext) && $CFG->bloglevel > BLOG_USER_LEVEL) { | |
1205 | if ($entryid) { | |
1206 | if (!$entryobject = $DB->get_record('post', array('id' => $entryid))) { | |
1207 | print_error('nosuchentry', 'blog'); | |
1208 | } | |
1209 | $userid = $entryobject->userid; | |
1210 | } | |
1211 | } else if (!$userid) { | |
1212 | $userid = $USER->id; | |
1213 | } | |
1214 | ||
1215 | if (!empty($modid)) { | |
1216 | if ($CFG->bloglevel < BLOG_SITE_LEVEL) { | |
1217 | print_error(get_string('nocourseblogs', 'blog')); | |
1218 | } | |
1219 | if (!$mod = $DB->get_record('course_modules', array('id' => $modid))) { | |
1220 | print_error(get_string('invalidmodid', 'blog')); | |
1221 | } | |
1222 | $courseid = $mod->course; | |
1223 | } | |
1224 | ||
1225 | if ((empty($courseid) ? true : $courseid == SITEID) && empty($userid)) { | |
1226 | if ($CFG->bloglevel < BLOG_SITE_LEVEL) { | |
1227 | print_error('siteblogdisable', 'blog'); | |
1228 | } | |
1229 | if (!has_capability('moodle/blog:view', $sitecontext)) { | |
1230 | print_error('cannotviewsiteblog', 'blog'); | |
1231 | } | |
1232 | ||
1233 | $COURSE = $DB->get_record('course', array('format' => 'site')); | |
1234 | $courseid = $COURSE->id; | |
1235 | } | |
1236 | ||
1237 | if (!empty($courseid)) { | |
1238 | if (!$course = $DB->get_record('course', array('id' => $courseid))) { | |
1239 | print_error('invalidcourseid'); | |
1240 | } | |
1241 | ||
1242 | $courseid = $course->id; | |
1243 | ||
1244 | if (!has_capability('moodle/blog:view', $sitecontext)) { | |
1245 | print_error('cannotviewcourseblog', 'blog'); | |
1246 | } | |
1247 | } else { | |
1248 | $coursecontext = context_course::instance(SITEID); | |
1249 | } | |
1250 | ||
1251 | if (!empty($groupid)) { | |
1252 | if ($CFG->bloglevel < BLOG_SITE_LEVEL) { | |
1253 | print_error('groupblogdisable', 'blog'); | |
1254 | } | |
1255 | ||
1256 | if (! $group = groups_get_group($groupid)) { | |
1257 | print_error(get_string('invalidgroupid', 'blog')); | |
1258 | } | |
1259 | ||
1260 | if (!$course = $DB->get_record('course', array('id' => $group->courseid))) { | |
1261 | print_error('invalidcourseid'); | |
1262 | } | |
1263 | ||
1264 | $coursecontext = context_course::instance($course->id); | |
1265 | $courseid = $course->id; | |
1266 | ||
1267 | if (!has_capability('moodle/blog:view', $sitecontext)) { | |
1268 | print_error(get_string('cannotviewcourseorgroupblog', 'blog')); | |
1269 | } | |
1270 | ||
1271 | if (groups_get_course_groupmode($course) == SEPARATEGROUPS && | |
1272 | !has_capability('moodle/site:accessallgroups', $coursecontext)) { | |
1273 | ||
1274 | if (!groups_is_member($groupid)) { | |
1275 | print_error('notmemberofgroup'); | |
1276 | } | |
1277 | } | |
1278 | } | |
1279 | ||
1280 | if (!empty($userid)) { | |
1281 | if ($CFG->bloglevel < BLOG_USER_LEVEL) { | |
1282 | print_error('blogdisable', 'blog'); | |
1283 | } | |
1284 | ||
1285 | if (!$user = $DB->get_record('user', array('id' => $userid))) { | |
1286 | print_error('invaliduserid'); | |
1287 | } | |
1288 | ||
1289 | if ($user->deleted) { | |
1290 | print_error('userdeleted'); | |
1291 | } | |
1292 | ||
1293 | if ($USER->id == $userid) { | |
1294 | if (!has_capability('moodle/blog:create', $sitecontext) | |
1295 | && !has_capability('moodle/blog:view', $sitecontext)) { | |
1296 | print_error('donothaveblog', 'blog'); | |
1297 | } | |
1298 | } else { | |
1299 | if (!has_capability('moodle/blog:view', $sitecontext) || !blog_user_can_view_user_entry($userid)) { | |
1300 | print_error('cannotviewcourseblog', 'blog'); | |
1301 | } | |
1302 | } | |
1303 | } | |
1304 | return array($courseid, $userid); | |
1305 | } |