4 * Library of functions and constants for blog
6 require_once($CFG->libdir
.'/blocklib.php');
7 require_once($CFG->libdir
.'/pagelib.php');
8 require_once($CFG->dirroot
.'/blog/rsslib.php');
9 require_once($CFG->dirroot
.'/blog/blogpage.php');
10 include_once($CFG->dirroot
.'/tag/lib.php');
13 * Definition of blogcourse page type (blog page with course id present).
15 //not used at the moment, and may not need to be
16 define('PAGE_BLOG_COURSE_VIEW', 'blog_course-view');
20 * Checks to see if user has visited blogpages before, if not, install 2
21 * default blocks (blog_menu and blog_tags).
23 function blog_check_and_install_blocks() {
25 if (isloggedin() && !isguest()) {
26 // if this user has not visited this page before
27 if (!get_user_preferences('blogpagesize')) {
28 // find the correct ids for blog_menu and blog_from blocks
29 $menublock = get_record('block','name','blog_menu');
30 $tagsblock = get_record('block','name','blog_tags');
31 // add those 2 into block_instance page
33 // add blog_menu block
34 $newblock = new object();
35 $newblock->blockid
= $menublock->id
;
36 $newblock->pageid
= $USER->id
;
37 $newblock->pagetype
= 'blog-view';
38 $newblock->position
= 'r';
39 $newblock->weight
= 0;
40 $newblock->visible
= 1;
41 insert_record('block_instance', $newblock);
44 $newblock -> blockid
= $tagsblock->id
;
45 $newblock -> weight
= 1;
46 insert_record('block_instance', $newblock);
48 // finally we set the page size pref
49 set_user_preference('blogpagesize', 10);
56 * Adaptation of isediting in moodlelib.php for blog module
59 function blog_isediting() {
62 return !empty($SESSION->blog_editing_enabled
);
67 * This function is in lib and not in BlogInfo because entries being searched
68 * might be found in any number of blogs rather than just one.
72 function blog_print_html_formatted_entries($postid, $filtertype, $filterselect, $tagid, $tag) {
76 $blogpage = optional_param('blogpage', 0, PARAM_INT
);
77 $bloglimit = optional_param('limit', get_user_preferences('blogpagesize', 10), PARAM_INT
);
78 $start = $blogpage * $bloglimit;
80 $sitecontext = get_context_instance(CONTEXT_SYSTEM
, SITEID
);
82 $morelink = '<br /> ';
84 $totalentries = get_viewable_entry_count($postid, $bloglimit, $start, $filtertype, $filterselect, $tagid, $tag, $sort='lastmodified DESC');
85 $blogEntries = blog_fetch_entries($postid, $bloglimit, $start, $filtertype, $filterselect, $tagid, $tag, $sort='lastmodified DESC', true);
87 print_paging_bar($totalentries, $blogpage, $bloglimit, get_baseurl($filtertype, $filterselect), 'blogpage');
89 if ($CFG->enablerssfeeds
) {
90 blog_rss_print_link($filtertype, $filterselect, $tag);
93 if (has_capability('moodle/blog:create', $sitecontext)) {
94 //the user's blog is enabled and they are viewing their own blog
95 $addlink = '<div class="addbloglink">';
96 $addlink .= '<a href="'.$CFG->wwwroot
.'/blog/edit.php?action=add'.'">'. get_string('addnewentry', 'blog').'</a>';
104 foreach ($blogEntries as $blogEntry) {
105 blog_print_entry($blogEntry, 'list', $filtertype, $filterselect); //print this entry.
109 print_paging_bar($totalentries, $blogpage, $bloglimit, get_baseurl($filtertype, $filterselect), 'blogpage');
112 print '<br /><div style="text-align:center">'. get_string('noentriesyet', 'blog') .'</div><br />';
116 print $morelink.'<br />'."\n";
120 $output = '<br /><div style="text-align:center">'. get_string('noentriesyet', 'blog') .'</div><br />';
128 * This function is in lib and not in BlogInfo because entries being searched
129 * might be found in any number of blogs rather than just one.
131 * This function builds an array which can be used by the included
132 * template file, making predefined and nicely formatted variables available
133 * to the template. Template creators will not need to become intimate
134 * with the internal objects and vars of moodle blog nor will they need to worry
135 * about properly formatting their data
137 * @param BlogEntry blogEntry - a hopefully fully populated BlogEntry object
138 * @param string viewtype Default is 'full'. If 'full' then display this blog entry
139 * in its complete form (eg. archive page). If anything other than 'full'
140 * display the entry in its abbreviated format (eg. index page)
142 function blog_print_entry($blogEntry, $viewtype='full', $filtertype='', $filterselect='', $mode='loud') {
144 global $USER, $CFG, $COURSE, $ME;
146 $template['body'] = format_text($blogEntry->summary
, $blogEntry->format
);
147 //$template['title'] = '<a name="'. $blogEntry->subject .'"></a>';
148 //enclose the title in nolink tags so that moodle formatting doesn't autolink the text
149 $template['title'] = '<span class="nolink">'.$blogEntry->subject
.'</span>';
150 $template['userid'] = $blogEntry->userid
;
151 $template['author'] = fullname(get_record('user','id',$blogEntry->userid
));
152 $template['lastmod'] = userdate($blogEntry->lastmodified
);
153 $template['created'] = userdate($blogEntry->created
);
154 $template['publishstate'] = $blogEntry->publishstate
;
156 /// preventing user to browse blogs that they aren't supposed to see
157 /// This might not be too good since there are multiple calls per page
160 if (!blog_user_can_view_user_post($template['userid'])) {
161 error ('you can not view this post');
164 $stredit = get_string('edit');
165 $strdelete = get_string('delete');
167 $user = get_record('user','id',$template['userid']);
169 /// Start printing of the blog
171 echo '<table cellspacing="0" class="forumpost blogpost blog'.$template['publishstate'].'" width="100%">';
173 echo '<tr class="header"><td class="picture left">';
174 print_user_picture($template['userid'], SITEID
, $user->picture
);
177 echo '<td class="topic starter"><div class="subject">'.$template['title'].'</div><div class="author">';
178 $fullname = fullname($user, $template['userid']);
180 $by->name
= '<a href="'.$CFG->wwwroot
.'/user/view.php?id='.
181 $user->id
.'&course='.$COURSE->id
.'">'.$fullname.'</a>';
182 $by->date
= $template['lastmod'];
183 print_string('bynameondate', 'forum', $by);
184 echo '</div></td></tr>';
186 echo '<tr><td class="left side">';
190 echo '</td><td class="content">'."\n";
192 if ($blogEntry->attachment
) {
193 echo '<div class="attachments">';
194 $attachedimages = blog_print_attachments($blogEntry);
197 $attachedimages = '';
200 switch ($template['publishstate']) {
202 $blogtype = get_string('publishtonoone', 'blog');
205 $blogtype = get_string('publishtosite', 'blog');
208 $blogtype = get_string('publishtoworld', 'blog');
216 echo '<div class="audience">'.$blogtype.'</div>';
218 // Print whole message
219 echo format_text($template['body']);
221 /// Print attachments
222 echo $attachedimages;
226 if ($blogtags = get_records_sql('SELECT t.* FROM '.$CFG->prefix.'tags t, '.$CFG->prefix.'blog_tag_instance ti
227 WHERE t.id = ti.tagid
228 AND ti.entryid = '.$blogEntry->id)) {
230 if (!empty($CFG->usetags
) && ($blogtags = get_item_tags('blog', $blogEntry->id
))) {
231 echo '<div class="tags">';
233 print_string('tags');
235 foreach ($blogtags as $key => $blogtag) {
236 //$taglist[] = '<a href="index.php?filtertype='.$filtertype.'&filterselect='.$filterselect.'&tagid='.$blogtag->id.'">'.tag_display_name($blogtag).'</a>'; // Blog tag only
237 $taglist[] = '<a href="'.$CFG->wwwroot
.'/tag/index.php?id='.$blogtag->id
.'">'.tag_display_name($blogtag).'</a>'; // General tag link
239 echo implode(', ', $taglist);
246 echo '<div class="commands">';
248 if (blog_user_can_edit_post($blogEntry)) {
249 echo '<a href="'.$CFG->wwwroot
.'/blog/edit.php?action=edit&id='.$blogEntry->id
.'">'.$stredit.'</a>';
250 echo '| <a href="'.$CFG->wwwroot
.'/blog/edit.php?action=delete&id='.$blogEntry->id
.'">'.$strdelete.'</a>';
255 echo '</td></tr></table>'."\n\n";
259 function blog_file_area_name($blogentry) {
260 // Creates a directory file name, suitable for make_upload_directory()
262 // $CFG->dataroot/blog/attachments/xxxx/file.jpg
263 return "blog/attachments/$blogentry->id";
266 function blog_file_area($blogentry) {
267 return make_upload_directory( blog_file_area_name($blogentry) );
270 function blog_delete_old_attachments($post, $exception="") {
271 // Deletes all the user files in the attachments area for a post
272 // EXCEPT for any file named $exception
274 if ($basedir = blog_file_area($post)) {
275 if ($files = get_directory_list($basedir)) {
276 foreach ($files as $file) {
277 if ($file != $exception) {
278 unlink("$basedir/$file");
279 notify("Existing file '$file' has been deleted!");
283 if (!$exception) { // Delete directory as well, if empty
289 function blog_print_attachments($blogentry, $return=NULL) {
290 // if return=html, then return a html string.
291 // if return=text, then return a text-only string.
292 // otherwise, print HTML for non-images, and return image HTML
296 $filearea = blog_file_area_name($blogentry);
301 if ($basedir = blog_file_area($blogentry)) {
302 if ($files = get_directory_list($basedir)) {
303 $strattachment = get_string("attachment", "forum");
304 foreach ($files as $file) {
305 include_once($CFG->libdir
.'/filelib.php');
306 $icon = mimeinfo("icon", $file);
307 $type = mimeinfo("type", $file);
308 if ($CFG->slasharguments
) {
309 $ffurl = "$CFG->wwwroot/file.php/$filearea/$file";
311 $ffurl = "$CFG->wwwroot/file.php?file=/$filearea/$file";
313 $image = "<img src=\"$CFG->pixpath/f/$icon\" class=\"icon\" alt=\"\" />";
315 if ($return == "html") {
316 $output .= "<a href=\"$ffurl\">$image</a> ";
317 $output .= "<a href=\"$ffurl\">$file</a><br />";
319 } else if ($return == "text") {
320 $output .= "$strattachment $file:\n$ffurl\n";
323 if (in_array($type, array('image/gif', 'image/jpeg', 'image/png'))) { // Image attachments don't get printed as links
324 $imagereturn .= "<br /><img src=\"$ffurl\" alt=\"\" />";
326 echo "<a href=\"$ffurl\">$image</a> ";
327 echo filter_text("<a href=\"$ffurl\">$file</a><br />");
343 * Use this function to retrieve a list of publish states available for
344 * the currently logged in user.
346 * @return array This function returns an array ideal for sending to moodles'
347 * choose_from_menu function.
349 function blog_applicable_publish_states($courseid='') {
353 // everyone gets draft access
354 if ($CFG->bloglevel
>= BLOG_USER_LEVEL
) {
355 $options = array ( 'draft' => get_string('publishtonoone', 'blog') );
358 if ($CFG->bloglevel
> BLOG_USER_LEVEL
) {
359 $options['site'] = get_string('publishtosite', 'blog');
362 if ($CFG->bloglevel
>= BLOG_GLOBAL_LEVEL
) {
363 $options['public'] = get_string('publishtoworld', 'blog');
371 * User can edit a blog entry if this is their own blog post and they have
372 * the capability moodle/blog:create, or if they have the capability
373 * moodle/blog:manageentries.
375 * This also applies to deleting of posts.
377 function blog_user_can_edit_post($blogEntry) {
381 $sitecontext = get_context_instance(CONTEXT_SYSTEM
, SITEID
);
383 if (has_capability('moodle/blog:manageentries', $sitecontext)) {
384 return true; // can edit any blog post
387 if ($blogEntry->userid
== $USER->id
388 and has_capability('moodle/blog:create', $sitecontext)) {
389 return true; // can edit own when having blog:create capability
397 * Checks to see if a user can view the blogs of another user.
398 * Only blog level is checked here, the capabilities are enforced
401 function blog_user_can_view_user_post($targetuserid, $blogEntry=null) {
404 if (empty($CFG->bloglevel
)) {
405 return false; // blog system disabled
408 if (!empty($USER->id
) and $USER->id
== $targetuserid) {
409 return true; // can view own posts in any case
412 $sitecontext = get_context_instance(CONTEXT_SYSTEM
, SITEID
);
413 if (has_capability('moodle/blog:manageentries', $sitecontext)) {
414 return true; // can manage all posts
417 // coming for 1 post, make sure it's not a draft
418 if ($blogEntry and $blogEntry->publishstate
== 'draft') {
419 return false; // can not view draft of others
422 // coming for 1 post, make sure user is logged in, if not a public blog
423 if ($blogEntry && $blogEntry->publishstate
!= 'public' && !isloggedin()) {
427 switch ($CFG->bloglevel
) {
428 case BLOG_GLOBAL_LEVEL
:
432 case BLOG_SITE_LEVEL
:
433 if (!empty($USER->id
)) { // not logged in viewers forbidden
439 case BLOG_COURSE_LEVEL
:
440 $mycourses = array_keys(get_my_courses($USER->id
));
441 $usercourses = array_keys(get_my_courses($targetuserid));
442 $shared = array_intersect($mycourses, $usercourses);
443 if (!empty($shared)) {
449 case BLOG_GROUP_LEVEL
:
450 $mycourses = array_keys(get_my_courses($USER->id
));
451 $usercourses = array_keys(get_my_courses($targetuserid));
452 $shared = array_intersect($mycourses, $usercourses);
453 foreach ($shared as $courseid) {
454 $coursecontext = get_context_instance(CONTEXT_COURSE
, $courseid);
455 if (has_capability('moodle/site:accessallgroups', $coursecontext)
456 or groupmode($courseid) != SEPARATEGROUPS
) {
459 if ($usergroups = groups_get_all_groups($courseid, $targetuserid)) {
460 foreach ($usergroups as $usergroup) {
461 if (groups_is_member($usergroup->id
)) {
471 case BLOG_USER_LEVEL
:
473 $personalcontext = get_context_instance(CONTEXT_USER
, $targetuserid);
474 return has_capability('moodle/user:readuserblogs', $personalcontext);
482 * Main filter function.
484 function blog_fetch_entries($postid='', $fetchlimit=10, $fetchstart='', $filtertype='', $filterselect='', $tagid='', $tag ='', $sort='lastmodified DESC', $limit=true) {
488 /// the post table will be used for other things too
489 $typesql = " AND p.module = 'blog' ";
491 /// set the tag id for searching
495 if ($tagrec = get_record_sql('SELECT * FROM '.$CFG->prefix
.'tag WHERE name LIKE "'.$tag.'"')) {
498 $tag = -1; //no records found
502 // If we have specified an ID
503 // Just return 1 entry
507 if ($post = get_record('post', 'id', $postid)) {
509 if (blog_user_can_view_user_post($post->userid
, $post)) {
511 if ($user = get_record('user', 'id', $post->userid
)) {
512 $post->email
= $user->email
;
513 $post->firstname
= $user->firstname
;
514 $post->lastname
= $user->lastname
;
522 } else { // bad postid
528 $tagtablesql = $CFG->prefix
.'tag_instance ti, ';
529 $tagquerysql = ' AND ti.itemid = p.id AND ti.tagid = '.$tag.' AND ti.itemtype = \'blog\' ';
535 if (isloggedin() && !has_capability('moodle/legacy:guest', get_context_instance(CONTEXT_SYSTEM
, SITEID
), $USER->id
, false)) {
536 $permissionsql = 'AND (p.publishstate = \'site\' OR p.publishstate = \'public\' OR p.userid = '.$USER->id
.')';
538 $permissionsql = 'AND p.publishstate = \'public\'';
541 // fix for MDL-9165, use with readuserblogs capability in a user context can read that user's private blogs
542 // admins can see all blogs regardless of publish states, as described on the help page
543 if (has_capability('moodle/user:readuserblogs', get_context_instance(CONTEXT_SYSTEM
, SITEID
))) {
545 } else if ($filtertype=='user' && has_capability('moodle/user:readuserblogs', get_context_instance(CONTEXT_USER
, $filterselect))) {
548 /****************************************
549 * depending on the type, there are 4 *
550 * different possible sqls *
551 ****************************************/
553 $requiredfields = 'p.*, u.firstname,u.lastname,u.email';
555 if ($filtertype == 'course' && $filterselect == SITEID
) { // Really a site
556 $filtertype = 'site';
559 switch ($filtertype) {
563 $SQL = 'SELECT '.$requiredfields.' FROM '.$CFG->prefix
.'post p, '.$tagtablesql
564 .$CFG->prefix
.'user u
565 WHERE p.userid = u.id '.$tagquerysql.'
567 '.$permissionsql.$typesql;
572 // all users with a role assigned
573 $context = get_context_instance(CONTEXT_COURSE
, $filterselect);
575 // MDL-10037, hidden users' blogs should not appear
576 if (has_capability('moodle/role:viewhiddenassigns', $context)) {
579 $hiddensql = ' AND ra.hidden = 0 ';
582 $SQL = 'SELECT '.$requiredfields.' FROM '.$CFG->prefix
.'post p, '.$tagtablesql
583 .$CFG->prefix
.'role_assignments ra, '.$CFG->prefix
.'user u
584 WHERE p.userid = ra.userid '.$tagquerysql.'
585 AND ra.contextid '.get_related_contexts_string($context).'
588 '.$hiddensql.$permissionsql.$typesql;
594 $SQL = 'SELECT '.$requiredfields.' FROM '.$CFG->prefix
.'post p, '.$tagtablesql
595 .$CFG->prefix
.'groups_members gm, '.$CFG->prefix
.'user u
596 WHERE p.userid = gm.userid AND u.id = p.userid '.$tagquerysql.'
597 AND gm.groupid = '.$filterselect.'
599 '.$permissionsql.$typesql;
604 $SQL = 'SELECT '.$requiredfields.' FROM '.$CFG->prefix
.'post p, '.$tagtablesql
605 .$CFG->prefix
.'user u
606 WHERE p.userid = u.id '.$tagquerysql.'
607 AND u.id = '.$filterselect.'
609 '.$permissionsql.$typesql;
616 if ($fetchstart !== '' && $limit) {
617 $limitfrom = $fetchstart;
618 $limitnum = $fetchlimit;
621 $orderby = ' ORDER BY '. $sort .' ';
623 //global $db; $db->debug = true;
624 $records = get_records_sql($SQL . $orderby, $limitfrom, $limitnum);
625 //$db->debug = false;
627 if (empty($records)) {
636 * get the count of viewable entries, easiest way is to count blog_fetch_entries
637 * this is used for print_paging_bar
638 * this is not ideal, but because of the UNION in the sql in blog_fetch_entries,
639 * it is hard to use count_records_sql
641 function get_viewable_entry_count($postid='', $fetchlimit=10,
642 $fetchstart='', $filtertype='', $filterselect='', $tagid='',
643 $tag ='', $sort='lastmodified DESC') {
645 $blogEntries = blog_fetch_entries($postid, $fetchlimit,
646 $fetchstart, $filtertype, $filterselect, $tagid, $tag,
647 $sort='lastmodified DESC', false);
649 return count($blogEntries);
653 /// Find the base url from $_GET variables, for print_paging_bar
654 function get_baseurl($filtertype, $filterselect) {
658 unset($getcopy['blogpage']);
660 $strippedurl = strip_querystring(qualified_me());
661 if(!empty($getcopy)) {
664 foreach($getcopy as $var => $val) {
667 if ($var != 'filterselect' && $var != 'filtertype') {
668 $querystring .= '?'.$var.'='.$val;
674 if ($var != 'filterselect' && $var != 'filtertype') {
675 $querystring .= '&'.$var.'='.$val;
680 if (isset($hasparam)) {
681 $querystring .= '&';
689 return strip_querystring(qualified_me()) . $querystring. 'filtertype='.
690 $filtertype.'&filterselect='.$filterselect.'&';