]> git.mjollnir.org Git - moodle.git/commitdiff
MDL-19676 Blog improvements
authornicolasconnault <nicolasconnault>
Fri, 4 Sep 2009 00:36:43 +0000 (00:36 +0000)
committernicolasconnault <nicolasconnault>
Fri, 4 Sep 2009 00:36:43 +0000 (00:36 +0000)
46 files changed:
admin/cron.php
admin/settings/appearance.php
admin/settings/security.php
backup/backuplib.php
blocks/blog_externals/block_blog_externals.php [new file with mode: 0644]
blocks/blog_menu/block_blog_menu.php
blocks/blog_recent/block_blog_recent.php [new file with mode: 0644]
blocks/tags/block_tags.php
blog/edit.php
blog/edit_form.js [new file with mode: 0644]
blog/edit_form.php
blog/external.php [new file with mode: 0644]
blog/external_form.php [new file with mode: 0644]
blog/header.php
blog/index.php
blog/lib.php
blog/locallib.php [new file with mode: 0644]
blog/preferences.php
blog/preferences_form.php [new file with mode: 0644]
blog/rsslib.php
blog/simpletest/testbloglib.php [new file with mode: 0644]
blog/version.php
course/lib.php
grade/report/grader/preferences_form.php
lang/en_utf8/admin.php
lang/en_utf8/assignment.php
lang/en_utf8/blog.php
lang/en_utf8/help/blog/description.html [new file with mode: 0644]
lang/en_utf8/help/blog/name.html [new file with mode: 0644]
lang/en_utf8/help/blog/tags.html [new file with mode: 0644]
lang/en_utf8/help/blog/url.html [new file with mode: 0644]
lib/accesslib.php
lib/adminlib.php
lib/db/access.php
lib/db/install.xml
lib/db/upgrade.php
lib/form/format.php
lib/form/select.php
lib/outputcomponents.php
mod/assignment/type/blog/assignment.class.php [new file with mode: 0644]
mod/assignment/version.php
tag/index.php
theme/standard/styles_color.css
theme/standard/styles_fonts.css
theme/standard/styles_layout.css
user/tabs.php

index 20f7d970fa3632c5c0afca6d6afd6dd1fbfb79fe..cd6982811a6eb9f7f127ed51f28dfe36d21d9b34 100644 (file)
             }
         }
     }
+    
+    // Run external blog cron if needed
+    if ($CFG->useexternalblogs) {
+        require_once($CFG->dirroot . '/blog/lib.php');
+        $sql = "SELECT * FROM {blog_external} WHERE timefetched < ? - ? OR timefetched = 0";
+        $external_blogs = $DB->get_records_sql($sql, array(mktime(), $CFG->externalblogcrontime));
+        
+        foreach ($external_blogs as $eb) {
+            blog_fetch_external_entries($eb);
+        }
+    }
 
     // cleanup file trash
     $fs = get_file_storage();
index 73467fdfee304e80fbc68fee7714eab157948a1e..78d962fe88aa040c5585c313ff723ca5fe9f9434 100644 (file)
@@ -49,6 +49,22 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
     $temp->add(new admin_setting_configtext('calendar_exportsalt', get_string('calendarexportsalt','admin'), get_string('configcalendarexportsalt', 'admin'), random_string(60)));
     $ADMIN->add('appearance', $temp);
 
+    // blog
+    $temp = new admin_settingpage('blog', get_string('blog','blog'));
+    $temp->add(new admin_setting_configcheckbox('useblogassociations', get_string('useblogassociations', 'blog'), get_string('configuseblogassociations','blog'), 1));
+    $temp->add(new admin_setting_configselect('bloglevel', get_string('bloglevel', 'admin'), get_string('configbloglevel', 'admin'), 4, array(5 => get_string('worldblogs','blog'),
+                                                                                                                                              4 => get_string('siteblogs','blog'),
+                                                                                                                                              1 => get_string('personalblogs','blog'),
+                                                                                                                                              0 => get_string('disableblogs','blog'))));
+    $temp->add(new admin_setting_configcheckbox('useexternalblogs', get_string('useexternalblogs', 'blog'), get_string('configuseexternalblogs','blog'), 1));
+    $temp->add(new admin_setting_configselect('externalblogcrontime', get_string('externalblogcrontime', 'blog'), get_string('configexternalblogcrontime', 'blog'), 86400,
+        array(43200 => get_string('numhours', '', 12),
+              86400 => get_string('numhours', '', 24),
+              172800 => get_string('numdays', '', 2),
+              604800 => get_string('numdays', '', 7))));
+    $temp->add(new admin_setting_configtext('maxexternalblogsperuser', get_string('maxexternalblogsperuser','blog'), get_string('configmaxexternalblogsperuser', 'blog'), 1));
+    $ADMIN->add('appearance', $temp);
+
 /* TODO: reimplement editor settings and preferences, editors are now full plugins ;-)
     // "htmleditor" settingpage
     $ADMIN->add('appearance', new admin_category('htmleditor', get_string('htmleditor', 'admin')));
index 5799bce1d49268bc123f6dbbba89358703327047..9b253d7ca8ea5a46e6788243bd3175a6adef2aa2 100644 (file)
@@ -53,10 +53,6 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
                                               'firstname' => get_string('firstname'))));
     $temp->add(new admin_setting_configcheckbox('extendedusernamechars', get_string('extendedusernamechars', 'admin'), get_string('configextendedusernamechars', 'admin'), 0));
     $temp->add(new admin_setting_configtext('sitepolicy', get_string('sitepolicy', 'admin'), get_string('configsitepolicy', 'admin'), '', PARAM_RAW));
-    $temp->add(new admin_setting_configselect('bloglevel', get_string('bloglevel', 'admin'), get_string('configbloglevel', 'admin'), 4, array(5 => get_string('worldblogs','blog'),
-                                                                                                                                              4 => get_string('siteblogs','blog'),
-                                                                                                                                              1 => get_string('personalblogs','blog'),
-                                                                                                                                              0 => get_string('disableblogs','blog'))));
     $temp->add(new admin_setting_configcheckbox('usetags', get_string('usetags','admin'),get_string('configusetags', 'admin'),'1'));
     $temp->add(new admin_setting_configcheckbox('keeptagnamecase', get_string('keeptagnamecase','admin'),get_string('configkeeptagnamecase', 'admin'),'1'));
 
index a391e6d6d31bb8d08e961513ebd83d7a141a385e..2adc6cdce617ab5c5a75240fd1c329a2f773f147 100644 (file)
 
         //Now, add blog users if necessary
         if ($includeblogs) {
-            include_once("$CFG->dirroot/blog/lib.php");
             //Get users
-            $blogusers = blog_get_participants();
+            $blogusers = $DB->get_records_sql("SELECT u.id, u.id FROM {user} u WHERE u.id IN (SELECT DISTINCT userid FROM {post})");
+
             //Add blog users to results
             if ($blogusers) {
                 foreach ($blogusers as $bloguser) {
             fwrite ($bf, start_tag("BLOGS",2,true));
 
             if ($siteblogs) {
-                $rs_blogs = $DB->get_recordset('post', array('module'=>'blog', 'courseid'=>0));
+                $rs_blogs = $DB->get_records('post', array('module'=>'blog', 'courseid'=>0));
             /// Iterate over every blog
                 foreach ($rs_blogs as $blog) {
-                /// start blog
-                    fwrite($bf, start_tag("BLOG",3,true));
-                /// blog body
-                    fwrite ($bf,full_tag("ID",4,false,$blog->id));
-                    fwrite ($bf,full_tag("MODULE",4,false,$blog->module));
-                    fwrite ($bf,full_tag("USERID",4,false,$blog->userid));
-                    fwrite ($bf,full_tag("COURSEID",4,false,$blog->courseid));
-                    fwrite ($bf,full_tag("GROUPID",4,false,$blog->groupid));
-                    fwrite ($bf,full_tag("MODULEID",4,false,$blog->moduleid));
-                    fwrite ($bf,full_tag("COURSEMODULEID",4,false,$blog->coursemoduleid));
-                    fwrite ($bf,full_tag("SUBJECT",4,false,$blog->subject));
-                    fwrite ($bf,full_tag("SUMMARY",4,false,$blog->summary));
-                    fwrite ($bf,full_tag("CONTENT",4,false,$blog->content));
-                    fwrite ($bf,full_tag("UNIQUEHASH",4,false,$blog->uniquehash));
-                    fwrite ($bf,full_tag("RATING",4,false,$blog->rating));
-                    fwrite ($bf,full_tag("FORMAT",4,false,$blog->format));
-                    fwrite ($bf,full_tag("ATTACHMENT",4,false,$blog->attachment));
-                    fwrite ($bf,full_tag("PUBLISHSTATE",4,false,$blog->publishstate));
-                    fwrite ($bf,full_tag("LASTMODIFIED",4,false,$blog->lastmodified));
-                    fwrite ($bf,full_tag("CREATED",4,false,$blog->created));
-                    fwrite ($bf,full_tag("USERMODIFIED",4,false,$blog->usermodified));
-
-                /// Blog tags
-                /// Check if we have blog tags to backup
-                    if (!empty($CFG->usetags)) {
-                        if ($tags = tag_get_tags('post', $blog->id)) { //This return them ordered by default
-                        /// Start BLOG_TAGS tag
-                            fwrite ($bf,start_tag("BLOG_TAGS",4,true));
-                        /// Write blog tags fields
-                            foreach ($tags as $tag) {
-                                fwrite ($bf,start_tag("BLOG_TAG",5,true));
-                                fwrite ($bf,full_tag("NAME",6,false,$tag->name));
-                                fwrite ($bf,full_tag("RAWNAME",6,false,$tag->rawname));
-                                fwrite ($bf,end_tag("BLOG_TAG",5,true));
-                            }
-                        /// End BLOG_TAGS tag
-                            fwrite ($bf,end_tag("BLOG_TAGS",4,true));
-                        }
-                    }
-
-                /// Blog comments
-                    /// TODO: Blog comments go here (2.0)
-
-                /// end blog
-                    fwrite($bf, end_tag("BLOG",3,true));
+                    backup_blog($bf, $blog->id, 3);
 
                 /// Do some output
                     $counter++;
         return $status;
     }
 
+
+    function backup_course_blogs($bf, $preferences) {
+        global $DB;
+            fwrite ($bf, start_tag("BLOGS",2,true));
+
+        $sql = 'SELECT as.data1 FROM {assignment} a, {assignment_submissions} as WHERE 
+                as.assignment = a.id AND a.assignmenttype = \'blog\' AND a.course = ?';
+        $records = $DB->get_records_sql($sql, array($preferences->backup_course));
+        foreach ($records as $rec) {
+            backup_blog($bf, $rec->data1, 3); 
+        }
+        fwrite($bf, end_tag("BLOGS",2,true));
+    }
+    
+    function backup_blog($bf, $blogid, $level) {
+        global $DB;
+        $blog = $DB->get_record('post', array('module'=>'blog', 'id'=>$blogid));
+    
+                /// start blog
+        fwrite($bf, start_tag("BLOG",$level,true));
+                /// blog body
+        fwrite ($bf,full_tag("ID",$level+1,false,$blog->id));
+        fwrite ($bf,full_tag("MODULE",$level+1,false,$blog->module));
+        fwrite ($bf,full_tag("USERID",$level+1,false,$blog->userid));
+        fwrite ($bf,full_tag("COURSEID",$level+1,false,$blog->courseid));
+        fwrite ($bf,full_tag("GROUPID",$level+1,false,$blog->groupid));
+        fwrite ($bf,full_tag("MODULEID",$level+1,false,$blog->moduleid));
+        fwrite ($bf,full_tag("COURSEMODULEID",$level+1,false,$blog->coursemoduleid));
+        fwrite ($bf,full_tag("SUBJECT",$level+1,false,$blog->subject));
+        fwrite ($bf,full_tag("SUMMARY",$level+1,false,$blog->summary));
+        fwrite ($bf,full_tag("CONTENT",$level+1,false,$blog->content));
+        fwrite ($bf,full_tag("UNIQUEHASH",$level+1,false,$blog->uniquehash));
+        fwrite ($bf,full_tag("RATING",$level+1,false,$blog->rating));
+        fwrite ($bf,full_tag("FORMAT",$level+1,false,$blog->format));
+        fwrite ($bf,full_tag("ATTACHMENT",$level+1,false,$blog->attachment));
+        fwrite ($bf,full_tag("PUBLISHSTATE",$level+1,false,$blog->publishstate));
+        fwrite ($bf,full_tag("LASTMODIFIED",$level+1,false,$blog->lastmodified));
+        fwrite ($bf,full_tag("CREATED",$level+1,false,$blog->created));
+        fwrite ($bf,full_tag("USERMODIFIED",$level+1,false,$blog->usermodified));
+
+        /// Blog tags
+        /// Check if we have blog tags to backup
+        if (!empty($CFG->usetags)) {
+            if ($tags = tag_get_tags('post', $blog->id)) { //This return them ordered by default
+            /// Start BLOG_TAGS tag
+                fwrite ($bf,start_tag("BLOG_TAGS",$level+1,true));
+            /// Write blog tags fields
+                foreach ($tags as $tag) {
+                    fwrite ($bf,start_tag("BLOG_TAG",$level+2,true));
+                    fwrite ($bf,full_tag("NAME",$level+3,false,$tag->name));
+                    fwrite ($bf,full_tag("RAWNAME",$level+3,false,$tag->rawname));
+                    fwrite ($bf,end_tag("BLOG_TAG",$level+2,true));
+                }
+            /// End BLOG_TAGS tag
+                fwrite ($bf,end_tag("BLOG_TAGS",$level+1,true));
+            }
+        } 
+        /// end blog
+        fwrite($bf, end_tag("BLOG",$level,true));
+    }
+    
+    
+
     /**
      * Prints course's blocks info (table block_instance)
      */
                 }
             }
 
+            //Backup course blog assignment data, if any.
+            if (!defined('BACKUP_SILENTLY')) {
+                echo '<li>'.get_string("courseblogdata").'</li>';
+            }
+            if($status) {
+                if (!$status = backup_course_blogs($backup_file,$preferences)) {
+                    if (!defined('BACKUP_SILENTLY')) {
+                        notify("An error occurred while backing up the course blog assignment data");
+                    }
+                    else {
+                        $errorstr = "An error occurred while backing up the course blog assignment data";
+                        return false;
+                    }
+                }
+            }
+
+
             //Prints course end
             if ($status) {
                 if (!$status = backup_course_end($backup_file,$preferences)) {
diff --git a/blocks/blog_externals/block_blog_externals.php b/blocks/blog_externals/block_blog_externals.php
new file mode 100644 (file)
index 0000000..86ed24f
--- /dev/null
@@ -0,0 +1,92 @@
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+
+/**
+ * Block for managing external blogs. This block will appear only on a user's blog page, not
+ * on any other blog listing page (site, course, module etc). It may be filtered by tag.
+ *
+ * @package    moodlecore
+ * @subpackage blog
+ * @copyright  2009 Nicolas Connault
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+require_once($CFG->dirroot .'/blog/lib.php');
+
+/**
+ * External Blog Block class
+ */
+class block_blog_externals extends block_base {
+
+    function init() {
+        global $USER, $DB;
+
+        $this->title = get_string('blockexternalstitle', 'blog');
+        $this->content_type = BLOCK_TYPE_TEXT;
+        $this->version = 2009101509;
+
+        // See if a deletion has been requested
+        $delete = optional_param('delete_blog_external', false, PARAM_INT);
+        if ($delete && ($external_blog = $DB->get_record('blog_external', array('id' => $delete)))) {
+            // Check caps and userid matching $USER->id
+            if ($external_blog->userid == $USER->id) {
+                $DB->delete_records('blog_external', array('id' => $delete));
+            }
+        }
+    }
+
+    function get_content() {
+        global $CFG, $USER, $DB, $PAGE, $OUTPUT;
+
+        // This block should not appear if $CFG->useexternalblogs is off
+        if (empty($CFG->bloglevel)) {
+            $this->content->text = '';
+            return $this->content;
+        }
+
+        // don't display menu block if block is set at site level, and user is not logged in
+        if ($CFG->bloglevel < BLOG_GLOBAL_LEVEL && !(isloggedin() && !isguest())) {
+            $this->content->text = '';
+            return $this->content;
+        }
+
+        $output = '';
+
+        $this->content = new stdClass;
+        $this->content->footer = '';
+
+        $external_blogs = $DB->get_records('blog_external', array('userid' => $USER->id));
+
+        $external_blog_url = $CFG->wwwroot.'/blog/external.php?returnurl='.urlencode($PAGE->url->out());
+
+        foreach ($external_blogs as $id => $eb) {
+            $strdelete = get_string('delete') . " $eb->name";
+
+            $delete_url = new moodle_url();
+            $delete_url->param('delete_blog_external', $id);
+            $deleteicon = '<a href="'.$delete_url->out().'" class="delete">' .
+                              '<img src="'.$OUTPUT->old_icon_url('t/delete').'" alt="'.$strdelete.'" title="'.$strdelete.'" />' .
+                          "</a>\n";
+            $output .= '<li><a href="'.$external_blog_url.'&amp;id='.$id.'" title="'.$eb->name.'">'.shorten_text($eb->name, 20)."</a>$deleteicon</li>\n";
+        }
+
+        $this->content->text = '<ul class="list">'. $output ."</ul>\n";
+        $this->content->text .= '<div class="newlink"><a href="'.$external_blog_url.'">'.get_string('addnewexternalblog', 'blog').'</a></div>';
+        return $this->content;
+    }
+}
index 2967304084f67b2a1acf625122492149073e413a..19823d92e3ed9799d90430cec76c2c1d0cf174c9 100755 (executable)
@@ -1,4 +1,30 @@
-<?php //$Id$
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+
+/**
+ * Blog Menu Block page.
+ *
+ * @package    moodlecore
+ * @subpackage blog
+ * @copyright  2009 Nicolas Connault
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
 
 require_once($CFG->dirroot .'/blog/lib.php');
 
@@ -6,12 +32,29 @@ class block_blog_menu extends block_base {
 
     function init() {
         $this->title = get_string('blockmenutitle', 'blog');
-        $this->content_type = BLOCK_TYPE_TEXT;
-        $this->version = 2007101509;
+        $this->version = 2009071700;
+    }
+
+    function instance_allow_multiple() {
+        return true;
+    }
+
+    function has_config() {
+        return false;
+    }
+
+    function applicable_formats() {
+        return array('all' => true, 'my' => false, 'tag' => false);
+    }
+
+    function instance_allow_config() {
+        return true;
     }
 
     function get_content() {
-        global $CFG, $USER;
+        global $CFG, $USER, $PAGE;
+
+        $context = $PAGE->get_context();
 
         if (empty($CFG->bloglevel)) {
             $this->content->text = '';
@@ -24,95 +67,88 @@ class block_blog_menu extends block_base {
             return $this->content;
         }
 
-        if (!isset($userBlog)) {
-            $userBlog ->userid = 0;
-        }
-
-        if (!empty($USER->id)) {
-            $userBlog->userid = $USER->id;
-        }   //what is $userBlog anyway
-        if($this->content !== NULL) {
-            return $this->content;
-        }
-
         $output = '';
 
         $this->content = new stdClass;
         $this->content->footer = '';
 
-        //if ( blog_isLoggedIn() && !isguest() ) {
-            $courseviewlink = '';
-            $addentrylink = '';
-            $coursearg = '';
+        $viewblogentries_url = blog_get_context_url();
+        $strlevel = '';
+
+        switch ($context->contextlevel) {
+            case CONTEXT_COURSE:
+                $strlevel = ($context->instanceid == SITEID) ? '' : get_string('course');
+                break;
+            case CONTEXT_MODULE:
+                $strlevel = print_context_name($context);
+                break;
+            case CONTEXT_USER:
+                $strlevel = get_string('user');
+                break;
+        }
 
-            $sitecontext = get_context_instance(CONTEXT_SYSTEM);
+        $canviewblogs = has_capability('moodle/blog:view', $context);
 
-            if ($this->page->course->id != SITEID) {
+        /// Accessibility: markup as a list.
 
-                $incoursecontext = true;
-                $curcontext = get_context_instance(CONTEXT_COURSE, $this->page->course->id);
-            } else {
-                $incoursecontext = false;
-                $curcontext = $sitecontext;
-            }
+        $blogmodon = false;
 
-            $canviewblogs = has_capability('moodle/blog:view', $curcontext);
+        if (!empty($strlevel)) {
+            $output = '<li><a href="'.$viewblogentries_url.'">'.get_string('viewblogentries', 'blog', $strlevel).'</a></li>';
+        }
 
-            /// Accessibility: markup as a list.
+        $parts = array();
+        $query = parse_url($viewblogentries_url);
 
-            if ( (isloggedin() && !isguest()) && $incoursecontext
-                    && $CFG->bloglevel >= BLOG_COURSE_LEVEL && $canviewblogs) {
+        if (!empty($query['query'])) {
+            parse_str($query['query'], $parts);
+        }
 
-                $coursearg = '&amp;courseid='.$this->page->course->id;
-                // a course is specified
+        // show View site entries link
+        if ($CFG->bloglevel >= BLOG_SITE_LEVEL && $canviewblogs) {
+            $output .= '<li><a href="'. $CFG->wwwroot .'/blog/index.php">';
+            $output .= get_string('viewsiteentries', 'blog')."</a></li>\n";
+        }
 
-                $courseviewlink = '<li><a href="'. $CFG->wwwroot .'/blog/index.php?filtertype=course&amp;filterselect='. $this->page->course->id .'">';
-                $courseviewlink .= get_string('viewcourseentries', 'blog') ."</a></li>\n";
-            }
+        $output .= '';
 
-            $blogmodon = false;
-
-            if ( (isloggedin() && !isguest())
-                        && (!$blogmodon || ($blogmodon && $coursearg != ''))
-                        && $CFG->bloglevel >= BLOG_USER_LEVEL ) {
-
-                // show Add entry link
-                if (has_capability('moodle/blog:create', $sitecontext)) {
-                    $addentrylink = '<li><a href="'. $CFG->wwwroot. '/blog/edit.php?action=add'
-                                   .$coursearg.'">'.get_string('addnewentry', 'blog') ."</a></li>\n";
-                }
-                // show View my entries link
-                $addentrylink .= '<li><a href="'. $CFG->wwwroot .'/blog/index.php?userid='.
-                                 $userBlog->userid.'">'.get_string('viewmyentries', 'blog').
-                                 "</a></li>\n";
-
-                // show link to manage blog prefs
-                $addentrylink .= '<li><a href="'. $CFG->wwwroot. '/blog/preferences.php?userid='.
-                                 $userBlog->userid . $coursearg .'">'.
-                                 get_string('blogpreferences', 'blog')."</a></li>\n";
-
-                $output = $addentrylink;
-                $output .= $courseviewlink;
+        // show View my entries link
+        if ($context->contextlevel != CONTEXT_USER) {
+            $output .= '<li><a href="'. $CFG->wwwroot .'/blog/index.php?userid='. $USER->id;
+
+            foreach ($parts as $var => $val) {
+                $output .= "&amp;$var=$val";
             }
+            $output .= '">'.get_string('viewmyentries', 'blog').  "</a></li>\n";
+        }
 
-            // show View site entries link
-            if ($CFG->bloglevel >= BLOG_SITE_LEVEL && $canviewblogs) {
-                $output .= '<li><a href="'. $CFG->wwwroot .'/blog/index.php?filtertype=site&amp;">';
-                $output .= get_string('viewsiteentries', 'blog')."</a></li>\n";
+        // show link to manage blog prefs
+        $output .= '<li><a href="'. $CFG->wwwroot. '/blog/preferences.php?userid='.
+                         $USER->id .'">'.
+                         get_string('blogpreferences', 'blog')."</a></li>\n";
+
+        // show Add entry link
+        $sitecontext = get_context_instance(CONTEXT_SYSTEM);
+        if (has_capability('moodle/blog:create', $sitecontext)) {
+            $output .= '<li><a href="'. $CFG->wwwroot. '/blog/edit.php?action=add';
+            foreach ($parts as $var => $val) {
+                $output .= "&amp;$var=$val";
             }
+            $output .= '">'.get_string('addnewentry', 'blog') ."</a></li>\n";
+        }
 
-            // took out tag management interface/link, should use tag/manage.php
+        // Full-text search field
 
-            // show Help with blogging link
-            //$output .= '<li><a href="'. $CFG->wwwroot .'/help.php?module=blog&amp;file=user.html">';
-            //$output .= get_string('helpblogging', 'blog') ."</a></li>\n";
-        //} else {
-        //    $output = ''; //guest users and users who are not logged in do not get menus
-        //}
+        $output .= '<li><form method="get" action="'.$viewblogentries_url.'">';
+        $output .= '<div><input type="text" name="search" /><input type="submit" value="'.get_string('search').'" />';
 
+        if (!empty($parts)) {
+            foreach ($parts as $var => $val) {
+                $output .= '<input type="hidden" name="'.$var.'" value="'.$val.'" />';
+            }
+        }
+
+        $output .= '</div></form></li>';
         $this->content->text = '<ul class="list">'. $output ."</ul>\n";
-        return $this->content;
     }
 }
-
-?>
diff --git a/blocks/blog_recent/block_blog_recent.php b/blocks/blog_recent/block_blog_recent.php
new file mode 100644 (file)
index 0000000..9e89574
--- /dev/null
@@ -0,0 +1,112 @@
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+
+/**
+ * Recent Blog Entries Block page.
+ *
+ * @package    moodlecore
+ * @subpackage blog
+ * @copyright  2009 Nicolas Connault
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+require_once($CFG->dirroot .'/blog/lib.php');
+require_once($CFG->dirroot .'/blog/locallib.php');
+
+/**
+ * This block simply outputs a list of links to recent blog entries, depending on
+ * the context of the current page.
+ */
+class block_blog_recent extends block_base {
+
+    function init() {
+        $this->title = get_string('blockrecenttitle', 'blog');
+        $this->content_type = BLOCK_TYPE_TEXT;
+        $this->version = 2009070900;
+    }
+
+    function get_content() {
+        global $CFG, $USER, $PAGE, $DB;
+
+        $this->content = new stdClass();
+        $this->content->footer = '';
+
+        $tag     = optional_param('tag', null, PARAM_NOTAGS);
+        $tagid   = optional_param('tagid', null, PARAM_INT);
+        $entryid = optional_param('entryid', null, PARAM_INT);
+        $groupid = optional_param('groupid', null, PARAM_INT);
+        $search  = optional_param('search', null, PARAM_RAW);
+
+        //correct tagid if a text tag is provided as a param
+        if (!empty($tag)) {  //text tag parameter takes precedence
+            if ($tagrec = $DB->get_record_sql("SELECT * FROM {tag} WHERE name LIKE ?", array($tag))) {
+                $tagid = $tagrec->id;
+            } else {
+                unset($tagid);
+            }
+        }
+
+        $context = $PAGE->get_context();
+        
+        $strlevel = '';
+
+        switch ($context->contextlevel) {
+            case CONTEXT_COURSE:
+                $strlevel = ($context->instanceid == SITEID) ? '' : get_string('course');
+                break;
+            case CONTEXT_MODULE:
+                $strlevel = print_context_name($context);
+                break;
+            case CONTEXT_USER:
+                $strlevel = get_string('user');
+                break;
+        }
+
+        $filters = array();
+
+        if (!empty($entryid)) {
+            $filters['entry'] = $entryid;
+        }
+
+        if (!empty($groupid)) {
+            $filters['group'] = $groupid;
+        }
+
+        if (!empty($tagid)) {
+            $filters['tag'] = $tagid;
+        }
+
+        if (!empty($search)) {
+            $filters['search'] = $search;
+        }
+
+        $blog_listing = new blog_listing($filters);
+        $entries = $blog_listing->get_entries(0, get_user_preferences('blogrecententriesnumber', 4));
+
+        $this->content->text = '<ul class="list">';
+        $viewblog_url = $CFG->wwwroot . '/blog/index.php?entryid=';
+
+        foreach ($entries as $entry_id => $entry) {
+            $this->content->text .= "<li><a href=\"$viewblog_url$entry_id\">".shorten_text($entry->subject)."</a></li>\n";
+        }
+
+        $this->content->text .= '<li>&nbsp;</li>';
+        $this->content->text .= '<li><a href="'.blog_get_context_url().'">'.get_string('viewallblogentries', 'blog', $strlevel).'</a></li>'; 
+        $this->content->text .= '</ul>';
+    }
+}
index e27b5315c2624da44feb9bed80ed97eff70dd078..f53203f2c80c2b8df4245808cc6cc60a9dd7a835 100644 (file)
@@ -38,7 +38,7 @@ class block_tags extends block_base {
 
     function get_content() {
 
-        global $CFG, $SITE, $USER, $SCRIPT, $OUTPUT;
+        global $CFG, $COURSE, $SITE, $USER, $SCRIPT, $OUTPUT;
 
         if (empty($CFG->usetags)) {
             $this->content->text = '';
@@ -237,7 +237,7 @@ class block_tags extends block_base {
                         <form action="{$CFG->wwwroot}/tag/coursetags_add.php" method="post" id="coursetag"
                                 onsubmit="return ctags_checkinput(this.coursetag_new_tag.value)">
                             <div style="display: none;">
-                                <input type="hidden" name="entryid" value="$this->page->course->id" />
+                                <input type="hidden" name="entryid" value="$COURSE->id" />
                                 <input type="hidden" name="userid" value="$USER->id" />
                                 <input type="hidden" name="sesskey" value="$sesskey" />
                             </div>
index 97d5516c685549d943db25b4d3bd4c004f3a61ea..6b37aa5ec88ed10174d41193e65d5296088fd47e 100755 (executable)
@@ -1,14 +1,42 @@
-<?php //$Id$
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
+
+/**
+ * Blog entry edit page
+ *
+ * @package    moodlecore
+ * @subpackage blog
+ * @copyright  2009 Nicolas Connault
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
 require_once('../config.php');
 include_once('lib.php');
+include_once('locallib.php');
 include_once($CFG->dirroot.'/tag/lib.php');
 
 $action   = required_param('action', PARAM_ALPHA);
 $id       = optional_param('id', 0, PARAM_INT);
 $confirm  = optional_param('confirm', 0, PARAM_BOOL);
+$modid    = optional_param('modid', 0, PARAM_INT);
 $courseid = optional_param('courseid', 0, PARAM_INT); // needed for user tab - does nothing here
 
+$PAGE->set_url('blog/edit.php', compact('id', 'action', 'confirm', 'modid', 'courseid'));
+
 require_login($courseid);
 
 if (empty($CFG->bloglevel)) {
@@ -16,52 +44,64 @@ if (empty($CFG->bloglevel)) {
 }
 
 if (isguest()) {
-    print_error('noguestpost', 'blog');
+    print_error('noguestentry', 'blog');
 }
 
 $sitecontext = get_context_instance(CONTEXT_SYSTEM);
-if (!has_capability('moodle/blog:create', $sitecontext) and !has_capability('moodle/blog:manageentries', $sitecontext)) {
-    print_error('cannoteditpostorblog');
+if (!has_capability('moodle/blog:create', $sitecontext) && !has_capability('moodle/blog:manageentries', $sitecontext)) {
+    print_error('cannoteditentryorblog');
 }
 
+$returnurl = new moodle_url($CFG->wwwroot . '/blog/index.php');
+
 // Make sure that the person trying to edit have access right
 if ($id) {
-    if (!$existing = $DB->get_record('post', array('id'=>$id))) {
-        print_error('wrongpostid', 'blog');
+    if (!$existing = new blog_entry($id)) {
+        print_error('wrongentryid', 'blog');
     }
 
-    if (!blog_user_can_edit_post($existing)) {
+    if (!blog_user_can_edit_entry($existing)) {
         print_error('notallowedtoedit', 'blog');
     }
     $userid    = $existing->userid;
-    $returnurl = $CFG->wwwroot.'/blog/index.php?userid='.$existing->userid;
+    $returnurl->param('userid', $existing->userid);
 } else {
     if (!has_capability('moodle/blog:create', $sitecontext)) {
-        print_error('nopost', 'blog'); // manageentries is not enough for adding
+        print_error('noentry', 'blog'); // manageentries is not enough for adding
     }
     $existing  = false;
     $userid    = $USER->id;
-    $returnurl = 'index.php?userid='.$USER->id;
+    $returnurl->param('userid', $userid);
 }
-if (!empty($courseid)) {
-    $returnurl .= '&amp;courseid='.$courseid;
+
+if (!empty($courseid) && empty($modid)) {
+    $returnurl->param('courseid', $courseid);
+    $PAGE->set_context(get_context_instance(CONTEXT_COURSE, $courseid));
 }
 
+// If a modid is given, guess courseid
+if (!empty($modid)) {
+    $returnurl->param('modid', $modid);
+    $courseid = $DB->get_field('course_modules', 'course', array('id' => $modid)); 
+    $returnurl->param('courseid', $courseid);
+    $PAGE->set_context(get_context_instance(CONTEXT_MODULE, $modid));
+}
 
 $strblogs = get_string('blogs','blog');
 
 if ($action === 'delete'){
     if (!$existing) {
-        print_error('wrongpostid', 'blog');
+        print_error('wrongentryid', 'blog');
     }
-    if (data_submitted() and $confirm and confirm_sesskey()) {
-        do_delete($existing);
+    if (data_submitted() && $confirm && confirm_sesskey()) {
+        $existing->delete();
         redirect($returnurl);
     } else {
         $optionsyes = array('id'=>$id, 'action'=>'delete', 'confirm'=>1, 'sesskey'=>sesskey(), 'courseid'=>$courseid);
         $optionsno = array('userid'=>$existing->userid, 'courseid'=>$courseid);
         print_header("$SITE->shortname: $strblogs", $SITE->fullname);
-        blog_print_entry($existing);
+        //blog_print_entry($existing);
+        $existing->print_html();
         echo '<br />';
         echo $OUTPUT->confirm(get_string('blogdeleteconfirm', 'blog'), new moodle_url('edit.php', $optionsyes),new moodle_url( 'index.php', $optionsno));
         echo $OUTPUT->footer();
@@ -70,22 +110,52 @@ if ($action === 'delete'){
 }
 
 require_once('edit_form.php');
-$blogeditform = new blog_edit_form(null, compact('existing', 'sitecontext'));
+
+if (!empty($existing)) {
+    $assignmentdata = $DB->get_record_sql('SELECT a.timedue, a.preventlate, a.emailteachers, a.var2, asub.grade
+                                           FROM {assignment} a, {assignment_submissions} as asub WHERE
+                                           a.id = asub.assignment AND userid = '.$USER->id.' AND a.assignmenttype = \'blog\'
+                                           AND asub.data1 = \''.$existing->id.'\'');
+
+    if ($blogassociations = $DB->get_records('blog_association', array('blogid' => $existing->id))) {
+
+        foreach ($blogassociations as $assocrec) {
+            $contextrec = $DB->get_record('context', array('id' => $assocrec->contextid));
+
+            switch ($contextrec->contextlevel) {
+                case CONTEXT_COURSE:
+                    $existing->courseassoc = $assocrec->contextid;
+                    break;
+                case CONTEXT_MODULE:
+                    $existing->modassoc[] = $assocrec->contextid;
+                    break;
+            }
+        }
+    }
+}
+
+$textfieldoptions = array('trusttext'=>true, 'subdirs'=>true);
+$blogeditform = new blog_edit_form(null, compact('existing', 'sitecontext', 'assignmentdata', 'textfieldoptions'));
+
+$existing = file_prepare_standard_editor($existing, 'summary', $textfieldoptions, $PAGE->get_context());
 
 if ($blogeditform->is_cancelled()){
     redirect($returnurl);
 } else if ($fromform = $blogeditform->get_data()){
+    $fromform = file_postupdate_standard_editor($fromform, 'summary', $textfieldoptions, $PAGE->get_context());
+
     //save stuff in db
     switch ($action) {
         case 'add':
-            do_add($fromform, $blogeditform);
+            $blog_entry = new blog_entry($fromform, $blogeditform);
+            $blog_entry->add();
         break;
 
         case 'edit':
             if (!$existing) {
-                print_error('wrongpostid', 'blog');
+                print_error('wrongentryid', 'blog');
             }
-            do_edit($fromform, $blogeditform);
+            $existing->edit($fromform, $blogeditform);
         break;
         default :
             print_error('invalidaction');
@@ -98,115 +168,83 @@ if ($blogeditform->is_cancelled()){
 switch ($action) {
     case 'add':
         // prepare new empty form
-        $post->publishstate = 'site';
+        $entry->publishstate = 'site';
         $strformheading = get_string('addnewentry', 'blog');
-        $post->action       = $action;
-    break;
+        $entry->action       = $action;
+
+        if ($courseid) {  //pre-select the course for associations
+            $context = get_context_instance(CONTEXT_COURSE, $courseid);
+            $entry->courseassoc = $context->id;
+        }
+
+        if ($modid) { //pre-select the mod for associations
+            $context = get_context_instance(CONTEXT_MODULE, $modid);
+            $entry->modassoc = array($context->id);
+        }
+        break;
 
     case 'edit':
         if (!$existing) {
-            print_error('wrongpostid', 'blog');
+            print_error('wrongentryid', 'blog');
         }
-        $post->id           = $existing->id;
-        $post->subject      = $existing->subject;
-        $post->summary      = $existing->summary;
-        $post->publishstate = $existing->publishstate;
-        $post->format       = $existing->format;
-        $post->tags = tag_get_tags_array('post', $post->id);
-        $post->action       = $action;
+
+        $entry->id           = $existing->id;
+        $entry->subject      = $existing->subject;
+        $entry->fakesubject  = $existing->subject;
+        $entry->summary      = $existing->summary;
+        $entry->fakesummary  = $existing->summary;
+        $entry->publishstate = $existing->publishstate;
+        $entry->format       = $existing->format;
+        $entry->tags         = tag_get_tags_array('post', $entry->id);
+        $entry->action       = $action;
+
+        if (!empty($existing->courseassoc)) {
+            $entry->courseassoc = $existing->courseassoc;
+        }
+
+        if (!empty($existing->modassoc)) {
+            $entry->modassoc = $existing->modassoc;
+        }
+
         $strformheading = get_string('updateentrywithid', 'blog');
 
-    break;
+        break;
     default :
         print_error('unknowaction');
 }
 
-// done here in order to allow deleting of posts with wrong user id above
+// Add filter params for return url
+$entry->modid = $modid;
+$entry->courseid = $courseid;
+
+$PAGE->requires->data_for_js('blog_edit_existing', $entry);
+
+// done here in order to allow deleting of entries with wrong user id above
 if (!$user = $DB->get_record('user', array('id'=>$userid))) {
     print_error('invaliduserid');
 }
+
+$blog_headers = blog_get_headers();
+
+$navigation = build_navigation($blog_headers['navlinks'], $blog_headers['cm']);
+/*
 $navlinks = array();
 $navlinks[] = array('name' => fullname($user), 'link' => "$CFG->wwwroot/user/view.php?id=$userid", 'type' => 'misc');
 $navlinks[] = array('name' => $strblogs, 'link' => "$CFG->wwwroot/blog/index.php?userid=$userid", 'type' => 'misc');
 $navlinks[] = array('name' => $strformheading, 'link' => null, 'type' => 'misc');
 $navigation = build_navigation($navlinks);
+*/
+$PAGE->requires->js('blog/edit_form.js'); 
+$PAGE->set_title($blog_headers['title']);
+$PAGE->set_heading($blog_headers['title']);
+
+echo $OUTPUT->header($navigation);
 
-print_header("$SITE->shortname: $strblogs", $SITE->fullname, $navigation,'','',true);
-$blogeditform->set_data($post);
+$blogeditform->set_data($entry);
 $blogeditform->display();
 
+$PAGE->requires->js_function_call('select_initial_course');
 
 echo $OUTPUT->footer();
 
-
 die;
-
-/*****************************   edit.php functions  ***************************/
-
-/**
-* Delete blog post from database
-*/
-function do_delete($post) {
-    global $returnurl, $DB;
-
-    blog_delete_attachments($post);
-
-    $status = $DB->delete_records('post', array('id'=>$post->id));
-    tag_set('post', $post->id, array());
-    
-    add_to_log(SITEID, 'blog', 'delete', 'index.php?userid='. $post->userid, 'deleted blog entry with entry id# '. $post->id);
-}
-
-/**
- * Write a new blog entry into database
- */
-function do_add($post, $blogeditform) {
-    global $CFG, $USER, $returnurl, $DB;
-
-    $post->module       = 'blog';
-    $post->userid       = $USER->id;
-    $post->lastmodified = time();
-    $post->created      = time();
-
-    // Insert the new blog entry.
-    $post->id = $DB->insert_record('post', $post);
-    // Add blog attachment
-    if ($blogeditform->get_new_filename('attachment')) {
-        if ($blogeditform->save_stored_file('attachment', SYSCONTEXTID, 'blog', $post->id, '/', false, $USER->id)) {
-            $DB->set_field("post", "attachment", 1, array("id"=>$post->id));
-        }
-    }
-
-    // Update tags.
-    tag_set('post', $post->id, $post->tags);
-
-    add_to_log(SITEID, 'blog', 'add', 'index.php?userid='.$post->userid.'&postid='.$post->id, $post->subject);
-}
-
-/**
- * @param . $post argument is a reference to the post object which is used to store information for the form
- * @param . $bloginfo_arg argument is reference to a blogInfo object.
- * @todo complete documenting this function. enable trackback and pingback between entries on the same server
- */
-function do_edit($post, $blogeditform) {
-    global $CFG, $USER, $returnurl, $DB;
-
-    $post->lastmodified = time();
-
-    if ($blogeditform->get_new_filename('attachment')) {
-        blog_delete_attachments($post);
-        if ($blogeditform->save_stored_file('attachment', SYSCONTEXTID, 'blog', $post->id, '/', false, $USER->id)) {
-            $post->attachment = 1;
-        } else {
-            $post->attachment = 1;
-        }
-    }
-
-    // Update record
-    $DB->update_record('post', $post);
-    tag_set('post', $post->id, $post->tags);
-
-    add_to_log(SITEID, 'blog', 'update', 'index.php?userid='.$USER->id.'&postid='.$post->id, $post->subject);
-}
-
-?>
diff --git a/blog/edit_form.js b/blog/edit_form.js
new file mode 100644 (file)
index 0000000..69a9abb
--- /dev/null
@@ -0,0 +1,80 @@
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+//add function to clear the list of context associations
+function emptyAssocList() {
+    var modassoc = document.getElementById('id_modassoc');
+    var options = modassoc.getElementsByTagName('option');
+    while (options.length > 0) {
+        var option = options[0];
+        modassoc.removeChild(option);
+    }
+}
+
+//add function for adding an element to the list of context associations
+function addModAssoc(name, id) {
+    var modassoc = document.getElementById('id_modassoc');
+    newoption = document.createElement('option');
+    newoption.text = name;
+    newoption.value = id;
+
+    try {
+        modassoc.add(newoption, null);  //standard, broken in IE
+    } catch(ex) {
+        modassoc.add(newoption);
+    }
+}
+
+//add function to add associations for a particular course
+function addCourseAssociations() {
+    var courses = document.getElementById('id_courseassoc');
+    var course = courses.options[courses.selectedIndex].value;
+    var modassoc = document.getElementById('id_modassoc');
+    var newoption = null;
+
+    emptyAssocList(); 
+    
+    for (var mycourse in blog_edit_form_modnames) {
+        if (mycourse == course) {
+            for (var modid in blog_edit_form_modnames[mycourse]) {
+                addModAssoc(blog_edit_form_modnames[mycourse][modid], modid);
+            }
+        }
+    }
+}
+
+function select_initial_course() {
+    var course = document.getElementById('id_courseassoc');
+    var mods = document.getElementById('id_modassoc');
+    var i = 0;
+    var j = 0;
+    emptyAssocList();
+
+    for (i = 0; i < course.length; i++) {
+        if (course.options[i].value == blog_edit_existing.courseassoc) {
+            course.selectedIndex = i;
+            addCourseAssociations();
+            
+            for (j = 0; j < mods.length; j++) {
+                for (var modid in blog_edit_existing.modassoc) {
+                    if (mods.options[j].value == blog_edit_existing.modassoc[modid]) {
+                        mods.options[j].selected = true;
+                    }
+                }
+            }
+        }
+    }
+}
+
index 2c26d0e456d38e50b41dfdbdcee76deff821352b..00b82f6650908d030e85b89d02c67a0070352e49 100644 (file)
@@ -1,32 +1,91 @@
-<?php  // $Id$
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
 require_once($CFG->libdir.'/formslib.php');
 
 class blog_edit_form extends moodleform {
+    public $modnames = array();
 
     function definition() {
-        global $CFG, $COURSE, $USER;
+        global $CFG, $COURSE, $USER, $DB, $PAGE;
 
         $mform    =& $this->_form;
 
-        $post = $this->_customdata['existing'];
+        $existing       = $this->_customdata['existing'];
+        $summaryoptions = $this->_customdata['textfieldoptions'];
+
+        if (!empty($this->_customdata['assignmentdata'])) {
+            $assignmentdata = $this->_customdata['assignmentdata'];
+        }
+
+        $existing = $this->_customdata['existing'];
         $sitecontext = $this->_customdata['sitecontext'];
 
+        //determine if content elements should be deactivated for a past due blog assignment
+        $noedit = false;
+        if (!empty($assignmentdata)) {
+            if ((time() > $assignmentdata->timedue && $assignmentdata->preventlate) || $assignmentdata->grade != -1) {
+                $noedit = true;
+            }
+        }
+
         $mform->addElement('header', 'general', get_string('general', 'form'));
-        $mform->addElement('text', 'subject', get_string('entrytitle', 'blog'), 'size="60"');
+
+        if ($noedit) { //show disabled form elements, but provide hidden elements so that the data is transferred
+            $mform->addElement('text', 'fakesubject', get_string('entrytitle', 'blog'), array('size'=>60, 'disabled'=>'disabled'));
+            $mform->addElement('textarea', 'fakesummary', get_string('entrybody', 'blog'), array('rows'=>25, 'cols'=>40, 'disabled'=>'disabled'));
+            $mform->setHelpButton('fakesummary', array('writing', 'richtext'), false, 'editorhelpbutton');
+            $mform->addElement('hidden', 'subject');
+            $mform->addElement('hidden', 'summary');
+
+        } else {  //insert normal form elements
+            $mform->addElement('text', 'subject', get_string('entrytitle', 'blog'), 'size="60"');
+            $textfieldoptions = array('trusttext'=>true, 'subdirs'=>true);
+            $mform->addElement('editor', 'summary_editor', get_string('entrybody', 'blog'), null, $summaryoptions);
+        }
+
         $mform->setType('subject', PARAM_TEXT);
         $mform->addRule('subject', get_string('emptytitle', 'blog'), 'required', null, 'client');
 
-        $mform->addElement('htmleditor', 'summary', get_string('entrybody', 'blog'), array('rows'=>25));
-        $mform->setType('summary', PARAM_RAW);
-        $mform->addRule('summary', get_string('emptybody', 'blog'), 'required', null, 'client');
-        $mform->setHelpButton('summary', array('writing', 'richtext2'), false, 'editorhelpbutton');
+        $mform->setType('summary_editor', PARAM_RAW);
+        $mform->addRule('summary_editor', get_string('emptybody', 'blog'), 'required', null, 'client');
+        $mform->setHelpButton('summary_editor', array('writing', 'richtext2'), false, 'editorhelpbutton');
 
         $mform->addElement('format', 'format', get_string('format'));
 
         $mform->addElement('file', 'attachment', get_string('attachment', 'forum'));
 
-        $mform->addElement('select', 'publishstate', get_string('publishto', 'blog'), blog_applicable_publish_states());
+        //disable publishstate options that are not allowed
+        $publishstates = array();
+        $i = 0;
+
+        foreach (blog_entry::get_applicable_publish_states() as $state => $desc) {
+            if (!empty($assignmentdata)) {
+                if ($i <= $assignmentdata->var2)  { //var2 is the maximum publish state allowed
+                    $publishstates[$state] = $desc;
+                }
+            } else {
+                $publishstates[$state] = $desc;   //no maximum was set
+            }
+
+            $i++;
+        }
+
+        $mform->addElement('select', 'publishstate', get_string('publishto', 'blog'), $publishstates);
         $mform->setHelpButton('publishstate', array('publish_state', get_string('publishto', 'blog'), 'blog'));
 
 
@@ -35,6 +94,48 @@ class blog_edit_form extends moodleform {
             $mform->addElement('tags', 'tags', get_string('tags'));
         }
 
+        $allmodnames = array();
+
+        if (!empty($CFG->useblogassociations)) {
+            $mform->addElement('header', 'assochdr', get_string('associations', 'blog'));
+
+            if (has_capability('moodle/site:doanything', get_context_instance(CONTEXT_USER, $USER->id))) {
+                $courses = get_courses('all', 'visible DESC, fullname ASC');
+            } else {
+                $courses = get_my_courses($USER->id, 'visible DESC, fullname ASC');
+            }
+
+            $course_names[0] = 'none';
+
+            if (!empty($courses)) {
+
+                foreach ($courses as $course) {
+                    $course_names[$course->context->id] = $course->fullname;
+                    $modinfo = get_fast_modinfo($course, $USER->id);
+                    $course_context_path = $DB->get_field('context', 'path', array('id' => $course->context->id));
+
+                    foreach ($modinfo->instances as $modname => $instances) {
+
+                        foreach ($instances as $modid => $mod) {
+                            $mod_context_id = $DB->get_field_select('context', 'id',
+                                'instanceid = '.$mod->id.' AND ' .
+                                'contextlevel = ' . CONTEXT_MODULE . ' AND ' .
+                                'path LIKE \''.$course_context_path.'/%\'');
+
+                            $mod_string = $mod->name . ' (' . get_plugin_name($modname) . ')';
+                            $this->modnames[$course->context->id][$mod_context_id] = $mod_string;
+                            $allmodnames[$mod_context_id] = $course->shortname . " - " . $mod_string;
+                        }
+                    }
+                }
+            }
+            $mform->addElement('select', 'courseassoc', get_string('course'), $course_names, 'onchange="addCourseAssociations()"');
+            $selectassoc = &$mform->addElement('select', 'modassoc', get_string('managemodules'), $allmodnames);
+            $selectassoc->setMultiple(true);
+            $PAGE->requires->data_for_js('blog_edit_form_modnames', $this->modnames);
+
+        }
+
         $this->add_action_buttons();
 
         $mform->addElement('hidden', 'action');
@@ -48,6 +149,142 @@ class blog_edit_form extends moodleform {
         $mform->setType('id', PARAM_INT);
         $mform->setDefault('id', 0);
 
+        $mform->addElement('hidden', 'modid');
+        $mform->setType('modid', PARAM_INT);
+        $mform->setDefault('modid', 0);
+
+        $mform->addElement('hidden', 'courseid');
+        $mform->setType('courseid', PARAM_INT);
+        $mform->setDefault('courseid', 0);
+
+        if (!empty($assignmentdata)) {   //dont allow associations for blog assignments
+            $courseassoc = $mform->getElement('courseassoc');
+            $modassoc = $mform->getElement('modassoc');
+            $courseassoc->updateAttributes(array('disabled' => 'disabled'));
+            $modassoc->updateAttributes(array('disabled' => 'disabled'));
+        }
+
+        if ($noedit) {  //disable some other fields when editing is not allowed
+            $subject = $mform->getElement('subject');
+            $summary = $mform->getElement('summary');
+            $attachment = $mform->getElement('attachment');
+            $format = $mform->getElement('format');
+            $attachment->updateAttributes(array('disabled' => 'disabled'));
+            $format->updateAttributes(array('disabled' => 'disabled'));
+        }
+
+        $this->set_data($existing);
+    }
+
+    function validation($data, $files) {
+        global $CFG, $DB, $USER;
+
+        $errors = array();
+
+        //check to see if it's part of a submitted blog assignment
+        if ($blogassignment = $DB->get_record_sql('SELECT a.timedue, a.preventlate, a.emailteachers, a.var2, asub.grade
+                                          FROM {assignment} a, {assignment_submissions} as asub WHERE
+                                          a.id = asub.assignment AND userid = '.$USER->id.' AND a.assignmenttype = \'blog\'
+                                          AND asub.data1 = \''.$data['id'].'\'')) {
+
+            $original = $DB->get_record('post', array('id' => $data['id']));
+            //don't allow updates of the summary, subject, or attachment
+            $changed = ($original->summary != $data['summary'] ||
+                        $original->subject != $data['subject'] ||
+                        !empty($files));
+
+
+            //determine numeric value for publish state (for comparison purposes)
+            $postaccess = -1;
+            $i=0;
+
+            foreach (blog_applicable_publish_states() as $state => $desc) {
+                if ($state == $data['publishstate']) {
+                    $postaccess = $i;
+                }
+                $publishstates[$i++] = $state;
+            }
+
+            //send an error if improper changes are being made
+            if (($changed and time() > $blogassignment->timedue and $blogassignment->preventlate = 1) or
+                ($changed and $blogassignment->grade != -1) or
+                (time() < $blogassignment->timedue and ($postaccess > $blogassignment->var2 || $postaccess == -1))) {
+
+                //too late to edit this entry
+                if ($original->subject != $data['subject']) {
+                    $errors['subject'] = get_string('canteditblogassignment', 'blog');
+                }
+                if ($original->summary != $data['summary']) {
+                    $errors['summary'] = get_string('canteditblogassignment', 'blog');
+                }
+                if (!empty($files)) {
+                    $errors['attachment'] = get_string('canteditblogassignment', 'blog');
+                }
+            }
+
+            //insure the publishto value is within proper constraints
+
+            if (time() < $blogassignment->timedue and ($postaccess > $blogassignment->var2 || $postaccess == -1)) {
+                $errors['publishto'] = get_string('canteditblogassignment', 'blog');
+            }
+
+        } else {
+            if (empty($data['courseassoc']) && ($data['publishstate'] == 'course' || $data['publishstate'] == 'group') && !empty($CFG->useblogassociations)) {
+                return array('publishstate' => get_string('mustassociatecourse', 'blog'));
+            }
+        }
+
+
+        //validate course association
+        if (!empty($data['courseassoc'])) {
+            $coursecontext = $DB->get_record('context', array('id' => $data['courseassoc'], 'contextlevel' => CONTEXT_COURSE));
+
+            if ($coursecontext)  {    //insure associated course has a valid context id
+                //insure the user has access to this course
+
+                if (!has_capability('moodle/course:view', $coursecontext, $USER->id)) {
+                    $errors['courseassoc'] = get_string('studentnotallowed', '', fullname($USER, true));
+                }
+            } else {
+                $errors['courseassoc'] = get_string('invalidcontextid', 'blog');
+            }
+        }
+
+        //validate mod associations
+        if (!empty($data['modassoc'])) {
+            //insure mods are valid
+
+            foreach ($data['modassoc'] as $modid) {
+                $modcontext = $DB->get_record('context', array('id' => $modid, 'contextlevel' => CONTEXT_MODULE));
+
+                if ($modcontext) {  //insure associated mod has a valid context id
+                    //get context of the mod's course
+                    $path = split('/', $modcontext->path);
+                    $coursecontext = $DB->get_record('context', array('id' => $path[3]));
+
+                    //insure only one course is associated
+                    if (!empty($data['courseassoc'])) {
+                        if ($data['courseassoc'] != $coursecontext->id) {
+                            $errors['modassoc'] = get_string('onlyassociateonecourse', 'blog');
+                        }
+                    } else {
+                        $data['courseassoc'] = $coursecontext->id;
+                    }
+
+                    //insure the user has access to each mod's course
+                    if (!has_capability('moodle/course:view', $coursecontext)) {
+                        $errors['modassoc'] = get_string('studentnotallowed', '', fullname($USER, true));
+                    }
+                } else {
+                    $errors['modassoc'] = get_string('invalidcontextid', 'blog');
+                }
+            }
+        }
+
+        if ($errors) {
+            return $errors;
+        }
+        return true;
     }
 
     /**
@@ -70,4 +307,3 @@ class blog_edit_form extends moodleform {
     }
 
 }
-?>
diff --git a/blog/external.php b/blog/external.php
new file mode 100644 (file)
index 0000000..2fa1a3f
--- /dev/null
@@ -0,0 +1,130 @@
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+
+/**
+ * Form page for an external blog link.
+ *
+ * @package    moodlecore
+ * @subpackage blog
+ * @copyright  2009 Nicolas Connault
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+require_once('../config.php');
+require_once('lib.php');
+require_once('external_form.php');
+require_once($CFG->libdir . '/magpie/rss_fetch.inc');
+require_once($CFG->dirroot.'/tag/lib.php');
+
+require_login();
+
+$user = $USER;
+
+// TODO redirect if $CFG->useexternalblogs is off, $CFG->maxexternalblogsperuser == 0, or if user doesn't have caps to manage external blogs
+
+$id = optional_param('id', null, PARAM_INT);
+$returnurl = urldecode(optional_param('returnurl', $PAGE->url->out(), PARAM_RAW));
+$action = (empty($id)) ? 'add' : 'edit';
+
+$external = new stdClass();
+
+// Check that this id exists
+if (!empty($id) && !$DB->record_exists('blog_external', array('id' => $id))) {
+    print_error('wrongexternalid', 'blog');
+} elseif (!empty($id)) {
+    $external = $DB->get_record('blog_external', array('id' => $id));
+}
+
+$strformheading = ($action == 'edit') ? get_string('editexternalblog', 'blog') : get_string('addnewexternalblog', 'blog');
+$strexternalblogs = get_string('externalblogs','blog');
+$strblogs = get_string('blogs','blog');
+
+$externalblogform = new blog_edit_external_form();
+
+if ($externalblogform->is_cancelled()){
+    redirect($returnurl);
+
+} else if ($data = $externalblogform->get_data()) {
+    //save stuff in db
+    switch ($action) {
+        case 'add':
+            $rss = fetch_rss($data->url);
+            $new_external = new stdClass();
+            $new_external->name = (empty($data->name)) ? $rss->channel['title'] : $data->name;
+            $new_external->description = (empty($data->description)) ? $rss->channel['description'] : $data->description;
+            $new_external->userid = $user->id;
+            $new_external->url = $data->url;
+            $new_external->timemodified = mktime();
+
+            if ($new_external->id = $DB->insert_record('blog_external', $new_external)) {
+                tag_set('blog_external', $new_external->id, $data->tags);
+                // TODO success message
+            } else {
+                // TODO error message
+            }
+
+            break;
+
+        case 'edit':
+            if ($data->id && $DB->record_exists('blog_external', array('id' => $data->id))) {
+
+                $rss = fetch_rss($data->url);
+                $external->id = $data->id;
+                $external->name = (empty($data->name)) ? $rss->channel['title'] : $data->name;
+                $external->description = (empty($data->description)) ? $rss->channel['description'] : $data->description;
+                $external->userid = $user->id;
+                $external->url = $data->url;
+                $external->timemodified = mktime();
+
+                if ($DB->update_record('blog_external', $external)) {
+                    tag_set('blog_external', $external->id, explode(',', $data->tags));
+                    // TODO success message
+                } else {
+                    // TODO error message
+                }
+
+            } else {
+                print_error('wrongexternalid', 'blog');
+            }
+
+            break;
+
+        default :
+            print_error('invalidaction');
+    }
+
+    redirect($returnurl);
+}
+
+$navlinks = array();
+$navlinks[] = array('name' => fullname($user), 'link' => "$CFG->wwwroot/user/view.php?id=$user->id", 'type' => 'misc');
+$navlinks[] = array('name' => $strblogs, 'link' => "$CFG->wwwroot/blog/index.php?userid=$user->id", 'type' => 'misc');
+$navlinks[] = array('name' => $strformheading, 'link' => null, 'type' => 'misc');
+$navigation = build_navigation($navlinks);
+
+$PAGE->set_heading("$SITE->shortname: $strblogs: $strexternalblogs", $SITE->fullname);
+$PAGE->set_title("$SITE->shortname: $strblogs: $strexternalblogs");
+
+echo $OUTPUT->header($navigation);
+echo $OUTPUT->heading($strformheading, 2);
+
+$external->returnurl = $returnurl;
+$externalblogform->set_data($external);
+$externalblogform->display();
+
+echo $OUTPUT->footer();
diff --git a/blog/external_form.php b/blog/external_form.php
new file mode 100644 (file)
index 0000000..c9c6910
--- /dev/null
@@ -0,0 +1,107 @@
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+
+/**
+ * Moodleform for the user interface for managing external blog links.
+ *
+ * @package    moodlecore
+ * @subpackage blog
+ * @copyright  2009 Nicolas Connault
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+require_once($CFG->libdir.'/formslib.php');
+
+class blog_edit_external_form extends moodleform {
+    public function definition() {
+        global $CFG;
+
+        $mform =& $this->_form;
+
+        $mform->addElement('text', 'name', get_string('name'));
+        // No need to require the name, it gets prefilled with the external blog's site name if empty
+        // $mform->addRule('name', get_string('emptyname', 'blog'), 'required', null, 'client');
+        $mform->setHelpButton('name', array('name', get_string('name', 'blog'), 'blog'));
+
+        $mform->addElement('textarea', 'description', get_string('description'), array('cols' => 50, 'rows' => 7));
+        $mform->setHelpButton('description', array('description', get_string('description', 'blog'), 'blog'));
+
+        $mform->addElement('text', 'url', get_string('url'));
+        $mform->addRule('url', get_string('emptyurl', 'blog'), 'required', null, 'client');
+        $mform->setHelpButton('url', array('url', get_string('url', 'blog'), 'blog'));
+
+        if (!empty($CFG->usetags)) {
+            $mform->addElement('text', 'tags', get_string('tags'));
+            $mform->setHelpButton('tags', array('tags', get_string('tags', 'blog'), 'blog'));
+        }
+
+        $this->add_action_buttons();
+
+        $mform->addElement('hidden', 'id');
+        $mform->setType('id', PARAM_INT);
+        $mform->setDefault('id', 0);
+
+        $mform->addElement('hidden', 'returnurl');
+        $mform->setType('returnurl', PARAM_URL);
+        $mform->setDefault('returnurl', 0);
+    }
+
+    /**
+     * Additional validation includes checking URL and tags
+     */
+    public function validation($data, $files) {
+        $errors = parent::validation($data, $files);
+
+        if (!blog_is_valid_url($data['url'])) {
+            $errors['url'] = get_string('invalidurl', 'blog');
+        } else {
+            $rss = fetch_rss($data['url']);
+            if (empty($rss->channel)) {
+                $errors['url'] = get_string('emptyrssfeed', 'blog');
+            }
+        }
+
+        return $errors;
+    }
+
+/// tweak the form - depending on existing data
+    public function definition_after_data() {
+        global $CFG, $COURSE;
+        $mform =& $this->_form;
+
+        $name = trim($mform->getElementValue('name'));
+        $description = trim($mform->getElementValue('description'));
+        $url = $mform->getElementValue('url');
+
+        if (empty($name) || empty($description)) {
+            $rss = fetch_rss($url);
+
+            if (empty($name) && !empty($rss->channel['title'])) {
+                $mform->setDefault('name', $rss->channel['title']);
+            }
+
+            if (empty($description) && !empty($rss->channel['description'])) {
+                $mform->setDefault('description', $rss->channel['description']);
+            }
+        }
+
+        if ($id = $mform->getElementValue('id')) {
+            $mform->setDefault('tags', implode(',', tag_get_tags_array('blog_external', $id)));
+        }
+    }
+}
index 4efbc0a5bbe04c1f3d51e13055de9ad33566a3ad..0c14c6703a815235d4a01528069f703494d48832 100755 (executable)
 
 /// Sets up blocks and navigation for index.php
 
-require_once($CFG->dirroot .'/blog/lib.php');
-require_once($CFG->dirroot .'/blog/blogpage.php');
 require_once($CFG->dirroot .'/course/lib.php');
+require_once($CFG->dirroot.'/tag/lib.php');
 
-$blockaction = optional_param('blockaction','', PARAM_ALPHA);
 $instanceid  = optional_param('instanceid', 0, PARAM_INT);
-$blockid     = optional_param('blockid',    0, PARAM_INT);
-
-/// If user has never visited this page before, install 2 blocks for him
-blog_check_and_install_blocks();
 
+/// navigations
+/// site blogs - sitefullname -> blog entries -> (?tag) -> (?search)
+///      heading: Site Blog Entries
+/// course blogs - sitefullname -> course fullname ->  blog entries -> (?tag) -> (?search)
+///      heading: Blog Entries associated with [course fullname]
+/// mod blogs    - sitefullname -> course fullname -> mod name -> (?user/group) -> blog entries -> (?tag) -> (?search)
+///      heading: Blog Entries associated with [module fullname]
+/// group blogs - sitefullname -> course fullname ->group ->(?tag) -> (?search)
+///      heading: Blog Entries associated with [course fullname] by group [group name]
+/// user blogs   - sitefullname -> (?coursefullname) -> (?mod name) -> participants -> blog entries -> (?tag) -> (?search)
+///      heading: Blog Entries by [fullname]
+
+$blogstring = get_string('blogentries','blog');
+$tagstring = get_string('tag');
 
+// needed also for user tabs later
 if (!$course = $DB->get_record('course', array('id'=>$courseid))) {
     print_error('invalidcourseid', '', '', $courseid);
 }
 
-//_____________ new page class code ________
-$pagetype = PAGE_BLOG_VIEW;
-$pageclass = 'page_blog';
-
-// map our page identifier to the actual name
-// of the class which will be handling its operations.
-page_map_class($pagetype, $pageclass);
+$navlinks = array();
 
-// Now, create our page object.
-if (empty($USER->id)) {
-    $PAGE = page_create_object($pagetype);
-} else {
-    $PAGE = page_create_object($pagetype, $USER->id);
-}
-$PAGE->set_course($course);
-$PAGE->filtertype   = $filtertype;
-$PAGE->filterselect = $filterselect;
-$PAGE->tagid        = $tagid;
-$array = array();
-if (!empty($course->id)) {
-    $array['courseid'] = $course->id;
+if (!empty($modid)) { //mod
+    $cm = $DB->get_record('course_modules', array('id' => $modid));
+    $cm->modname = $DB->get_field('modules', 'name', array('id' => $cm->module));
+    $cm->name = $DB->get_field($cm->modname, 'name', array('id' => $cm->instance));
 }
-if (!empty($filtertype)) {
-    $array['filtertype'] = $filtertype;
-}
-if (!empty($filterselect)) {
-    $array['filterselect'] = $filterselect;
-}
-if (!empty($tagid)) {
-    $array['tagid'] = $tagid;
+
+if (!empty($groupid)) {
+    if ($thisgroup = groups_get_group($groupid, false)) { //TODO:
+        $navlinks[] = array('name' => $thisgroup->name,
+                            'link' => "$CFG->wwwroot/user/index.php?id=$course->id&amp;group=$groupid",
+                            'type' => 'misc');
+    } else {
+        print_error('cannotfindgroup');
+    }
+
 }
-$PAGE->set_url('blog/index.php', $array);
-$PAGE->set_blocks_editing_capability('moodle/blog:create');
-$PAGE->init_full(); //init the BlogInfo object and the courserecord object
 
-$editing = false;
-if ($PAGE->user_allowed_editing()) {
-    $editing = $PAGE->user_is_editing();
+if (!empty($userid)) {
+    $user = $DB->get_record('user', array('id'=>$userid));
+    $navlinks[] = array('name' => fullname($user),
+                        'link' => "$CFG->wwwroot/user/view.php?id=$userid".(empty($courseid)?'':"&amp;course=$courseid"),
+                        'type' => 'misc');
+
 }
 
+// After this we have dynamic navigation elements, with links that depend on each other
+$blogentries_link = array('name' => $blogstring, 'link' => null, 'type' => 'misc');
+$pure_url = new moodle_url();
+$pure_url->remove_params(array('tag', 'tagid', 'search'));
+$pure_blog_entries_link = $pure_url->out();
+
+// If Tag or Search is set, the "Blog entries" nav is set to the current Query String without tag or search params
 if (!empty($tagid)) {
-    $taginstance = $DB->get_record('tag', array('id'=>$tagid));
+    $tagrec = $DB->get_record('tag', array('id'=>$tagid));
+    $tag_link = array('name' => $tagrec->name,
+                      'link' => "index.php",
+                      'type' => 'misc');
+    $blogentries_link['link'] = $pure_blog_entries_link;
 } elseif (!empty($tag)) {
-    $taginstance = tag_id($tag);
+    $tag_link = array('name' => get_string('tagparam', 'blog', $tag),
+                      'link' => null,
+                      'type' => 'misc');
+    $blogentries_link['link'] = $pure_blog_entries_link;
 }
 
-/// navigations
-/// site blogs - sitefullname -> blogs -> (?tag)
-/// course blogs - sitefullname -> course fullname ->blogs ->(?tag)
-/// group blogs - sitefullname -> course fullname ->group ->(?tag)
-/// user blogs - sitefullname -> (?coursefullname) -> participants -> blogs -> (?tag)
+if (!empty($search)) {
+    $search_link = array('name' => get_string('searchterm', 'blog', $search),
+                         'link' => null,
+                         'type' => 'misc');
+    $blogentries_link['link'] = $pure_blog_entries_link;
 
-$blogstring = get_string('blogs','blog');
-$tagstring = get_string('tag');
+    $pure_url = new moodle_url();
+    $pure_url->remove_params(array('search'));
 
-// needed also for user tabs later
-if (!$course = $DB->get_record('course', array('id'=>$courseid))) {
-    print_error('invalidcourseid', '', '', $courseid);
+    if (!empty($tag_link)) {
+        $tag_link['link'] = $pure_url->out();
+    }
 }
 
-$navlinks = array();
+$navlinks[] = $blogentries_link;
 
-/// This is very messy atm.
-
-    switch ($filtertype) {
-        case 'site':
-            if ($tagid || !empty($tag)) {
-                $navlinks[] = array('name' => $blogstring, 'link' => "index.php?filtertype=site", 'type' => 'misc');
-                $navlinks[] = array('name' => "$tagstring: $taginstance->name", 'link' => null, 'type' => 'misc');
-                $navigation = build_navigation($navlinks);
-                print_header("$SITE->shortname: $blogstring", $SITE->fullname, $navigation,'','',true,$PAGE->get_extra_header_string());
-            } else {
-                $navlinks[] = array('name' => $blogstring, 'link' => null, 'type' => 'misc');
-                $navigation = build_navigation($navlinks);
-                print_header("$SITE->shortname: $blogstring", $SITE->fullname, $navigation,'','',true,$PAGE->get_extra_header_string());
-            }
-        break;
-
-        case 'course':
-            if ($tagid || !empty($tag)) {
-                $navlinks[] = array('name' => $blogstring,
-                                    'link' => "index.php?filtertype=course&amp;filterselect=$filterselect",
-                                    'type' => 'misc');
-                $navlinks[] = array('name' => "$tagstring: $taginstance->name", 'link' => null, 'type' => 'misc');
-                $navigation = build_navigation($navlinks);
-                print_header("$course->shortname: $blogstring", $course->fullname, $navigation,'','',true,$PAGE->get_extra_header_string());
-            } else {
-                $navlinks[] = array('name' => $blogstring, 'link' => null, 'type' => 'misc');
-                $navigation = build_navigation($navlinks);
-                print_header("$course->shortname: $blogstring", $course->fullname, $navigation,'','',true,$PAGE->get_extra_header_string());
-            }
-        break;
-
-        case 'group':
-
-            if ($thisgroup = groups_get_group($filterselect, false)) { //TODO:
-                if ($tagid || !empty($tag)) {
-                    $navlinks[] = array('name' => $thisgroup->name,
-                                        'link' => "$CFG->wwwroot/user/index.php?id=$course->id&amp;group=$filterselect",
-                                        'type' => 'misc');
-                    $navlinks[] = array('name' => $blogstring,
-                                        'link' => "index.php?filtertype=group&amp;filterselect=$filterselect",
-                                        'type' => 'misc');
-                    $navlinks[] = array('name' => "$tagstring: $taginstance->name", 'link' => null, 'type' => 'misc');
-                    $navigation = build_navigation($navlinks);
-                    print_header("$course->shortname: $blogstring", $course->fullname, $navigation,'','',true,$PAGE->get_extra_header_string());
-                } else {
-                    $navlinks[] = array('name' => $thisgroup->name,
-                                        'link' => "$CFG->wwwroot/user/index.php?id=$course->id&amp;group=$filterselect",
-                                        'type' => 'misc');
-                    $navlinks[] = array('name' => $blogstring, 'link' => null, 'type' => 'misc');
-                    $navigation = build_navigation($navlinks);
-                    print_header("$course->shortname: $blogstring", $course->fullname, $navigation,'','',true,$PAGE->get_extra_header_string());
-                }
-            } else {
-                print_error('cannotfindgroup');
-            }
-
-        break;
-
-        case 'user':
-            $participants = get_string('participants');
-            if (!$user = $DB->get_record('user', array('id'=>$filterselect))) {
-               print_error('invaliduserid');
-            }
-
-            if ($course->id != SITEID) {
-                $coursecontext = get_context_instance(CONTEXT_COURSE, $course->id);   // Course context
-                $systemcontext = get_context_instance(CONTEXT_SYSTEM);   // SYSTEM context
-
-                if (has_capability('moodle/course:viewparticipants', $coursecontext) || has_capability('moodle/site:viewparticipants', $systemcontext)) {
-                    $navlinks[] = array('name' => $participants,
-                                        'link' => "$CFG->wwwroot/user/index.php?id=$course->id",
-                                        'type' => 'misc');
-                }
-                $navlinks[] = array('name' => fullname($user),
-                                    'link' => "$CFG->wwwroot/user/view.php?id=$filterselect&amp;course=$course->id",
-                                    'type' => 'misc');
-
-                if ($tagid || !empty($tag)) {
-                    $navlinks[] = array('name' => $blogstring,
-                                        'link' => "index.php?courseid=$course->id&amp;filtertype=user&amp;filterselect=$filterselect",
-                                        'type' => 'misc');
-                    $navlinks[] = array('name' => "$tagstring: $taginstance->name", 'link' => null, 'type' => 'misc');
-                    $navigation = build_navigation($navlinks);
-
-                } else {
-                    $navlinks[] = array('name' => $blogstring, 'link' => null, 'type' => 'misc');
-                    $navigation = build_navigation($navlinks);
-                }
-                print_header("$course->shortname: $blogstring", $course->fullname, $navigation,'','',true,$PAGE->get_extra_header_string());
-
-            } else {
-
-            //in top view
-
-                if ($postid) {
-                    $navlinks[] = array('name' => fullname($user),
-                                        'link' => "$CFG->wwwroot/user/view.php?id=$filterselect",
-                                        'type' => 'misc');
-                    $navlinks[] = array('name' => $blogstring,
-                                        'link' => "index.php?filtertype=user&amp;filterselect=$filterselect",
-                                        'type' => 'misc');
-                    $navlinks[] = array('name' => format_string($postobject->subject), 'link' => null, 'type' => 'misc');
-                    $navigation = build_navigation($navlinks);
-
-                } else if ($tagid || !empty($tag)) {
-                    $navlinks[] = array('name' => fullname($user),
-                                        'link' => "$CFG->wwwroot/user/view.php?id=$filterselect",
-                                        'type' => 'misc');
-                    $navlinks[] = array('name' => $blogstring,
-                                        'link' => "index.php?filtertype=user&amp;filterselect=$filterselect",
-                                        'type' => 'misc');
-                    $navlinks[] = array('name' => "$tagstring: $taginstance->name", 'link' => null, 'type' => 'misc');
-                    $navigation = build_navigation($navlinks);
-
-                } else {
-                    $navlinks[] = array('name' => fullname($user),
-                                        'link' => "$CFG->wwwroot/user/view.php?id=$filterselect",
-                                        'type' => 'misc');
-                    $navlinks[] = array('name' => $blogstring, 'link' => null, 'type' => 'misc');
-                    $navigation = build_navigation($navlinks);
-                }
-                print_header("$SITE->shortname: $blogstring", $SITE->fullname, $navigation,'','',true,$PAGE->get_extra_header_string());
-
-            }
-        break;
-
-        default:
-            print_error('unknownfiletype');
-        break;
-    }
+if (!empty($tag_link)) {
+    $navlinks[] = $tag_link;
+}
+if (!empty($search_link)) {
+    $navlinks[] = $search_link;
+}
 
+$blog_headers = blog_get_headers();
 
-// prints the tabs
-if ($filtertype=='user') {
-    $showroles = true;
+if (isset($cm)) {
+    $navigation = build_navigation($blog_headers['navlinks'], $cm);
 } else {
-    $showroles = false;
+    $navigation = build_navigation($blog_headers['navlinks']);
 }
-$currenttab = 'blogs';
-
-require_once($CFG->dirroot .'/user/tabs.php');
 
+// prints the tabs
+$showroles = !empty($userid);
+$currenttab = 'blogs';
 
-?>
-<table width="100%">
-<tr>
-<td valign="top">
+$user = $USER;
+$userid = $USER->id;
index ae0cf64ec6d9c3c844ace91f1e9172f2d24bca7e..dc3fcc3dc56f1db624f8015b4a085dd61f18b089 100755 (executable)
@@ -6,19 +6,30 @@
  * if a blog id is specified then the latest entries from that blog are shown
  */
 
-require_once('../config.php');
+require_once(dirname(dirname(__FILE__)).'/config.php');
 require_once($CFG->dirroot .'/blog/lib.php');
+require_once($CFG->dirroot .'/blog/locallib.php');
+require_once($CFG->dirroot .'/course/lib.php');
+require_once($CFG->dirroot .'/tag/lib.php');
 
-$id           = optional_param('id', 0, PARAM_INT);
+$id           = optional_param('id', null, PARAM_INT);
 $start        = optional_param('formstart', 0, PARAM_INT);
-$userid       = optional_param('userid', 0, PARAM_INT);
 $tag          = optional_param('tag', '', PARAM_NOTAGS);
-$tagid        = optional_param('tagid', 0, PARAM_INT);
-$postid       = optional_param('postid', 0, PARAM_INT);
-$listing_type = optional_param('listing_type', '', PARAM_ALPHA);
-$listing_id   = optional_param('listing_id', null, PARAM_INT);
-$edit         = optional_param('edit', -1, PARAM_BOOL);
-$courseid     = optional_param('courseid', 0, PARAM_INT); // needed for user tabs and course tracking
+$userid       = optional_param('userid', null, PARAM_INT);
+$tagid        = optional_param('tagid', null, PARAM_INT);
+$modid        = optional_param('modid', null, PARAM_INT);
+$entryid      = optional_param('entryid', null, PARAM_INT);
+$groupid      = optional_param('groupid', null, PARAM_INT);
+$courseid     = optional_param('courseid', null, PARAM_INT); // needed for user tabs and course tracking
+$search       = optional_param('search', null, PARAM_RAW);
+
+$url_params = compact('id', 'start', 'tag', 'userid', 'tagid', 'modid', 'entryid', 'groupid', 'courseid', 'search');
+foreach ($url_params as $var => $val) {
+    if (empty($val)) {
+        unset($url_params[$var]);
+    }
+}
+$PAGE->set_url('blog/index.php', $url_params);
 
 //correct tagid if a text tag is provided as a param
 if (!empty($tag)) {  //text tag parameter takes precedence
@@ -29,12 +40,12 @@ if (!empty($tag)) {  //text tag parameter takes precedence
     }
 }
 
-//add courseid if modid or groupid is specified
-if (!empty($modid) and empty($courseid)) {
+// add courseid if modid or groupid is specified: This is used for navigation and title
+if (!empty($modid) && empty($courseid)) {
     $courseid = $DB->get_field('course_modules', 'course', array('id'=>$modid));
 }
 
-if (!empty($groupid) and empty($courseid)) {
+if (!empty($groupid) && empty($courseid)) {
     $courseid = $DB->get_field('groups', 'courseid', array('id'=>$groupid));
 }
 
@@ -43,18 +54,14 @@ if (empty($CFG->bloglevel)) {
 }
 
 $sitecontext = get_context_instance(CONTEXT_SYSTEM);
+$tabsfile = null;
 
-// change block edit staus if not guest and logged in
-if (isloggedin() and !isguest() and $edit != -1) {
-    $USER->editing = $edit;
-}
-
-if (!$userid and has_capability('moodle/blog:view', $sitecontext) and $CFG->bloglevel > BLOG_USER_LEVEL) {
-    if ($postid) {
-        if (!$postobject = $DB->get_record('post', array('module'=>'blog', 'id'=>$postid))) {
+if (!$userid && has_capability('moodle/blog:view', $sitecontext) && $CFG->bloglevel > BLOG_USER_LEVEL) {
+    if ($entryid) {
+        if (!$entryobject = $DB->get_record('post', array('module'=>'blog', 'id'=>$entryid))) {
             print_error('nosuchentry', 'blog');
         }
-        $userid = $postobject->userid;
+        $userid = $entryobject->userid;
     }
 } else if (!$userid) {
     // user might have capability to write blogs, but not read blogs at site level
@@ -73,7 +80,7 @@ if (!empty($modid)) {  //check mod access
     $courseid = $mod->course;
 }
 
-if ((empty($courseid) ? true : $courseid == SITEID) and empty($userid)) {  //check site access
+if ((empty($courseid) ? true : $courseid == SITEID) && empty($userid)) {  //check site access
     if ($CFG->bloglevel < BLOG_SITE_LEVEL) {
         print_error('siteblogdisable', 'blog');
     }
@@ -127,7 +134,7 @@ if (!empty($groupid)) {
         print_error(get_string('cannotviewcourseorgroupblog', 'blog'));
     }
 
-    if (groups_get_course_groupmode($course) == SEPARATEGROUPS and !has_capability('moodle/site:accessallgroups', $coursecontext)) {
+    if (groups_get_course_groupmode($course) == SEPARATEGROUPS && !has_capability('moodle/site:accessallgroups', $coursecontext)) {
         if (!groups_is_member($groupid)) {
             print_error('notmemberofgroup');
         }
@@ -144,7 +151,7 @@ if (!empty($user)) {
     }
 
     if ($user->deleted) {
-        print_header();
+        echo $OUTPUT->header();
         echo $OUTPUT->heading(get_string('userdeleted'));
         echo $OUTPUT->footer();
         die;
@@ -152,59 +159,84 @@ if (!empty($user)) {
 
     if ($USER->id == $userid) {
         if (!has_capability('moodle/blog:create', $sitecontext)
-          and !has_capability('moodle/blog:view', $sitecontext)) {
+          && !has_capability('moodle/blog:view', $sitecontext)) {
             print_error('donothaveblog', 'blog');
         }
     } else {
         $personalcontext = get_context_instance(CONTEXT_USER, $userid);
 
-        if (!has_capability('moodle/blog:view', $sitecontext) and !has_capability('moodle/user:readuserblogs', $personalcontext)) {
+        if (!has_capability('moodle/blog:view', $sitecontext) && !has_capability('moodle/user:readuserblogs', $personalcontext)) {
             print_error('cannotviewuserblog', 'blog');
         }
 
-        if (!blog_user_can_view_user_post($userid)) {
+        if (!blog_user_can_view_user_entry($userid)) {
             print_error('cannotviewcourseblog', 'blog');
         }
     }
+    $tabsfile = $CFG->dirroot . '/user/tabs.php';
 }
 
-if (empty($courseid)) {
-    $courseid = SITEID;
-}
+$courseid = (empty($courseid)) ? SITEID : $courseid;
 
-if(!empty($postid)) {
-    $filters['post'] = $postid;
-}
-
-if(!empty($courseid)) {
+if (!empty($courseid)) {
     $filters['course'] = $courseid;
+    $PAGE->set_context(get_context_instance(CONTEXT_COURSE, $courseid));
 }
 
-if(!empty($modid)) {
-    $filters['mod'] = $modid;
+if (!empty($modid)) {
+    $filters['module'] = $modid;
+    $PAGE->set_context(get_context_instance(CONTEXT_MODULE, $modid));
 }
 
-if(!empty($groupid)) {
+if (!empty($groupid)) {
     $filters['group'] = $groupid;
 }
 
-if(!empty($userid)) {
+if (!empty($userid)) {
     $filters['user'] = $userid;
 }
 
-if(!empty($tagid)) {
+if (!empty($tagid)) {
     $filters['tag'] = $tagid;
 }
 
-$PAGE->title = get_string('blog');
-include($CFG->dirroot .'/blog/header.php');
+if (!empty($search)) {
+    $filters['search'] = $search;
+}
 
-blog_print_html_formatted_entries($postid, $filtertype, $filterselect, $tagid, $tag);
+if (!empty($entryid)) {
+    $filters['entry'] = $entryid;
+}
+$blog_headers = blog_get_headers();
+
+$navigation = build_navigation($blog_headers['navlinks'], $blog_headers['cm']);
+
+// prints the tabs
+$showroles = !empty($userid);
+$currenttab = 'blogs';
+
+$user = $USER;
+$userid = $USER->id;
+
+// Unless this is a user's blog listing, the context is system
+if (empty($entryid) && empty($modid) && empty($groupid)) {
+    $PAGE->set_context(get_context_instance(CONTEXT_USER, $userid));
+}
+
+$PAGE->set_title($blog_headers['title']);
+$PAGE->set_heading($blog_headers['title']);
+
+echo $OUTPUT->header($navigation);
+
+if (!empty($tabsfile)) {
+    require_once($tabsfile);
+}
 
-add_to_log($courseid, 'blog', 'view', 'index.php?filtertype='.$filtertype.'&amp;filterselect='.$filterselect.'&amp;postid='.$postid.'&amp;tagid='.$tagid.'&amp;tag='.$tag, 'view blog entry');
+echo $OUTPUT->heading($blog_headers['heading'], 2);
 
-include($CFG->dirroot .'/blog/footer.php');
+$blog_listing = new blog_listing($filters);
+$blog_listing->print_entries();
 
 echo $OUTPUT->footer();
 
-?>
+add_to_log($courseid, 'blog', 'view', 'index.php?entryid='.$entryid.'&amp;tagid='.@$tagid.'&amp;tag='.$tag, 'view blog entry');
index f752590ffb7b491579905ad24f8ab9e8544bd3c6..28eddc662a67d05894c8dda3c894267e481ebe67 100755 (executable)
@@ -1,33 +1,57 @@
-<?php //$Id$
-
-    /**
-     * Library of functions and constants for blog
-     */
-    require_once($CFG->dirroot .'/blog/rsslib.php');
-    require_once($CFG->dirroot .'/blog/blogpage.php');
-    require_once($CFG->dirroot.'/tag/lib.php');
-
-    /**
-     * Definition of blogcourse page type (blog page with course id present).
-     */
-    //not used at the moment, and may not need to be
-    define('PAGE_BLOG_COURSE_VIEW', 'blog_course-view');
-
-
-    /**
-     * Checks to see if user has visited blogpages before, if not, install 2
-     * default blocks (blog_menu and blog_tags).
-     */
-    function blog_check_and_install_blocks() {
-        global $USER, $DB;
-
-        if (isloggedin() && !isguest()) {
-            // if this user has not visited this page before
-            if (!get_user_preferences('blogpagesize')) {
-                // find the correct ids for blog_menu and blog_from blocks
-                $menublock = $DB->get_record('block', array('name'=>'blog_menu'));
-                $tagsblock = $DB->get_record('block', array('name'=>'blog_tags'));
-                // add those 2 into block_instance page
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+
+/**
+ * Core global functions for Blog.
+ *
+ * @package    moodlecore
+ * @subpackage blog
+ * @copyright  2009 Nicolas Connault
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+/**
+ * Library of functions and constants for blog
+ */
+require_once($CFG->dirroot .'/blog/rsslib.php');
+require_once($CFG->dirroot.'/tag/lib.php');
+
+/**
+ * Definition of blogcourse page type (blog page with course id present).
+ */
+//not used at the moment, and may not need to be
+define('PAGE_BLOG_COURSE_VIEW', 'blog_course-view');
+
+
+/**
+ * Checks to see if user has visited blogpages before, if not, install 2
+ * default blocks (blog_menu and blog_tags).
+ */
+function blog_check_and_install_blocks() {
+    global $USER, $DB;
+
+    if (isloggedin() && !isguest()) {
+        // if this user has not visited this page before
+        if (!get_user_preferences('blogpagesize')) {
+            // find the correct ids for blog_menu and blog_from blocks
+            $menublock = $DB->get_record('block', array('name'=>'blog_menu'));
+            $tagsblock = $DB->get_record('block', array('name'=>'blog_tags'));
+            // add those 2 into block_instance page
 
 // Commmented out since the block changes broke it. Hopefully nico will fix it ;-)
 //                // add blog_menu block
 //                $newblock -> weight  = 1;
 //                $DB->insert_record('block_instances', $newblock);
 
-                // finally we set the page size pref
-                set_user_preference('blogpagesize', 10);
-            }
+            // finally we set the page size pref
+            set_user_preference('blogpagesize', 10);
         }
     }
+}
 
 
-    /**
-     *  This function is in lib and not in BlogInfo because entries being searched
-     *   might be found in any number of blogs rather than just one.
-     *
-     *   $@param ...
-     */
-    function blog_print_html_formatted_entries($postid, $filtertype, $filterselect, $tagid, $tag) {
+/**
+ * User can edit a blog entry if this is their own blog entry and they have
+ * the capability moodle/blog:create, or if they have the capability
+ * moodle/blog:manageentries.
+ *
+ * This also applies to deleting of entries.
+ */
+function blog_user_can_edit_entry($blog_entry) {
+    global $CFG, $USER, $OUTPUT;
 
-        global $CFG, $USER, $OUTPUT;
+    $sitecontext = get_context_instance(CONTEXT_SYSTEM);
 
-        $blogpage  = optional_param('blogpage', 0, PARAM_INT);
-        $bloglimit = optional_param('limit', get_user_preferences('blogpagesize', 10), PARAM_INT);
-        $start     = $blogpage * $bloglimit;
+    if (has_capability('moodle/blog:manageentries', $sitecontext)) {
+        return true; // can edit any blog entry
+    }
 
-        $sitecontext = get_context_instance(CONTEXT_SYSTEM);
+    if ($blog_entry->userid == $USER->id
+      and has_capability('moodle/blog:create', $sitecontext)) {
+        return true; // can edit own when having blog:create capability
+    }
 
-        $morelink = '<br />&nbsp;&nbsp;';
+    return false;
+}
 
-        $totalentries = get_viewable_entry_count($postid, $bloglimit, $start, $filtertype, $filterselect, $tagid, $tag, $sort='created DESC');
-        $blogEntries = blog_fetch_entries($postid, $bloglimit, $start, $filtertype, $filterselect, $tagid, $tag, $sort='created DESC', true);
 
-        $pagingbar = moodle_paging_bar::make($totalentries, $blogpage, $bloglimit, get_baseurl($filtertype, $filterselect));
-        $pagingbar->pagevar = 'blogpage';
-        echo $OUTPUT->paging_bar($pagingbar);
+/**
+ * Checks to see if a user can view the blogs of another user.
+ * Only blog level is checked here, the capabilities are enforced
+ * in blog/index.php
+ */
+function blog_user_can_view_user_entry($targetuserid, $blog_entry=null) {
+    global $CFG, $USER, $DB;
 
-        if ($CFG->enablerssfeeds) {
-            blog_rss_print_link($filtertype, $filterselect, $tag);
-        }
+    $pagingbar = moodle_paging_bar::make($totalentries, $blogpage, $bloglimit, get_baseurl($filtertype, $filterselect));
+    $pagingbar->pagevar = 'blogpage';
+    echo $OUTPUT->paging_bar($pagingbar);
 
-        if (has_capability('moodle/blog:create', $sitecontext)) {
-            //the user's blog is enabled and they are viewing their own blog
-            $addlink = '<div class="addbloglink">';
-            $addlink .= '<a href="'.$CFG->wwwroot .'/blog/edit.php?action=add'.'">'. get_string('addnewentry', 'blog').'</a>';
-            $addlink .= '</div>';
-            echo $addlink;
-        }
 
-        if ($blogEntries) {
+    if (empty($CFG->bloglevel)) {
+        return false; // blog system disabled
+    }
+
+    if (!empty($USER->id) and $USER->id == $targetuserid) {
+        return true; // can view own entries in any case
+    }
+
+    $sitecontext = get_context_instance(CONTEXT_SYSTEM);
+    if (has_capability('moodle/blog:manageentries', $sitecontext)) {
+        return true; // can manage all entries
+    }
 
+    // coming for 1 entry, make sure it's not a draft
+    if ($blog_entry and $blog_entry->publishstate == 'draft') {
+        return false;  // can not view draft of others
+    }
+
+    // coming for 1 entry, make sure user is logged in, if not a public blog
+    if ($blog_entry && $blog_entry->publishstate != 'public' && !isloggedin()) {
+        return false;
+    }
             $count = 0;
             foreach ($blogEntries as $blogEntry) {
                 blog_print_entry($blogEntry, 'list', $filtertype, $filterselect); //print this entry.
             $pagingbar->pagevar = 'blogpage';
             echo $OUTPUT->paging_bar($pagingbar);
 
-            if (!$count) {
-                print '<br /><div style="text-align:center">'. get_string('noentriesyet', 'blog') .'</div><br />';
+    switch ($CFG->bloglevel) {
+        case BLOG_GLOBAL_LEVEL:
+            return true;
+        break;
 
+        case BLOG_SITE_LEVEL:
+            if (!empty($USER->id)) { // not logged in viewers forbidden
+                return true;
             }
+            return false;
+        break;
 
-            print $morelink.'<br />'."\n";
-            return;
-        }
-
-        $output = '<br /><div style="text-align:center">'. get_string('noentriesyet', 'blog') .'</div><br />';
-
-        print $output;
-
-    }
-
-
-    /**
-     * This function is in lib and not in BlogInfo because entries being searched
-     * might be found in any number of blogs rather than just one.
-     *
-     * This function builds an array which can be used by the included
-     * template file, making predefined and nicely formatted variables available
-     * to the template. Template creators will not need to become intimate
-     * with the internal objects and vars of moodle blog nor will they need to worry
-     * about properly formatting their data
-     *
-     *   @param BlogEntry blogEntry - a hopefully fully populated BlogEntry object
-     *   @param string viewtype Default is 'full'. If 'full' then display this blog entry
-     *     in its complete form (eg. archive page). If anything other than 'full'
-     *     display the entry in its abbreviated format (eg. index page)
-     */
-    function blog_print_entry($blogEntry, $viewtype='full', $filtertype='', $filterselect='', $mode='loud') {
-        global $USER, $CFG, $COURSE, $DB, $OUTPUT;
-
-        $template['body'] = format_text($blogEntry->summary, $blogEntry->format);
-        $template['title'] = '<a id="b'. s($blogEntry->id) .'" />';
-        //enclose the title in nolink tags so that moodle formatting doesn't autolink the text
-        $template['title'] .= '<span class="nolink">'. format_string($blogEntry->subject) .'</span>';
-        $template['userid'] = $blogEntry->userid;
-        $template['author'] = fullname($DB->get_record('user', array('id'=>$blogEntry->userid)));
-        $template['created'] = userdate($blogEntry->created);
-
-        if($blogEntry->created != $blogEntry->lastmodified){
-            $template['lastmod'] = userdate($blogEntry->lastmodified);
-        }
-
-        $template['publishstate'] = $blogEntry->publishstate;
-
-        /// preventing user to browse blogs that they aren't supposed to see
-        /// This might not be too good since there are multiple calls per page
-
-        /*
-        if (!blog_user_can_view_user_post($template['userid'])) {
-            print_error('cannotviewuserblog', 'blog');
-        }*/
-
-        $stredit = get_string('edit');
-        $strdelete = get_string('delete');
-
-        $user = $DB->get_record('user', array('id'=>$template['userid']));
+        case BLOG_USER_LEVEL:
+        default:
+            $personalcontext = get_context_instance(CONTEXT_USER, $targetuserid);
+            return has_capability('moodle/user:readuserblogs', $personalcontext);
+        break;
 
-        /// Start printing of the blog
+    }
+}
+
+/**
+ * remove all associations for the blog entries of a particular user
+ * @param int userid - id of user whose blog associations will be deleted
+ */
+function blog_remove_associations_for_user($userid) {
+     global $DB;
+     foreach(blog_fetch_entries(array('user' => $userid), 'lasmodified DESC') as $entry) {
+         blog_remove_associations_for_entry($entry->id);
+     }
+ }
+
+/**
+ * generates the url of the page displaying entries matching the search criteria
+ *  @param array filters an array of filters (filtername => filtervalue) to narrow down results by
+ *  available filters:
+ *    entry: id field of a specific entry
+ *    course: id of a course that the entries must be associated with
+ *    mod: id of a course module that the entries must be associated with
+ *    user: id of a user who must be the author of an entry
+ *    group: id of a group who the author must be a member of, and whose course must be associated with the entry
+ *    tag: id of a tag that must be applied to the entry
+ *    site: the entire site is searched
+ *  @return string the url of the page displaying entries matching the search criteria
+ */
+function blog_get_blogs_url($filters) {
+    global $CFG;
+    return $CFG->wwwroot.'/blog/index.php?'.
+        (empty($filters['course']) ? '' : 'courseid='.$filters['course'].'&amp;').
+        (empty($filters['mod']) ? '' : 'modid='.$filters['mod'].'&amp;').
+        (empty($filters['group']) ? '' : 'groupid='.$filters['group'].'&amp;').
+        (empty($filters['user']) ? '' : 'userid='.$filters['user'].'&amp;').
+        (empty($filters['entry']) ? '' : 'entryid='.$filters['entry'].'&amp;').
+        (empty($filters['tag']) ? '' : 'tagid='.$filters['tag'].'&amp;').
+        (empty($filters['tagtext']) ? '' : 'tag='.$filters['tagtext']);
+}
+
+/**
+ * A simple function for checking if a given URL is valid and resolves
+ * to a proper XML data stream.
+ *
+ * @param string $url
+ * @return bool
+ */
+function blog_is_valid_url($url) {
+    $url = @parse_url($url);
+
+    if (!$url) {
+        return false;
+    }
 
-        echo '<table cellspacing="0" class="forumpost blogpost blog'.$template['publishstate'].'" width="100%">';
+    $url = array_map('trim', $url);
 
-        echo '<tr class="header"><td class="picture left">';
-        echo $OUTPUT->user_picture(moodle_user_picture::make($user, SITEID));
-        echo '</td>';
+    if (empty($url['port'])) {
+        $url['port'] = 80;
+    } else {
+        $url['port'] = (int)$url['port'];
+    }
 
-        echo '<td class="topic starter"><div class="subject">'.$template['title'].'</div><div class="author">';
-        $fullname = fullname($user, has_capability('moodle/site:viewfullnames', get_context_instance(CONTEXT_COURSE, $COURSE->id)));
-        $by = new object();
-        $by->name =  '<a href="'.$CFG->wwwroot.'/user/view.php?id='.
-                    $user->id.'&amp;course='.$COURSE->id.'">'.$fullname.'</a>';
-        $by->date = $template['created'];
-        print_string('bynameondate', 'forum', $by);
-        echo '</div></td></tr>';
+    $path = '';
+    if (!empty($url['path'])) {
+        $path = $url['path'];
+    }
 
-        echo '<tr><td class="left side">';
 
-    /// Actual content
+    if ($path == '') {
+        $path = '/';
+    }
 
-        echo '</td><td class="content">'."\n";
+    if (!empty($url['query'])) {
+        $path .= "?{$url['query']}";
+    }
 
-        if ($blogEntry->attachment) {
-            echo '<div class="attachments">';
-            $attachedimages = blog_print_attachments($blogEntry);
-            echo '</div>';
+    if (isset($url['host']) && $url['host'] != gethostbyname($url['host'])) {
+        if (PHP_VERSION >= 5) {
+            $headers = get_headers("{$url['scheme']}://{$url['host']}:{$url['port']}$path");
         } else {
-            $attachedimages = '';
-        }
+            $fp = fsockopen($url['host'], $url['port'], $errno, $errstr, 30);
 
-        switch ($template['publishstate']) {
-            case 'draft':
-                $blogtype = get_string('publishtonoone', 'blog');
-            break;
-            case 'site':
-                $blogtype = get_string('publishtosite', 'blog');
-            break;
-            case 'public':
-                $blogtype = get_string('publishtoworld', 'blog');
-            break;
-            default:
-                $blogtype = '';
-            break;
-
-        }
-
-        echo '<div class="audience">'.$blogtype.'</div>';
-
-        // Print whole message
-        echo $template['body'];
-
-        /// Print attachments
-        echo $attachedimages;
-    /// Links to tags
-
-        if ( !empty($CFG->usetags) && ($blogtags = tag_get_tags_csv('post', $blogEntry->id)) ) {
-            echo '<div class="tags">';
-            if ($blogtags) {
-                print(get_string('tags', 'tag') .': '. $blogtags);
-           }
-            echo '</div>';
-        }
-
-    /// Commands
-
-        echo '<div class="commands">';
+            if (!$fp) {
+                return false;
+            }
 
-        if (blog_user_can_edit_post($blogEntry)) {
-            echo '<a href="'.$CFG->wwwroot.'/blog/edit.php?action=edit&amp;id='.$blogEntry->id.'">'.$stredit.'</a>';
-            echo '| <a href="'.$CFG->wwwroot.'/blog/edit.php?action=delete&amp;id='.$blogEntry->id.'">'.$strdelete.'</a> | ';
+            fputs($fp, "HEAD $path HTTP/1.1\r\nHost: {$url['host']}\r\n\r\n");
+            $headers = fread($fp, 128);
+            fclose($fp);
         }
 
-        echo '<a href="'.$CFG->wwwroot.'/blog/index.php?postid='.$blogEntry->id.'">'.get_string('permalink', 'blog').'</a>';
-
-        echo '</div>';
-
-        if( isset($template['lastmod']) ){
-            echo '<div style="font-size: 55%;">';
-            echo ' [ '.get_string('modified').': '.$template['lastmod'].' ]';
-            echo '</div>';
+        if (is_array($headers)) {
+            $headers = implode("\n", $headers);
         }
 
-        echo '</td></tr></table>'."\n\n";
-
+        return (bool) preg_match('#^HTTP/.*\s+[(200|301|302)]+\s#i', $headers);
     }
-
-    /**
-     * Deletes all the user files in the attachments area for a post
-     */
-    function blog_delete_attachments($post) {
-        $fs = get_file_storage();
-        $fs->delete_area_files(SYSCONTEXTID, 'blog', $post->id);
+    return false;
+}
+
+/**
+ * This function is in lib and not in BlogInfo because entries being searched
+ * might be found in any number of blogs rather than just one.
+ *
+ * This function builds an array which can be used by the included
+ * template file, making predefined and nicely formatted variables available
+ * to the template. Template creators will not need to become intimate
+ * with the internal objects and vars of moodle blog nor will they need to worry
+ * about properly formatting their data
+ *
+ *   @param BlogEntry blogEntry - a hopefully fully populated BlogEntry object
+ *   @param string viewtype Default is 'full'. If 'full' then display this blog entry
+ *     in its complete form (eg. archive page). If anything other than 'full'
+ *     display the entry in its abbreviated format (eg. index page)
+ */
+function blog_print_entry($blogEntry, $viewtype='full', $filtertype='', $filterselect='', $mode='loud') {
+    global $USER, $CFG, $COURSE, $DB, $OUTPUT;
+
+    $template['body'] = format_text($blogEntry->summary, $blogEntry->format);
+    $template['title'] = '<a id="b'. s($blogEntry->id) .'" />';
+    //enclose the title in nolink tags so that moodle formatting doesn't autolink the text
+    $template['title'] .= '<span class="nolink">'. format_string($blogEntry->subject) .'</span>';
+    $template['userid'] = $blogEntry->userid;
+    $template['author'] = fullname($DB->get_record('user', array('id'=>$blogEntry->userid)));
+    $template['created'] = userdate($blogEntry->created);
+
+    if($blogEntry->created != $blogEntry->lastmodified){
+        $template['lastmod'] = userdate($blogEntry->lastmodified);
     }
 
-    /**
-     * if return=html, then return a html string.
-     * if return=text, then return a text-only string.
-     * otherwise, print HTML for non-images, and return image HTML
-     */
-    function blog_print_attachments($blogentry, $return=NULL) {
-        global $CFG;
+    $template['publishstate'] = $blogEntry->publishstate;
 
-        require_once($CFG->libdir.'/filelib.php');
+    /// preventing user to browse blogs that they aren't supposed to see
+    /// This might not be too good since there are multiple calls per page
 
-        $fs = get_file_storage();
-        $browser = get_file_browser();
+    /*
+    if (!blog_user_can_view_user_post($template['userid'])) {
+        print_error('cannotviewuserblog', 'blog');
+    }*/
 
-        $files = $fs->get_area_files(SYSCONTEXTID, 'blog', $blogentry->id);
+    $stredit = get_string('edit');
+    $strdelete = get_string('delete');
 
-        $imagereturn = "";
-        $output = "";
+    $user = $DB->get_record('user', array('id'=>$template['userid']));
 
-        $strattachment = get_string("attachment", "forum");
+    /// Start printing of the blog
 
-        foreach ($files as $file) {
-            if ($file->is_directory()) {
-                continue;
-            }
+    echo '<table cellspacing="0" class="forumpost blogpost blog'.$template['publishstate'].'" width="100%">';
 
-            $filename = $file->get_filename();
-            $ffurl    = file_encode_url($CFG->wwwroot.'/pluginfile.php', '/'.SYSCONTEXTID.'/blog/'.$blogentry->id.'/'.$filename);
-            $type     = $file->get_mimetype();
-            $type     = mimeinfo_from_type("type", $type);
+    echo '<tr class="header"><td class="picture left">';
+    echo $OUTPUT->user_picture(moodle_user_picture::make($user, SITEID));
+    echo '</td>';
 
-            $image = "<img src=\"" . $OUTPUT->old_icon_url(file_mimetype_icon($type)) . "\" class=\"icon\" alt=\"\" />";
+    echo '<td class="topic starter"><div class="subject">'.$template['title'].'</div><div class="author">';
+    $fullname = fullname($user, has_capability('moodle/site:viewfullnames', get_context_instance(CONTEXT_COURSE, $COURSE->id)));
+    $by = new object();
+    $by->name =  '<a href="'.$CFG->wwwroot.'/user/view.php?id='.
+                $user->id.'&amp;course='.$COURSE->id.'">'.$fullname.'</a>';
+    $by->date = $template['created'];
+    print_string('bynameondate', 'forum', $by);
+    echo '</div></td></tr>';
 
-            if ($return == "html") {
-                $output .= "<a href=\"$ffurl\">$image</a> ";
-                $output .= "<a href=\"$ffurl\">$filename</a><br />";
+    echo '<tr><td class="left side">';
 
-            } else if ($return == "text") {
-                $output .= "$strattachment $filename:\n$ffurl\n";
+/// Actual content
 
-            } else {
-                if (in_array($type, array('image/gif', 'image/jpeg', 'image/png'))) {    // Image attachments don't get printed as links
-                    $imagereturn .= "<br /><img src=\"$ffurl\" alt=\"\" />";
-                } else {
-                    echo "<a href=\"$ffurl\">$image</a> ";
-                    echo filter_text("<a href=\"$ffurl\">$filename</a><br />");
-                }
-            }
-        }
+    echo '</td><td class="content">'."\n";
 
-        if ($return) {
-            return $output;
-        }
-
-        return $imagereturn;
+    if ($blogEntry->attachment) {
+        echo '<div class="attachments">';
+        $attachedimages = blog_print_attachments($blogEntry);
+        echo '</div>';
+    } else {
+        $attachedimages = '';
     }
 
+    switch ($template['publishstate']) {
+        case 'draft':
+            $blogtype = get_string('publishtonoone', 'blog');
+        break;
+        case 'site':
+            $blogtype = get_string('publishtosite', 'blog');
+        break;
+        case 'public':
+            $blogtype = get_string('publishtoworld', 'blog');
+        break;
+        default:
+            $blogtype = '';
+        break;
 
-    /**
-     * Use this function to retrieve a list of publish states available for
-     * the currently logged in user.
-     *
-     * @return array This function returns an array ideal for sending to moodles'
-     *                choose_from_menu function.
-     */
-    function blog_applicable_publish_states($courseid='') {
-        global $CFG;
-
-        // everyone gets draft access
-        if ($CFG->bloglevel >= BLOG_USER_LEVEL) {
-            $options = array ( 'draft' => get_string('publishtonoone', 'blog') );
-        }
-
-        if ($CFG->bloglevel > BLOG_USER_LEVEL) {
-            $options['site'] = get_string('publishtosite', 'blog');
-        }
-
-        if ($CFG->bloglevel >= BLOG_GLOBAL_LEVEL) {
-            $options['public'] = get_string('publishtoworld', 'blog');
-        }
-
-        return $options;
     }
 
+    echo '<div class="audience">'.$blogtype.'</div>';
 
-    /**
-     * User can edit a blog entry if this is their own blog post and they have
-     * the capability moodle/blog:create, or if they have the capability
-     * moodle/blog:manageentries.
-     *
-     * This also applies to deleting of posts.
-     */
-    function blog_user_can_edit_post($blogEntry) {
-        global $CFG, $USER;
-
-        $sitecontext = get_context_instance(CONTEXT_SYSTEM);
-
-        if (has_capability('moodle/blog:manageentries', $sitecontext)) {
-            return true; // can edit any blog post
-        }
+    // Print whole message
+    echo $template['body'];
 
-        if ($blogEntry->userid == $USER->id
-          and has_capability('moodle/blog:create', $sitecontext)) {
-            return true; // can edit own when having blog:create capability
-        }
+    /// Print attachments
+    echo $attachedimages;
+/// Links to tags
 
-        return false;
+    if ( !empty($CFG->usetags) && ($blogtags = tag_get_tags_csv('post', $blogEntry->id)) ) {
+        echo '<div class="tags">';
+        if ($blogtags) {
+            print(get_string('tags', 'tag') .': '. $blogtags);
+       }
+        echo '</div>';
     }
 
+/// Commands
 
-    /**
-     * Checks to see if a user can view the blogs of another user.
-     * Only blog level is checked here, the capabilities are enforced
-     * in blog/index.php
-     */
-    function blog_user_can_view_user_post($targetuserid, $blogEntry=null) {
-        global $CFG, $USER, $DB;
-
-        if (empty($CFG->bloglevel)) {
-            return false; // blog system disabled
-        }
-
-        if (!empty($USER->id) and $USER->id == $targetuserid) {
-            return true; // can view own posts in any case
-        }
-
-        $sitecontext = get_context_instance(CONTEXT_SYSTEM);
-        if (has_capability('moodle/blog:manageentries', $sitecontext)) {
-            return true; // can manage all posts
-        }
+    echo '<div class="commands">';
 
-        // coming for 1 post, make sure it's not a draft
-        if ($blogEntry and $blogEntry->publishstate == 'draft') {
-            return false;  // can not view draft of others
-        }
+    if (blog_user_can_edit_post($blogEntry)) {
+        echo '<a href="'.$CFG->wwwroot.'/blog/edit.php?action=edit&amp;id='.$blogEntry->id.'">'.$stredit.'</a>';
+        echo '| <a href="'.$CFG->wwwroot.'/blog/edit.php?action=delete&amp;id='.$blogEntry->id.'">'.$strdelete.'</a> | ';
+    }
 
-        // coming for 1 post, make sure user is logged in, if not a public blog
-        if ($blogEntry && $blogEntry->publishstate != 'public' && !isloggedin()) {
-            return false;
-        }
+    echo '<a href="'.$CFG->wwwroot.'/blog/index.php?postid='.$blogEntry->id.'">'.get_string('permalink', 'blog').'</a>';
 
-        switch ($CFG->bloglevel) {
-            case BLOG_GLOBAL_LEVEL:
-                return true;
-            break;
+    echo '</div>';
 
-            case BLOG_SITE_LEVEL:
-                if (!empty($USER->id)) { // not logged in viewers forbidden
-                    return true;
-                }
-                return false;
-            break;
+    if( isset($template['lastmod']) ){
+        echo '<div style="font-size: 55%;">';
+        echo ' [ '.get_string('modified').': '.$template['lastmod'].' ]';
+        echo '</div>';
+    }
 
-            case BLOG_COURSE_LEVEL:
-                $mycourses = array_keys(get_my_courses($USER->id));
-                $usercourses = array_keys(get_my_courses($targetuserid));
-                $shared = array_intersect($mycourses, $usercourses);
-                if (!empty($shared)) {
-                    return true;
-                }
-                return false;
-            break;
+    echo '</td></tr></table>'."\n\n";
 
-            case BLOG_GROUP_LEVEL:
-                $mycourses = array_keys(get_my_courses($USER->id));
-                $usercourses = array_keys(get_my_courses($targetuserid));
-                $shared = array_intersect($mycourses, $usercourses);
-                foreach ($shared as $courseid) {
-                    $course = $DB->get_record('course', array('id'=>$courseid));
-                    $coursecontext = get_context_instance(CONTEXT_COURSE, $courseid);
-                    if (has_capability('moodle/site:accessallgroups', $coursecontext)
-                      or groups_get_course_groupmode($course) != SEPARATEGROUPS) {
-                        return true;
-                    } else {
-                        if ($usergroups = groups_get_all_groups($courseid, $targetuserid)) {
-                            foreach ($usergroups as $usergroup) {
-                                if (groups_is_member($usergroup->id)) {
-                                    return true;
-                                }
-                            }
-                        }
-                    }
-                }
-                return false;
-            break;
+}
 
-            case BLOG_USER_LEVEL:
-            default:
-                $personalcontext = get_context_instance(CONTEXT_USER, $targetuserid);
-                return has_capability('moodle/user:readuserblogs', $personalcontext);
-            break;
+/**
+ * Given a record in the {blog_external} table, checks the blog's URL
+ * for new entries not yet copied into Moodle.
+ *
+ * @param object $external_blog
+ * @return void
+ */
+function blog_fetch_external_entries($external_blog) {
+    global $CFG, $DB;
+    require_once($CFG->libdir . '/magpie/rss_fetch.inc');
 
-        }
+    if (!blog_is_valid_url($external_blog->url)) {
+        return null;
     }
 
+    if (!$rss = fetch_rss($external_blog->url)) {
+        return null;
+    }
 
-    /**
-     * Main filter function.
-     */
-    function blog_fetch_entries($postid='', $fetchlimit=10, $fetchstart='', $filtertype='', $filterselect='', $tagid='', $tag ='', $sort='lastmodified DESC', $limit=true) {
-        global $CFG, $USER, $DB;
-
-        /// the post table will be used for other things too
-        $typesql = "AND p.module = 'blog'";
-
-        /// set the tag id for searching
-        if ($tagid) {
-            $tag = $tagid;
-        } else if ($tag) {
-            if ($tagrec = $DB->get_record_sql("SELECT * FROM {tag} WHERE name LIKE ?", array($tag))) {
-                $tag = $tagrec->id;
-            } else {
-                $tag = -1;    //no records found
-            }
-        }
-
-        // If we have specified an ID
-        // Just return 1 entry
+    if (empty($rss->channel) || empty($rss->items)) {
+        return null;
+    }
 
-        if ($postid) {
-            if ($post = $DB->get_record('post', array('id'=>$postid))) {
+    foreach ($rss->items as $entry) {
+        $params = array('userid' => $external_blog->userid,
+                        'module' => 'blog',
+                        'uniquehash' => $entry['link'],
+                        'publishstate' => 'site',
+                        'format' => FORMAT_HTML);
 
-                if (blog_user_can_view_user_post($post->userid, $post)) {
+        if (!$DB->record_exists('post', $params)) {
+            $params['subject']      = $entry['title'];
+            $params['summary']      = $entry['description'];
+            $params['created']      = $entry['date_timestamp'];
+            $params['lastmodified'] = $entry['date_timestamp'];
 
-                    if ($user = $DB->get_record('user', array('id'=>$post->userid))) {
-                        $post->email = $user->email;
-                        $post->firstname = $user->firstname;
-                        $post->lastname = $user->lastname;
-                    }
-                    $retarray[] = $post;
-                    return $retarray;
-                } else {
-                    return null;
-                }
+            $id = $DB->insert_record('post', $params);
 
-            } else { // bad postid
-                return null;
+            // Set tags
+            if ($tags = tag_get_tags_array('blog_external', $external_blog->id)) {
+                tag_set('post', $id, $tags);
             }
         }
+    }
 
-        $params = array();
-
-        if ($tag) {
-            $tagtablesql = ", {tag_instance} ti";
-            $tagquerysql = "AND ti.itemid = p.id AND ti.tagid = :tag AND ti.itemtype = 'post'";
-            $params['tag'] = $tag;
-        } else {
-            $tagtablesql = '';
-            $tagquerysql = '';
-        }
-
-        if (isloggedin() && !has_capability('moodle/legacy:guest', get_context_instance(CONTEXT_SYSTEM), $USER->id, false)) {
-            $permissionsql = "AND (p.publishstate = 'site' OR p.publishstate = 'public' OR p.userid = :userid)";
-            $params['userid'] = $USER->id;
-        } else {
-            $permissionsql = "AND p.publishstate = 'public'";
-        }
+    $DB->update_record('blog_external', array('id' => $external_blog->id, 'timefetched' => mktime()));
+}
 
-        // fix for MDL-9165, use with readuserblogs capability in a user context can read that user's private blogs
-        // admins can see all blogs regardless of publish states, as described on the help page
-        if (has_capability('moodle/user:readuserblogs', get_context_instance(CONTEXT_SYSTEM))) {
-            $permissionsql = '';
-        } else if ($filtertype=='user' && has_capability('moodle/user:readuserblogs', get_context_instance(CONTEXT_USER, $filterselect))) {
-            $permissionsql = '';
-        }
-        /****************************************
-         * depending on the type, there are 4   *
-         * different possible sqls              *
-         ****************************************/
+/**
+ * Returns a URL based on the context of the current page.
+ * This URL points to blog/index.php and includes filter parameters appropriate for the current page.
+ *
+ * @param stdclass $context
+ * @return string
+ */
+function blog_get_context_url($context=null) {
+    global $CFG;
 
-        $requiredfields = "p.*, u.firstname,u.lastname,u.email";
+    $viewblogentries_url = $CFG->wwwroot . '/blog/index.php?';
 
-        if ($filtertype == 'course' && $filterselect == SITEID) {  // Really a site
-            $filtertype = 'site';
-        }
-
-        switch ($filtertype) {
+    if (empty($context)) {
+        global $PAGE;
+        $context = $PAGE->get_context();
+    }
 
-            case 'site':
+    // Change contextlevel to SYSTEM if viewing the site course
+    if ($context->contextlevel == CONTEXT_COURSE && $context->instanceid == SITEID) {
+        $context->contextlevel = CONTEXT_SYSTEM;
+    }
 
-                $SQL = "SELECT $requiredfields
-                          FROM {post} p, {user} u $tagtablesql
-                         WHERE p.userid = u.id $tagquerysql
-                               AND u.deleted = 0
-                               $permissionsql $typesql";
+    $filterparam = '';
+    $strlevel = '';
 
+    switch ($context->contextlevel) {
+        case CONTEXT_SYSTEM:
+        case CONTEXT_BLOCK:
+        case CONTEXT_COURSECAT:
             break;
-
-            case 'course':
-                // all users with a role assigned
-                $context = get_context_instance(CONTEXT_COURSE, $filterselect);
-
-                // MDL-10037, hidden users' blogs should not appear
-                if (has_capability('moodle/role:viewhiddenassigns', $context)) {
-                    $hiddensql = '';
-                } else {
-                    $hiddensql = 'AND ra.hidden = 0';
-                }
-
-                $SQL = "SELECT $requiredfields
-                          FROM {post} p, {user} u, {role_assignments} ra $tagtablesql
-                         WHERE p.userid = ra.userid $tagquerysql
-                               AND ra.contextid ".get_related_contexts_string($context)."
-                               AND u.id = p.userid
-                               AND u.deleted = 0
-                               $hiddensql $permissionsql $typesql";
-
+        case CONTEXT_COURSE:
+            $filterparam = 'courseid';
+            $strlevel = get_string('course');
             break;
-
-            case 'group':
-
-                $SQL = "SELECT $requiredfields
-                          FROM {post} p, {user} u, {groups_members} gm $tagtablesql
-                         WHERE p.userid = gm.userid AND u.id = p.userid $tagquerysql
-                               AND gm.groupid = :groupid
-                               AND u.deleted = 0
-                               $permissionsql $typesql";
-                $params['groupid'] = $filterselect;
+        case CONTEXT_MODULE:
+            $filterparam = 'modid';
+            $strlevel = print_context_name($context);
             break;
-
-            case 'user':
-
-                $SQL = "SELECT $requiredfields
-                          FROM {post} p, {user} u $tagtablesql
-                         WHERE p.userid = u.id $tagquerysql
-                               AND u.id = :uid
-                               AND u.deleted = 0
-                               $permissionsql $typesql";
-               $params['uid'] = $filterselect;
+        case CONTEXT_USER:
+            $filterparam = 'userid';
+            $strlevel = get_string('user');
             break;
-        }
-
-        $limitfrom = 0;
-        $limitnum = 0;
-
-        if ($fetchstart !== '' && $limit) {
-            $limitfrom = $fetchstart;
-            $limitnum = $fetchlimit;
-        }
-
-        $orderby = "ORDER BY $sort";
-
-        $records = $DB->get_records_sql("$SQL $orderby", $params, $limitfrom, $limitnum);
-
-        if (empty($records)) {
-            return array();
-        }
-
-        return $records;
     }
 
+    if (!empty($filterparam)) {
+        $viewblogentries_url .= "$filterparam=$context->instanceid";
+    }
 
-    /**
-     * get the count of viewable entries, easiest way is to count blog_fetch_entries
-     * this is used for print_paging_bar
-     * this is not ideal, but because of the UNION in the sql in blog_fetch_entries,
-     * it is hard to use $DB->count_records_sql
-     */
-    function get_viewable_entry_count($postid='', $fetchlimit=10,
-                $fetchstart='', $filtertype='', $filterselect='', $tagid='',
-                $tag ='', $sort='lastmodified DESC') {
-
-        $blogEntries = blog_fetch_entries($postid, $fetchlimit,
-                $fetchstart, $filtertype, $filterselect, $tagid, $tag,
-                $sort='lastmodified DESC', false);
+    return $viewblogentries_url;
+}
+
+/**
+ * This function encapsulates all the logic behind the complex
+ * navigation, titles and headings of the blog listing page, depending
+ * on URL params. It builds and returns an array containing:
+ *
+ * 1. The navlinks used to build the breadcrumbs
+ * 2. The title shown in the browser and at the top of the web page
+ * 3. The heading displayed above the blog entries
+ *
+ * It uses the current URL to build these variables.
+ * A number of mutually exclusive use cases are used to structure this function.
+ *
+ * @return array
+ */
+function blog_get_headers() {
+    global $CFG, $PAGE, $DB, $USER;
+
+    $tag      = optional_param('tag', null, PARAM_NOTAGS);
+    $tagid    = optional_param('tagid', null, PARAM_INT);
+    $userid   = optional_param('userid', null, PARAM_INT);
+    $modid    = optional_param('modid', null, PARAM_INT);
+    $entryid  = optional_param('entryid', null, PARAM_INT);
+    $groupid  = optional_param('groupid', null, PARAM_INT);
+    $courseid = optional_param('courseid', null, PARAM_INT);
+    $search   = optional_param('search', null, PARAM_RAW);
+    $action   = optional_param('action', null, PARAM_ALPHA);
+    $confirm  = optional_param('confirm', false, PARAM_BOOL);
+
+    $headers = array('navlinks' => array(), 'title' => '', 'heading' => '', 'cm' => null);
+
+    $blog_url = new moodle_url($CFG->wwwroot . '/blog/index.php');
+    $site = $DB->get_record('course', array('id' => SITEID));
+
+    // Common Lang strings
+    $strparticipants = get_string("participants");
+    $strblogentries  = get_string("blogentries", 'blog');
+
+    // Prepare record objects as needed
+    if (!empty($courseid)) {
+        $course = $DB->get_record('course', array('id' => $courseid));
+    }
 
-        return count($blogEntries);
+    if (!empty($userid)) {
+        $user = $DB->get_record('user', array('id' => $userid));
     }
 
+    if (!empty($groupid)) { // groupid always overrides courseid
+        $group = $DB->get_record('groups', array('id' => $groupid));
+        $course = $DB->get_record('course', array('id' => $group->courseid));
+    }
 
-    /// Find the base url from $_GET variables, for print_paging_bar
-    function get_baseurl($filtertype, $filterselect) {
+    if (!empty($modid)) { // modid always overrides courseid, so the $course object may be reset here
+        // A groupid param may conflict with this coursemod's courseid. Ignore groupid in that case
+        $course_id = $DB->get_field('course_modules', 'course', array('id'=>$modid));
+        $course = $DB->get_record('course', array('id' => $course_id));
+        $cm = $DB->get_record('course_modules', array('id' => $modid));
+        $cm->modname = $DB->get_field('modules', 'name', array('id' => $cm->module));
+        $cm->name = $DB->get_field($cm->modname, 'name', array('id' => $cm->instance));
+    }
 
-        $getcopy  = $_GET;
+    // Case 1: only entryid is requested, ignore all other filters. courseid is used to give more contextual information
+    // Breadcrumbs: [site shortname] -> [?course shortname] -> participants -> [user fullname] -> Blog entries -> [Entry subject]
+    // Title: [site shortname]: [user fullname]: Blog entry
+    // Heading: [Entry subject] by [user fullname]
+    if (!empty($entryid)) {
+        $sql = 'SELECT u.* FROM {user} u, {post} p WHERE p.id = ? AND p.userid = u.id';
+        $user = $DB->get_record_sql($sql, array($entryid));
+        $entry = $DB->get_record('post', array('id' => $entryid));
 
-        unset($getcopy['blogpage']);
+        $blog_url->param('userid', $user->id);
 
-        $strippedurl = strip_querystring(qualified_me());
-        if(!empty($getcopy)) {
-            $first = false;
-            $querystring = '';
-            foreach($getcopy as $var => $val) {
-                if(!$first) {
-                    $first = true;
-                    if ($var != 'filterselect' && $var != 'filtertype') {
-                        $querystring .= '?'.$var.'='.$val;
-                        $hasparam = true;
-                    } else {
-                        $querystring .= '?';
-                    }
-                } else {
-                    if ($var != 'filterselect' && $var != 'filtertype') {
-                    $querystring .= '&amp;'.$var.'='.$val;
-                    $hasparam = true;
-                    }
-                }
-            }
-            if (isset($hasparam)) {
-                $querystring .= '&amp;';
-            } else {
-                $querystring = '?';
-            }
+        if (!empty($course)) {
+            $courseid = $course->id;
+            $blog_url->param('courseid', $courseid);
         } else {
-            $querystring = '?';
+            $courseid = $site->id;
         }
 
-        return strip_querystring(qualified_me()) . $querystring. 'filtertype='.
-                $filtertype.'&amp;filterselect='.$filterselect.'&amp;';
+        $headers['navlinks'][] = array('name' => $strparticipants, 'link' => "$CFG->wwwroot/user/index.php?id=$courseid", 'type' => 'misc');
+        $headers['navlinks'][] = array('name' => fullname($user), 'link' => "$CFG->wwwroot/user/view.php?id=$user->id", 'type' => 'misc');
+        $headers['navlinks'][] = array('name' => $strblogentries, 'link' => $blog_url->out(), 'type' => 'misc');
+        $headers['navlinks'][] = array('name' => $entry->subject, 'link' => null, 'type' => 'misc');
 
+        $headers['title'] = "$site->shortname: " . fullname($user) . ": $entry->subject";
+        $headers['heading'] = get_string('blogentrybyuser', 'blog', fullname($user));
+
+        // We ignore tag and search params
+        return $headers;
     }
 
-    /**
-     * Returns a list of all user ids who have used blogs in the site
-     * Used in backup of site courses.
-     */
-    function blog_get_participants() {
-        global $CFG, $DB;
+    // Case 2: A user's blog entries
+    // Breadcrumbs: [site shortname] -> participants -> [user fullname] -> Blog entries
+    // Title: [site shortname]: [user fullname]: Blog
+    // Heading: [user fullname]'s blog
+    if (!empty($userid) && empty($modid) && empty($courseid)) {
+        $blog_url->param('userid', $userid);
+        $headers['navlinks'][] = array('name' => $strparticipants, 'link' => "$CFG->wwwroot/user/index.php?id=$site->id", 'type' => 'misc');
+        $headers['navlinks'][] = array('name' => fullname($user), 'link' => "$CFG->wwwroot/user/view.php?id=$user->id", 'type' => 'misc');
+        $headers['navlinks'][] = array('name' => $strblogentries, 'link' => $blog_url->out(), 'type' => 'misc');
+        $headers['title'] = "$site->shortname: " . fullname($user) . ": " . get_string('blog', 'blog');
+        $headers['heading'] = get_string('userblog', 'blog', fullname($user));
+
+    } else
+
+    // Case 3: Blog entries associated with an activity by a specific user (courseid ignored)
+    // Breadcrumbs: [site shortname] -> [course shortname] -> [activity name] -> [user fullname] -> Blog entries
+    // Title: [site shortname]: [course shortname]: [activity name]: [user fullname]: blog entries
+    // Heading: Blog entries by [user fullname] about [activity name]
+    if (!empty($userid) && !empty($modid)) {
+        $blog_url->param('userid', $userid);
+        $blog_url->param('modid', $modid);
+
+        // Course module navigation is handled by build_navigation as the second param
+        $headers['cm'] = $cm;
+        $headers['navlinks'][] = array('name' => fullname($user), 'link' => "$CFG->wwwroot/user/view.php?id=$user->id", 'type' => 'misc');
+        $headers['navlinks'][] = array('name' => $strblogentries, 'link' => $blog_url->out(), 'type' => 'misc');
+
+        $headers['title'] = "$site->shortname: $cm->name: " . fullname($user) . ': ' . get_string('blogentries', 'blog');
+
+        $a->user = fullname($user);
+        $a->mod = $cm->name;
+        $headers['heading'] = get_string('blogentriesbyuseraboutmodule', 'blog', $a);
+    } else
+
+    // Case 4: Blog entries associated with a course by a specific user
+    // Breadcrumbs: [site shortname] -> [course shortname] -> participants -> [user fullname] -> Blog entries
+    // Title: [site shortname]: [course shortname]: participants: [user fullname]: blog entries
+    // Heading: Blog entries by [user fullname] about [course fullname]
+    if (!empty($userid) && !empty($courseid) && empty($modid)) {
+        $blog_url->param('userid', $userid);
+        $blog_url->param('courseid', $courseid);
+
+        $headers['navlinks'][] = array('name' => $strparticipants, 'link' => "$CFG->wwwroot/user/index.php?id=$course->id", 'type' => 'misc');
+        $headers['navlinks'][] = array('name' => fullname($user), 'link' => "$CFG->wwwroot/user/view.php?id=$user->id", 'type' => 'misc');
+        $headers['navlinks'][] = array('name' => $strblogentries, 'link' => $blog_url->out(), 'type' => 'misc');
+
+        $headers['title'] = "$site->shortname: $course->shortname: " . fullname($user) . ': ' . get_string('blogentries', 'blog');
+
+        $a->user = fullname($user);
+        $a->course = $course->fullname;
+        $headers['heading'] = get_string('blogentriesbyuseraboutcourse', 'blog', $a);
+    } else
+
+    // Case 5: Blog entries by members of a group, associated with that group's course
+    // Breadcrumbs: [site shortname] -> [course shortname] -> Blog entries -> [group name]
+    // Title: [site shortname]: [course shortname]: blog entries : [group name]
+    // Heading: Blog entries by [group name] about [course fullname]
+    if (!empty($groupid) && empty($modid)) {
+        $blog_url->param('courseid', $course->id);
+        $headers['navlinks'][] = array('name' => $strblogentries, 'link' => $blog_url->out(), 'type' => 'misc');
+        $blog_url->remove_params(array('courseid'));
+        $blog_url->param('groupid', $groupid);
+        $headers['navlinks'][] = array('name' => $group->name, 'link' => $blog_url->out(), 'type' => 'misc');
+
+        $headers['title'] = "$site->shortname: $course->shortname: " . get_string('blogentries', 'blog') . ": $group->name";
+
+        $a->group = $group->name;
+        $a->course = $course->fullname;
+        $headers['heading'] = get_string('blogentriesbygroupaboutcourse', 'blog', $a);
+    } else
+
+    // Case 6: Blog entries by members of a group, associated with an activity in that course
+    // Breadcrumbs: [site shortname] -> [course shortname] -> [activity name] -> Blog entries -> [group name]
+    // Title: [site shortname]: [course shortname]: [activity name] : blog entries : [group name]
+    // Heading: Blog entries by [group name] about [activity fullname]
+    if (!empty($groupid) && !empty($modid)) {
+        $headers['cm'] = $cm;
+        $blog_url->param('modid', $modid);
+        $headers['navlinks'][] = array('name' => $strblogentries, 'link' => $blog_url->out(), 'type' => 'misc');
+
+        $blog_url->param('groupid', $groupid);
+        $headers['navlinks'][] = array('name' => $group->name, 'link' => $blog_url->out(), 'type' => 'misc');
+
+        $headers['title'] = "$site->shortname: $course->shortname: $cm->name: " . get_string('blogentries', 'blog') . ": $group->name";
+
+        $a->group = $group->name;
+        $a->mod = $cm->name;
+        $headers['heading'] = get_string('blogentriesbygroupaboutmodule', 'blog', $a);
+
+    } else
+
+    // Case 7: All blog entries associated with an activity
+    // Breadcrumbs: [site shortname] -> [course shortname] -> [activity name] -> Blog entries
+    // Title: [site shortname]: [course shortname]: [activity name] : blog entries
+    // Heading: Blog entries about [activity fullname]
+    if (!empty($modid) && empty($userid) && empty($groupid)) {
+        $headers['cm'] = $cm;
+        $blog_url->param('modid', $modid);
+        $headers['navlinks'][] = array('name' => $strblogentries, 'link' => $blog_url->out(), 'type' => 'misc');
+        $headers['title'] = "$site->shortname: $course->shortname: $cm->name: " . get_string('blogentries', 'blog');
+        $headers['heading'] = get_string('blogentriesabout', 'blog', $cm->name);
+    } else
+
+    // Case 8: All blog entries associated with a course
+    // Breadcrumbs: [site shortname] -> [course shortname] -> Blog entries
+    // Title: [site shortname]: [course shortname]: blog entries
+    // Heading: Blog entries about [course fullname]
+    if (!empty($courseid) && empty($userid) && empty($groupid) && empty($modid)) {
+        $blog_url->param('courseid', $courseid);
+        $headers['navlinks'][] = array('name' => $strblogentries, 'link' => $blog_url->out(), 'type' => 'misc');
+        $headers['title'] = "$site->shortname: $course->shortname: " . get_string('blogentries', 'blog');
+        $headers['heading'] = get_string('blogentriesabout', 'blog', $course->fullname);
+    }
+
+    // Append Tag info
+    if (!empty($tagid)) {
+        $blog_url->param('tagid', $tagid);
+        $tagrec = $DB->get_record('tag', array('id'=>$tagid));
+        $headers['navlinks'][] = array('name' => $tagrec->name, 'link' => $blog_url->out(), 'type' => 'misc');
+    } elseif (!empty($tag)) {
+        $blog_url->param('tag', $tag);
+        $headers['navlinks'][] = array('name' => get_string('tagparam', 'blog', $tag), 'link' => $blog_url->out(), 'type' => 'misc');
+    }
+
+    // Append Search info
+    if (!empty($search)) {
+        $blog_url->param('search', $search);
+        $headers['navlinks'][] = array('name' => get_string('searchterm', 'blog', $search), 'link' => $blog_url->out(), 'type' => 'misc');
+    }
 
-        return $DB->get_records_sql("SELECT userid AS id
-                                       FROM {post}
-                                      WHERE module = 'blog' AND courseid = 0");
+    // Append edit mode info
+    if (!empty($action) && $action == 'add') {
+        $headers['navlinks'][] = array('name' => get_string('addnewentry', 'blog'), 'link' => null, 'type' => 'misc');
+    } else if (!empty($action) && $action == 'edit') {
+        $headers['navlinks'][] = array('name' => get_string('editentry', 'blog'), 'link' => null, 'type' => 'misc');
     }
-?>
+    return $headers;
+}
diff --git a/blog/locallib.php b/blog/locallib.php
new file mode 100644 (file)
index 0000000..7551f3c
--- /dev/null
@@ -0,0 +1,1139 @@
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+
+/**
+ * Classes for Blogs.
+ *
+ * @package    moodlecore
+ * @subpackage blog
+ * @copyright  2009 Nicolas Connault
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+
+/**
+ * Blog_entry class. Represents an entry in a user's blog. Contains all methods for managing this entry.
+ * This class does not contain any HTML-generating code. See blog_listing sub-classes for such code.
+ * This class follows the Object Relational Mapping technique, its member variables being mapped to
+ * the fields of the posts table.
+ *
+ * @package    moodlecore
+ * @subpackage blog
+ * @copyright  2009 Nicolas Connault
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class blog_entry {
+    // Public Database fields
+    public $id;
+    public $userid;
+    public $subject;
+    public $summary;
+    public $rating = 0;
+    public $attachment;
+    public $publishstate;
+
+    // Locked Database fields (Don't touch these)
+    public $courseid = 0;
+    public $groupid = 0;
+    public $module = 'blog';
+    public $moduleid = 0;
+    public $coursemoduleid = 0;
+    public $content;
+    public $format = 1;
+    public $uniquehash = '';
+    public $lastmodified;
+    public $created;
+    public $usermodified;
+
+    // Other class variables
+    public $form;
+    public $tags = array();
+
+    // Methods
+    /**
+     * Constructor. If given an id, will fetch the corresponding record from the DB.
+     *
+     * @param mixed $id_or_params A blog entry id if INT, or data for a new entry if array
+     */
+    public function __construct($id_or_params=null, $form=null) {
+        global $DB;
+
+        if (!empty($id_or_params) && !is_array($id_or_params) && !is_object($id_or_params)) {
+            $object = $DB->get_record('post', array('id' => $id_or_params));
+            foreach ($object as $var => $val) {
+                $this->$var = $val;
+            }
+        } else if (!empty($id_or_params) && (is_array($id_or_params) || is_object($id_or_params))) {
+            foreach ($id_or_params as $var => $val) {
+                $this->$var = $val;
+            }
+        }
+
+        $this->form = $form;
+    }
+
+    /**
+     * Prints or returns the HTML for this blog entry.
+     *
+     * @param bool $return
+     * @return string
+     */
+    public function print_html($return=false) {
+
+        global $USER, $CFG, $COURSE, $DB, $OUTPUT;
+
+        // Comments
+        $user = $DB->get_record('user', array('id'=>$this->userid));
+
+        $template['body'] = format_text($this->summary, $this->format);
+        $template['title'] = '<a id="b'. s($this->id) .'" />';
+        //enclose the title in nolink tags so that moodle formatting doesn't autolink the text
+        $template['title'] .= '<span class="nolink">'. format_string($this->subject) .'</span>';
+        $template['userid'] = $user->id;
+        $template['author'] = fullname($user);
+        $template['created'] = userdate($this->created);
+
+        if($this->created != $this->lastmodified){
+            $template['lastmod'] = userdate($this->lastmodified);
+        }
+
+        $template['publishstate'] = $this->publishstate;
+
+        $stredit = get_string('edit');
+        $strdelete = get_string('delete');
+
+        //check to see if the entry is unassociated with group/course level access
+        $unassociatedentry = false;
+        if (!empty($CFG->useblogassociations) && ($this->publishstate == 'group' || $this->publishstate == 'course')) {
+            if (!$DB->record_exists('blog_association', array('blogid' => $this->id))) {
+                $unassociatedentry = true;
+            }
+        }
+
+        /// Start printing of the blog
+        $table = new html_table();
+        $table->cellspacing = 0;
+        $table->add_classes('forumpost blog_entry blog'. ($unassociatedentry ? 'draft' : $template['publishstate']));
+        $table->width = '100%';
+
+        $picturecell = new html_table_cell();
+        $picturecell->add_classes('picture left');
+        $picturecell->text = $OUTPUT->user_picture(moodle_user_picture::make($user, SITEID));
+
+        $table->head[] = $picturecell;
+
+        $topiccell = new html_table_cell();
+        $topiccell->add_classes('topic starter');
+        $topiccell->text = $OUTPUT->container($template['title'], 'subject');
+        $topiccell->text .= $OUTPUT->container_start('author');
+
+        $fullname = fullname($user, has_capability('moodle/site:viewfullnames', get_context_instance(CONTEXT_COURSE, $COURSE->id)));
+        $by = new object();
+        $by->name =  $OUTPUT->link(html_link::make(new moodle_url($CFG->wwwroot.'/user/view.php', array('id' => $user->id, 'course' => $COURSE->id)), $fullname));
+        $by->date = $template['created'];
+
+        $topiccell->text .= get_string('bynameondate', 'forum', $by);
+        $topiccell->text .= $OUTPUT->container_end();
+        $topiccell->header = false;
+        $table->head[] = $topiccell;
+
+    /// Actual content
+        $mainrow = new html_table_row();
+
+        $leftsidecell = new html_table_cell();
+        $leftsidecell->add_classes('left side');
+        $mainrow->cells[] = $leftsidecell;
+
+        $contentcell = new html_table_cell();
+        $contentcell->add_class('content');
+
+        if ($this->attachment) {
+            $attachedimages = $OUTPUT->container($this->print_attachments(), 'attachments');
+        } else {
+            $attachedimages = '';
+        }
+
+        //retrieve associations in case they're needed early
+        $blog_associations = $DB->get_records('blog_association', array('blogid' => $this->id));
+        //determine text for publish state
+        switch ($template['publishstate']) {
+            case 'draft':
+                $blogtype = get_string('publishtonoone', 'blog');
+            break;
+            case 'site':
+                $blogtype = get_string('publishtosite', 'blog');
+            break;
+            case 'public':
+                $blogtype = get_string('publishtoworld', 'blog');
+            break;
+            default:
+                $blogtype = '';
+            break;
+
+        }
+
+        $contentcell->text .= $OUTPUT->container($blogtype, 'audience');
+
+        $contentcell->text .= $template['body'];
+        $contentcell->text .= $attachedimages;
+
+        // Uniquehash is used as a link to an external blog
+        if (!empty($this->uniquehash) && blog_is_valid_url($this->uniquehash)) {
+            $contentcell->text .= $OUTPUT->container_start('externalblog');
+            $contentcell->text .= $OUTPUT->link(html_link::make($this->uniquehash, get_string('linktooriginalentry', 'blog')));
+            $contentcell->text .= $OUTPUT->container_end();
+        }
+
+        // Links to tags
+
+        if (!empty($CFG->usetags) && ($blogtags = tag_get_tags_csv('post', $this->id)) ) {
+            $contentcell->text .= $OUTPUT->container_start('tags');
+
+            if ($blogtags) {
+                $contentcell->text .= get_string('tags', 'tag') .': '. $blogtags;
+            }
+            $contentcell->text .= $OUTPUT->container_end();
+        }
+
+        //add associations
+        if (!empty($CFG->useblogassociations) && $blog_associations) {
+            $contentcell->text .= $OUTPUT->container_start('tags');
+            $assoc_str = '';
+
+            foreach ($blog_associations as $assoc_rec) {  //first find and show the associated course
+                $context_rec = $DB->get_record('context', array('id' => $assoc_rec->contextid));
+                if ($context_rec->contextlevel ==  CONTEXT_COURSE) {
+                    $associcon = new moodle_action_icon();
+                    $associcon->link->url = new moodle_url($CFG->wwwroot.'/course/view.php', array('id' => $context_rec->instanceid));
+                    $associcon->image->src = $OUTPUT->old_icon_url('i/course');
+                    $associcon->linktext = $DB->get_field('course', 'shortname', array('id' => $context_rec->instanceid));
+                    $assoc_str .= $OUTPUT->action_icon($associcon);
+                }
+            }
+
+            foreach ($blog_associations as $assoc_rec) {  //now show each mod association
+                $context_rec = $DB->get_record('context', array('id' => $assoc_rec->contextid));
+
+                if ($context_rec->contextlevel ==  CONTEXT_MODULE) {
+                    $modinfo = $DB->get_record('course_modules', array('id' => $context_rec->instanceid));
+                    $modname = $DB->get_field('modules', 'name', array('id' => $modinfo->module));
+
+                    $associcon = new moodle_action_icon();
+                    $associcon->link->url = new moodle_url($CFG->wwwroot.'/mod/'.$modname.'/view.php', array('id' => $modinfo->id));
+                    $associcon->image->src = $OUTPUT->mod_icon_url('icon', $modname);
+                    $associcon->linktext = $DB->get_field($modname, 'name', array('id' => $modinfo->instance));
+                    $assoc_str .= $OUTPUT->action_icon($associcon);
+
+                    $assoc_str .= ', ';
+                    $assoc_str .= $OUTPUT->action_icon($associcon);
+                }
+            }
+            $contentcell->text .= get_string('associations', 'blog') . ': '. $assoc_str;
+
+            $contentcell->text .= $OUTPUT->container_end();
+        }
+
+        if ($unassociatedentry) {
+            $contentcell->text .= $OUTPUT->container(get_string('associationunviewable', 'blog'), 'noticebox');
+        }
+
+    /// Commands
+
+        $contentcell->text .= $OUTPUT->container_start('commands');
+
+        if (blog_user_can_edit_entry($this)) {
+            $contentcell->text .= $OUTPUT->link(html_link::make(new moodle_url($CFG->wwwroot.'/blog/edit.php', array('action' => 'edit', 'id' => $this->id)), $stredit)) . ' | ';
+            if (!$DB->record_exists_sql('SELECT a.timedue, a.preventlate, a.emailteachers, a.var2, asub.grade
+                                          FROM {assignment} a, {assignment_submissions} as asub WHERE
+                                          a.id = asub.assignment AND userid = '.$USER->id.' AND a.assignmenttype = \'blog\'
+                                          AND asub.data1 = \''.$this->id.'\'')) {
+
+                $contentcell->text .= $OUTPUT->link(html_link::make(new moodle_url($CFG->wwwroot.'/blog/edit.php', array('action' => 'delete', 'id' => $this->id)), $strdelete)) . ' | ';
+            }
+        }
+
+        $contentcell->text .= $OUTPUT->link(html_link::make(new moodle_url($CFG->wwwroot.'/blog/index.php', array('entryid' => $this->id)), get_string('permalink', 'blog')));
+
+        $contentcell->text .= $OUTPUT->container_end();
+
+        if (isset($template['lastmod']) ){
+            $contentcell->text .= '<div style="font-size: 55%;">';
+            $contentcell->text .= ' [ '.get_string('modified').': '.$template['lastmod'].' ]';
+            $contentcell->text .= '</div>';
+        }
+
+        $mainrow->cells[] = $contentcell;
+        $table->data = array($mainrow);
+
+        if ($return) {
+            return $OUTPUT->table($table);
+        } else {
+            echo $OUTPUT->table($table);
+        }
+    }
+
+    /**
+     * Inserts this entry in the database. Access control checks must be done by calling code.
+     *
+     * @param mform $form Used for attachments
+     * @return void
+     */
+    public function process_attachment($form) {
+        $this->form = $form;
+    }
+
+    /**
+     * Inserts this entry in the database. Access control checks must be done by calling code.
+     * TODO Set the publishstate correctly
+     * @param mform $form Used for attachments
+     * @return void
+     */
+    public function add() {
+        global $CFG, $USER, $DB;
+
+        unset($this->id);
+        $this->module       = 'blog';
+        $this->userid       = (empty($this->userid)) ? $USER->id : $this->userid;
+        $this->lastmodified = time();
+        $this->created      = time();
+
+        // Insert the new blog entry.
+        $this->id = $DB->insert_record('post', $this);
+
+        // Add blog attachment
+        if (!empty($this->form) && $this->form->get_new_filename('attachment')) {
+            if ($this->form->save_stored_file('attachment', SYSCONTEXTID, 'blog', $this->id, '/', $this->form->get_new_filename('attachment'), $USER->id)) {
+                $DB->set_field("post", "attachment", 1, array("id"=>$this->id));
+            }
+        }
+
+        // Update tags.
+        $this->add_tags_info();
+
+        if (!empty($CFG->useblogassociations)) {
+            $this->add_associations();
+            add_to_log(SITEID, 'blog', 'add', 'index.php?userid='.$this->userid.'&entryid='.$this->id, $this->subject);
+
+        }
+
+        tag_set('post', $this->id, $this->tags);
+    }
+
+    /**
+     * Updates this entry in the database. Access control checks must be done by calling code.
+     *
+     * @param mform $form Used for attachments
+     * @return void
+     */
+    public function edit($params=array(), $form=null) {
+        global $CFG, $USER, $DB;
+
+        $this->form = $form;
+        foreach ($params as $var => $val) {
+            $this->$var = $val;
+        }
+
+        //check to see if it's part of a submitted blog assignment
+        if ($blogassignment = $DB->get_record_sql("SELECT a.timedue, a.preventlate, a.emailteachers, a.var2, asi.grade, asi.id
+                                                  FROM {assignment} a, {assignment_submissions} as asi WHERE
+                                                  a.id = asi.assignment AND userid = ? AND a.assignmenttype = 'blog'
+                                                  AND asi.data1 = ?", array($USER->id, $this->id))) {
+            //email teachers if necessary
+            if ($blogassignment->emailteachers) {
+                email_teachers($DB->get_record('assignment_submissions', array('id'=>$blogassignment['id'])));
+            }
+
+        } else {
+            //only update the attachment and associations if it is not a submitted assignment
+            if (!empty($CFG->useblogassociations)) {
+                $this->add_associations();
+            }
+        }
+
+        $this->lastmodified = time();
+
+        if (!empty($this->form) && $this->form->get_new_filename('attachment')) {
+            $this->delete_attachments();
+            if ($this->form->save_stored_file('attachment', SYSCONTEXTID, 'blog', $this->id, '/', false, $USER->id)) {
+                $this->attachment = 1;
+            } else {
+                $this->attachment = 1;
+            }
+        }
+
+        // Update record
+        $DB->update_record('post', $this);
+        tag_set('post', $this->id, $this->tags);
+
+        add_to_log(SITEID, 'blog', 'update', 'index.php?userid='.$USER->id.'&entryid='.$this->id, $this->subject);
+    }
+
+    /**
+     * Deletes this entry from the database. Access control checks must be done by calling code.
+     *
+     * @return void
+     */
+    public function delete() {
+        global $DB, $USER;
+
+        $returnurl = '';
+
+        //check to see if it's part of a submitted blog assignment
+        if ($blogassignment = $DB->get_record_sql("SELECT a.timedue, a.preventlate, a.emailteachers, asub.grade
+                                                  FROM {assignment} a, {assignment_submissions} as asub WHERE
+                                                  a.id = asub.assignment AND userid = ? AND a.assignmenttype = 'blog'
+                                                  AND asub.data1 = ?", array($USER->id, $this->id))) {
+            print_error('cantdeleteblogassignment', 'blog', $returnurl);
+        }
+
+        $this->delete_attachments();
+
+        $DB->delete_records('post', array('id' => $this->id));
+        tag_set('post', $this->id, array());
+
+        add_to_log(SITEID, 'blog', 'delete', 'index.php?userid='. $this->userid, 'deleted blog entry with entry id# '. $this->id);
+    }
+
+    /**
+     * function to add all context associations to an entry
+     * @param int entry - data object processed to include all 'entry' fields and extra data from the edit_form object
+     */
+    public function add_associations() {
+        global $DB, $USER;
+
+        $allowaddcourseassoc = true;
+
+        $this->remove_associations();
+
+        if (!empty($this->courseassoc)) {
+            $this->add_association($this->courseassoc);
+            $allowaddcourseassoc = false;
+        }
+
+        if (!empty($this->modassoc)) {
+            foreach ($this->modassoc as $modid) {
+                $this->add_association($modid, $allowaddcourseassoc);
+                $allowaddcourseassoc = false;   //let the course be added the first time
+            }
+        }
+    }
+
+    /**
+     * add a single association for a blog entry
+     * @param int contextid - id of context to associate with the blog entry
+     */
+    public function add_association($contextid) {
+        global $DB;
+
+        $assoc_object = new StdClass;
+        $assoc_object->contextid = $contextid;
+        $assoc_object->blogid = $this->id;
+        $DB->insert_record('blog_association', $assoc_object);
+    }
+
+    /**
+     * remove all associations for a blog entry
+     * @return voic
+     */
+    public function remove_associations() {
+        global $DB;
+        $DB->delete_records('blog_association', array('blogid' => $this->id));
+    }
+
+    /**
+     * Deletes all the user files in the attachments area for an entry
+     *
+     * @return void
+     */
+    public function delete_attachments() {
+        $fs = get_file_storage();
+        $fs->delete_area_files(SYSCONTEXTID, 'blog', $this->id);
+    }
+
+    /**
+     * if return=html, then return a html string.
+     * if return=text, then return a text-only string.
+     * otherwise, print HTML for non-images, and return image HTML
+     *
+     * @param bool $return Whether to return or print the generated code
+     * @return void
+     */
+    public function print_attachments($return=false) {
+        global $CFG;
+
+        require_once($CFG->libdir.'/filelib.php');
+
+        $fs = get_file_storage();
+        $browser = get_file_browser();
+
+        $files = $fs->get_area_files(SYSCONTEXTID, 'blog', $this->id);
+
+        $imagereturn = "";
+        $output = "";
+
+        $strattachment = get_string("attachment", "forum");
+
+        foreach ($files as $file) {
+            if ($file->is_directory()) {
+                continue;
+            }
+
+            $filename = $file->get_filename();
+            $ffurl    = file_encode_url($CFG->wwwroot.'/pluginfile.php', '/'.SYSCONTEXTID.'/blog/'.$this->id.'/'.$filename);
+            $type     = $file->get_mimetype();
+            $icon     = mimeinfo_from_type("icon", $type);
+            $type     = mimeinfo_from_type("type", $type);
+
+            $image = "<img src=\"$CFG->pixpath/f/$icon\" class=\"icon\" alt=\"\" />";
+
+            if ($return == "html") {
+                $output .= "<a href=\"$ffurl\">$image</a> ";
+                $output .= "<a href=\"$ffurl\">$filename</a><br />";
+
+            } else if ($return == "text") {
+                $output .= "$strattachment $filename:\n$ffurl\n";
+
+            } else {
+                if (in_array($type, array('image/gif', 'image/jpeg', 'image/png'))) {    // Image attachments don't get printed as links
+                    $imagereturn .= "<br /><img src=\"$ffurl\" alt=\"\" />";
+                } else {
+                    $imagereturn .= "<a href=\"$ffurl\">$image</a> ";
+                    $imagereturn .= filter_text("<a href=\"$ffurl\">$filename</a><br />");
+                }
+            }
+        }
+
+        if ($return) {
+            return $output;
+        }
+
+        return $imagereturn;
+
+    }
+
+    /**
+     * function to attach tags into an entry
+     * @return void
+     */
+    public function add_tags_info() {
+
+        $tags = array();
+
+        if ($otags = optional_param('otags', '', PARAM_INT)) {
+            foreach ($otags as $tagid) {
+                // TODO : make this use the tag name in the form
+                if ($tag = tag_get('id', $tagid)) {
+                    $tags[] = $tag->name;
+                }
+            }
+        }
+
+        tag_set('post', $this->id, $tags);
+    }
+
+    /**
+     * User can edit a blog entry if this is their own blog entry and they have
+     * the capability moodle/blog:create, or if they have the capability
+     * moodle/blog:manageentries.
+     * This also applies to deleting of entries.
+     *
+     * @param int $userid Optional. If not given, $USER is used
+     * @return boolean
+     */
+    public function can_user_edit($userid=null) {
+        global $CFG, $USER;
+
+        if (empty($userid)) {
+            $userid = $USER->id;
+        }
+
+        $sitecontext = get_context_instance(CONTEXT_SYSTEM);
+
+        if (has_capability('moodle/blog:manageentries', $sitecontext)) {
+            return true; // can edit any blog entry
+        }
+
+        if ($this->userid == $userid && has_capability('moodle/blog:create', $sitecontext)) {
+            return true; // can edit own when having blog:create capability
+        }
+
+        return false;
+    }
+
+    /**
+     * Checks to see if a user can view the blogs of another user.
+     * Only blog level is checked here, the capabilities are enforced
+     * in blog/index.php
+     *
+     * @param int $targetuserid ID of the user we are checking
+     *
+     * @return bool
+     */
+    public function can_user_view($targetuserid) {
+        global $CFG, $USER, $DB;
+
+        if (empty($CFG->bloglevel)) {
+            return false; // blog system disabled
+        }
+
+        if (!empty($USER->id) and $USER->id == $targetuserid) {
+            return true; // can view own entries in any case
+        }
+
+        $sitecontext = get_context_instance(CONTEXT_SYSTEM);
+        if (has_capability('moodle/blog:manageentries', $sitecontext)) {
+            return true; // can manage all entries
+        }
+
+        // coming for 1 entry, make sure it's not a draft
+        if ($this->publishstate == 'draft') {
+            return false;  // can not view draft of others
+        }
+
+        // coming for 1 entry, make sure user is logged in, if not a public blog
+        if ($this->publishstate != 'public' && !isloggedin()) {
+            return false;
+        }
+
+        switch ($CFG->bloglevel) {
+            case BLOG_GLOBAL_LEVEL:
+                return true;
+                break;
+
+            case BLOG_SITE_LEVEL:
+                if (!empty($USER->id)) { // not logged in viewers forbidden
+                    return true;
+                }
+                return false;
+                break;
+
+            case BLOG_USER_LEVEL:
+            default:
+                $personalcontext = get_context_instance(CONTEXT_USER, $targetuserid);
+                return has_capability('moodle/user:readuserblogs', $personalcontext);
+                break;
+        }
+    }
+
+    /**
+     * Use this function to retrieve a list of publish states available for
+     * the currently logged in user.
+     *
+     * @return array This function returns an array ideal for sending to moodles'
+     *                choose_from_menu function.
+     */
+
+    public static function get_applicable_publish_states() {
+        global $CFG;
+        $options = array();
+
+        // everyone gets draft access
+        if ($CFG->bloglevel >= BLOG_USER_LEVEL) {
+            $options['draft'] = get_string('publishtonoone', 'blog');
+        }
+
+        if ($CFG->bloglevel > BLOG_USER_LEVEL) {
+            $options['site'] = get_string('publishtosite', 'blog');
+        }
+
+        if ($CFG->bloglevel >= BLOG_GLOBAL_LEVEL) {
+            $options['public'] = get_string('publishtoworld', 'blog');
+        }
+
+        return $options;
+    }
+}
+
+/**
+ * Abstract Blog_Listing class: used to gather blog entries and output them as listings. One of the subclasses must be used.
+ *
+ * @package    moodlecore
+ * @subpackage blog
+ * @copyright  2009 Nicolas Connault
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class blog_listing {
+    /**
+     * Array of blog_entry objects.
+     * @var array $entries
+     */
+    public $entries = array();
+
+    /**
+     * An array of blog_filter_* objects
+     * @var array $filters
+     */
+    public $filters = array();
+
+    /**
+     * Constructor
+     *
+     * @param array $filters An associative array of filtername => filterid
+     */
+    public function __construct($filters=array()) {
+        // Unset filters overridden by more specific filters
+        foreach ($filters as $type => $id) {
+            if (!empty($type) && !empty($id)) {
+                $this->filters[$type] = blog_filter::get_instance($id, $type);
+            }
+        }
+
+        foreach ($this->filters as $type => $filter) {
+            foreach ($filter->overrides as $override) {
+                if (array_key_exists($override, $this->filters)) {
+                    unset($this->filters[$override]);
+                }
+            }
+        }
+    }
+
+    /**
+     * Fetches the array of blog entries.
+     *
+     * @return array
+     */
+    public function get_entries($start=0, $limit=10) {
+        global $DB;
+
+        if (empty($this->entries)) {
+            if ($sql_array = $this->get_entry_fetch_sql()) {
+                $this->entries = $DB->get_records_sql($sql_array['sql'] . " LIMIT $start, $limit", $sql_array['params']);
+            } else {
+                return false;
+            }
+        }
+
+        return $this->entries;
+    }
+
+    public function get_entry_fetch_sql($count=false, $sort='lastmodified DESC', $userid = false) {
+        global $DB, $USER, $CFG;
+
+        if(!$userid) {
+            $userid = $USER->id;
+        }
+
+        // The query used to locate blog entries is complicated.  It will be built from the following components:
+        $requiredfields = "p.*, u.firstname, u.lastname, u.email";  // the SELECT clause
+        $tables = array('p' => 'post', 'u' => 'user');   // components of the FROM clause (table_id => table_name)
+        $conditions = array('u.deleted = 0', 'p.userid = u.id', 'p.module = \'blog\'');  // components of the WHERE clause (conjunction)
+
+        // build up a clause for permission constraints
+
+        $params = array();
+
+        // fix for MDL-9165, use with readuserblogs capability in a user context can read that user's private blogs
+        // admins can see all blogs regardless of publish states, as described on the help page
+        if (has_capability('moodle/user:readuserblogs', get_context_instance(CONTEXT_SYSTEM))) {
+            // don't add permission constraints
+
+        } else if(!empty($this->filters['user']) && has_capability('moodle/user:readuserblogs',
+                get_context_instance(CONTEXT_USER, (empty($this->filters['user']->id) ? 0 : $this->filters['user']->id)))) {
+            // don't add permission constraints
+
+        } else {
+            if (isloggedin() && !has_capability('moodle/legacy:guest', get_context_instance(CONTEXT_SYSTEM, SITEID), $userid, false)) {
+                $assocexists = $DB->record_exists('blog_association', array());  //dont check association records if there aren't any
+
+                //begin permission sql clause
+                $permissionsql =  '(p.userid = ? ';
+                $params[] = $userid;
+
+                if ($CFG->bloglevel >= BLOG_SITE_LEVEL) { // add permission to view site-level entries
+                    $permissionsql .= " OR p.publishstate = 'site' ";
+                }
+
+                if ($CFG->bloglevel >= BLOG_GLOBAL_LEVEL) { // add permission to view global entries
+                    $permissionsql .= " OR p.publishstate = 'public' ";
+                }
+
+                $permissionsql .= ') ';   //close permissions sql clause
+            } else {  // default is access to public entries
+                $permissionsql = "p.publishstate = 'public'";
+            }
+            $conditions[] = $permissionsql;  //add permission constraints
+        }
+
+        foreach ($this->filters as $type => $blog_filter) {
+            $conditions = array_merge($conditions, $blog_filter->conditions);
+            $params = array_merge($params, $blog_filter->params);
+            $tables = array_merge($tables, $blog_filter->tables);
+        }
+
+        $tablessql = '';  // build up the FROM clause
+        foreach ($tables as $tablename => $table) {
+            $tablessql .= ($tablessql ? ', ' : '').'{'.$table.'} '.$tablename;
+        }
+
+        $sql = ($count) ? 'SELECT COUNT(*)' : 'SELECT ' . $requiredfields;
+        $sql .= " FROM $tablessql WHERE " . implode(' AND ', $conditions);
+        $sql .= ($count) ? '' : " GROUP BY p.id ORDER BY $sort";
+
+        return array('sql' => $sql, 'params' => $params);
+    }
+
+    /**
+     * Outputs all the blog entries aggregated by this blog listing.
+     *
+     * @return void
+     */
+    public function print_entries() {
+        global $CFG, $USER, $DB, $OUTPUT;
+        $sitecontext = get_context_instance(CONTEXT_SYSTEM);
+
+        $page  = optional_param('blogpage', 0, PARAM_INT);
+        $limit = optional_param('limit', get_user_preferences('blogpagesize', 10), PARAM_INT);
+        $start = $page * $limit;
+
+        $morelink = '<br />&nbsp;&nbsp;';
+
+        if ($sql_array = $this->get_entry_fetch_sql(true)) {
+            $totalentries = $DB->count_records_sql($sql_array['sql'], $sql_array['params']);
+        } else {
+            $totalentries = 0;
+        }
+
+        $entries = $this->get_entries($start, $limit);
+        $pagingbar = moodle_paging_bar::make($totalentries, $page, $limit, $this->get_baseurl());
+        $pagingbar->pagevar = 'blogpage';
+
+        echo $OUTPUT->paging_bar($pagingbar);
+
+        /* TODO RSS link
+        if ($CFG->enablerssfeeds) {
+            $this->blog_rss_print_link($filtertype, $filterselect, $tag);
+        }
+        */
+
+        if (has_capability('moodle/blog:create', $sitecontext)) {
+            //the user's blog is enabled and they are viewing their own blog
+            $userid = optional_param('userid', null, PARAM_INT);
+
+            if (empty($userid) || (!empty($userid) && $userid == $USER->id)) {
+                $add_url = new moodle_url("$CFG->wwwroot/blog/edit.php");
+                $url_params = array('action' => 'add',
+                                    'userid' => $userid,
+                                    'courseid' => optional_param('courseid', null, PARAM_INT),
+                                    'groupid' => optional_param('groupid', null, PARAM_INT),
+                                    'modid' => optional_param('modid', null, PARAM_INT),
+                                    'tagid' => optional_param('tagid', null, PARAM_INT),
+                                    'tag' => optional_param('tag', null, PARAM_INT),
+                                    'search' => optional_param('search', null, PARAM_INT));
+
+                foreach ($url_params as $var => $val) {
+                    if (empty($val)) {
+                        unset($url_params[$var]);
+                    }
+                }
+                $add_url->params($url_params);
+
+                $addlink = '<div class="addbloglink">';
+                $addlink .= '<a href="'.$add_url->out().'">'. get_string('addnewentry', 'blog').'</a>';
+                $addlink .= '</div>';
+                echo $addlink;
+            }
+        }
+
+        if ($entries) {
+            $count = 0;
+
+            foreach ($entries as $entry) {
+                $blog_entry = new blog_entry($entry);
+                $blog_entry->print_html();
+                $count++;
+            }
+
+            echo $OUTPUT->paging_bar($pagingbar);
+
+            if (!$count) {
+                print '<br /><div style="text-align:center">'. get_string('noentriesyet', 'blog') .'</div><br />';
+            }
+
+            print $morelink.'<br />'."\n";
+            return;
+        }
+    }
+
+    /// Find the base url from $_GET variables, for print_paging_bar
+    public function get_baseurl() {
+        $getcopy  = $_GET;
+
+        unset($getcopy['blogpage']);
+
+        if (!empty($getcopy)) {
+            $first = false;
+            $querystring = '';
+
+            foreach ($getcopy as $var => $val) {
+                if (!$first) {
+                    $first = true;
+                    $querystring .= "?$var=$val";
+                } else {
+                    $querystring .= '&amp;'.$var.'='.$val;
+                    $hasparam = true;
+                }
+            }
+        } else {
+            $querystring = '?';
+        }
+
+        return strip_querystring(qualified_me()) . $querystring;
+
+    }
+}
+
+/**
+ * Abstract class for blog_filter objects.
+ * A set of core filters are implemented here. To write new filters, you need to subclass
+ * blog_filter and give it the name of the type you want (for example, blog_filter_entry).
+ * The blog_filter abstract class will automatically use it when the filter is added to the
+ * URL. The first parameter of the constructor is the ID of your filter, but it can be a string
+ * or have any other meaning you wish it to have. The second parameter is called $type and is
+ * used as a sub-type for filters that have a very similar implementation (see blog_filter_context for an example)
+ */
+abstract class blog_filter {
+    /**
+     * An array of strings representing the available filter types for each blog_filter.
+     * @var array $available_types
+     */
+    public $available_types = array();
+
+    /**
+     * The type of filter (for example, types of blog_filter_context are site, course and module)
+     * @var string $type
+     */
+    public $type;
+
+    /**
+     * The unique ID for a filter's associated record
+     * @var int $id
+     */
+    public $id;
+
+    /**
+     * An array of table aliases that are used in the WHERE conditions
+     * @var array $tables
+     */
+    public $tables = array();
+
+    /**
+     * An array of WHERE conditions
+     * @var array $conditions
+     */
+    public $conditions = array();
+
+    /**
+     * An array of SQL params
+     * @var array $params
+     */
+    public $params = array();
+
+    /**
+     * An array of filter types which this particular filter type overrides: their conditions will not be evaluated
+     */
+    public $overrides = array();
+
+    public function __construct($id, $type=null) {
+        $this->id = $id;
+        $this->type = $type;
+    }
+
+    /**
+     * TODO This is poor design. A parent class should not know anything about its children.
+     * The default case helps to resolve this design issue
+     */
+    public static function get_instance($id, $type) {
+
+        switch ($type) {
+            case 'site':
+            case 'course':
+            case 'module':
+                return new blog_filter_context($id, $type);
+                break;
+
+            case 'group':
+            case 'user':
+                return new blog_filter_user($id, $type);
+                break;
+
+            case 'tag':
+                return new blog_filter_tag($id);
+                break;
+
+            default:
+                $class_name = "blog_filter_$type";
+                if (class_exists($class_name)) {
+                    return new $class_name($id, $type);
+                }
+        }
+    }
+}
+
+/**
+ * This filter defines the context level of the blog entries being searched: site, course, module
+ */
+class blog_filter_context extends blog_filter {
+    /**
+     * Constructor
+     *
+     * @param string $type
+     * @param int    $id
+     */
+    public function __construct($id=null, $type='site') {
+        global $SITE, $CFG, $DB;
+
+        if (empty($id)) {
+            $this->type = 'site';
+        } else {
+            $this->id = $id;
+            $this->type = $type;
+        }
+
+        $this->available_types = array('site' => get_string('site'), 'course' => get_string('course'), 'module' => get_string('module'));
+
+        switch ($this->type) {
+            case 'course': // Careful of site course!
+                // Ignore course filter if blog associations are not enabled
+                if ($this->id != $SITE->id && !empty($CFG->useblogassociations)) {
+                    $this->overrides = array('site');
+                    $context = get_context_instance(CONTEXT_COURSE, $this->id);
+                    $this->tables['ba'] = 'blog_association';
+                    $this->conditions[] = 'p.id = ba.blogid';
+                    $this->conditions[] = 'ba.contextid = '.$context->id;
+                    break;
+                } else {
+                    // We are dealing with the site course, do not break from the current case
+                }
+
+            case 'site':
+                // No special constraints
+                break;
+            case 'module':
+                if (!empty($CFG->useblogassociations)) {
+                    $this->overrides = array('course', 'site');
+
+                    $context = get_context_instance(CONTEXT_MODULE, $this->id);
+                    $this->tables['ba'] = 'blog_association';
+                    $this->tables['p']  = 'post';
+                    $this->conditions = array('p.id = ba.blogid', 'ba.contextid = ?');
+                    $this->params = array($context->id);
+                }
+                break;
+        }
+    }
+}
+
+/**
+ * This filter defines the user level of the blog entries being searched: a userid or a groupid.
+ * It can be combined with a context filter in order to refine the search.
+ */
+class blog_filter_user extends blog_filter {
+    public $tables = array('u' => 'user');
+
+    /**
+     * Constructor
+     *
+     * @param string $type
+     * @param int    $id
+     */
+    public function __construct($id=null, $type='user') {
+        $this->available_types = array('user' => get_string('user'), 'group' => get_string('group'));
+
+        if (empty($id)) {
+            $this->id = $USER->id;
+            $this->type = 'user';
+        } else {
+            $this->id = $id;
+            $this->type = $type;
+        }
+
+        if ($this->type == 'user') {
+            $this->conditions = array('u.id = ?');
+            $this->params = array($this->id);
+            $this->overrides = array('group');
+
+        } elseif ($this->type == 'group') {
+            $this->overrides = array('course', 'site');
+
+            $this->tables['gm'] = 'groups_members';
+            $this->conditions[] = 'p.userid = gm.userid';
+            $this->conditions[] = 'gm.groupid = ?';
+            $this->params[]     = $this->id;
+
+            if (!empty($CFG->useblogassociations)) {  // only show blog entries associated with this course
+                $course_context     = get_context_instance(CONTEXT_COURSE, $DB->get_field('groups', 'courseid', array('id' => $this->id)));
+                $this->tables['ba'] = 'blog_association';
+                $this->conditions[] = 'gm.groupid = ?';
+                $this->conditions[] = 'ba.contextid = ?';
+                $this->conditions[] = 'ba.blogid = p.id';
+                $this->params[]     = $this->id;
+                $this->params[]     = $course_context->id;
+            }
+        }
+    }
+}
+
+/**
+ * This filter defines a tag by which blog entries should be searched.
+ */
+class blog_filter_tag extends blog_filter {
+    public $tables = array('t' => 'tag', 'ti' => 'tag_instance', 'p' => 'post');
+
+    /**
+     * Constructor
+     *
+     * @return void
+     */
+    public function __construct($id) {
+        global $DB;
+        $this->id = $id;
+
+        $this->conditions = array('ti.tagid = t.id',
+                                  "ti.itemtype = 'post'",
+                                  'ti.itemid = p.id',
+                                  't.id = ?');
+        $this->params = array($this->id);
+    }
+}
+
+/**
+ * This filter defines a specific blog entry id.
+ */
+class blog_filter_entry extends blog_filter {
+    public $conditions = array('p.id = ?');
+    public $overrides  = array('site', 'course', 'module', 'group', 'user', 'tag');
+
+    public function __construct($id) {
+        $this->id = $id;
+        $this->params[] = $this->id;
+    }
+}
+
+/**
+ * Filter used to perform full-text search on an entry's subject, summary and content
+ */
+class blog_filter_search extends blog_filter {
+
+    public function __construct($search_term) {
+        global $DB;
+        $ilike = $DB->sql_ilike();
+        $this->conditions = array("(p.summary $ilike '%$search_term%' OR
+                                    p.content $ilike '%$search_term%' OR
+                                    p.subject $ilike '%$search_term%')");
+    }
+}
index ad798e584b3a12b6015a025ad9b74da269f54e89..e5e9ed9f9b5fccf9b15145228bc5d9e373266d21 100755 (executable)
@@ -1,57 +1,84 @@
-<?php  // $Id$
-       // preferences.php - user prefs for blog modeled on calendar
+<?php
 
-    require_once('../config.php');
-    require_once($CFG->dirroot.'/blog/lib.php');
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
-    $courseid = optional_param('courseid', SITEID, PARAM_INT);
 
-    if ($courseid == SITEID) {
-        require_login();
-        $context = get_context_instance(CONTEXT_SYSTEM);
-    } else {
-        require_login($courseid);
-        $context = get_context_instance(CONTEXT_COURSE, $courseid);
-    }
+/**
+ * Form page for blog preferences
+ *
+ * @package    moodlecore
+ * @subpackage blog
+ * @copyright  2009 Nicolas Connault
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
 
-    if (empty($CFG->bloglevel)) {
-        print_error('blogdisable', 'blog');
-    }
+require_once('../config.php');
+require_once($CFG->dirroot.'/blog/lib.php');
+require_once('preferences_form.php');
+
+$courseid = optional_param('courseid', SITEID, PARAM_INT);
+$PAGE->set_url('blog/preferences.php', array('courseid' => $courseid));
+
+if ($courseid == SITEID) {
+    require_login();
+    $context = get_context_instance(CONTEXT_SYSTEM);
+} else {
+    require_login($courseid);
+    $context = get_context_instance(CONTEXT_COURSE, $courseid);
+}
 
-    require_capability('moodle/blog:view', $context);
+if (empty($CFG->bloglevel)) {
+    print_error('blogdisable', 'blog');
+}
+
+require_capability('moodle/blog:view', $context);
 
 /// If data submitted, then process and store.
 
-    if (data_submitted()) {
-        $pagesize = required_param('pagesize', PARAM_INT);
+$mform = new blog_preferences_form('preferences.php');
 
-        if ($pagesize < 1) {
-            print_error('invalidpagesize');
-        }
-        set_user_preference('blogpagesize', $pagesize);
+if (!$mform->is_cancelled() && $data = $mform->get_data()) {
+    $pagesize = $data->pagesize;
 
-        // now try to guess where to go from here ;-)
-        if ($courseid == SITEID) {
-            redirect($CFG->wwwroot.'/blog/index.php');
-        } else {
-            redirect($CFG->wwwroot.'/blog/index.php?filtertype=course&amp;filterselect='.$courseid);
-        }
+    if ($pagesize < 1) {
+        print_error('invalidpagesize');
     }
+    set_user_preference('blogpagesize', $pagesize);
+}
+
+if ($mform->is_cancelled()){
+    redirect($CFG->wwwroot . '/blog/index.php');
+}
+
+$site = get_site();
+
+$strpreferences = get_string('preferences');
+$strblogs       = get_string('blogs', 'blog');
+$navlinks = array(array('name' => $strblogs, 'link' => "$CFG->wwwroot/blog/", 'type' => 'misc'));
+$navlinks[] = array('name' => $strpreferences, 'link' => null, 'type' => 'misc');
+$navigation = build_navigation($navlinks);
 
-    $site = get_site();
+$title = "$site->shortname: $strblogs : $strpreferences";
+$PAGE->set_title($title);
+$PAGE->set_heading($title);
 
-    $strpreferences = get_string('preferences');
-    $strblogs       = get_string('blogs', 'blog');
-    $navlinks = array(array('name' => $strblogs, 'link' => "$CFG->wwwroot/blog/", 'type' => 'misc'));
-    $navlinks[] = array('name' => $strpreferences, 'link' => null, 'type' => 'misc');
-    $navigation = build_navigation($navlinks);
+echo $OUTPUT->header($navigation);
 
-    print_header("$site->shortname: $strblogs : $strpreferences", $strblogs, $navigation);
-    echo $OUTPUT->heading($strpreferences);
+echo $OUTPUT->heading("$strblogs : $strpreferences", 2);
 
-    echo $OUTPUT->box_start('generalbox boxaligncenter');
-    require('./preferences.html');
-    echo $OUTPUT->box_end();
+$mform->display();
 
-    echo $OUTPUT->footer();
-?>
+echo $OUTPUT->footer();
diff --git a/blog/preferences_form.php b/blog/preferences_form.php
new file mode 100644 (file)
index 0000000..4d94ec9
--- /dev/null
@@ -0,0 +1,42 @@
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+
+/**
+ * Form for blog preferences
+ *
+ * @package    moodlecore
+ * @subpackage blog
+ * @copyright  2009 Nicolas Connault
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+require_once($CFG->libdir.'/formslib.php');
+
+class blog_preferences_form extends moodleform {
+    public function definition() {
+        global $USER, $CFG;
+
+        $mform    =& $this->_form;
+        $strpagesize = get_string('pagesize', 'blog');
+
+        $mform->addElement('text', 'pagesize', $strpagesize);
+        $mform->setDefault('pagesize', get_user_preferences('pagesize'));
+
+        $this->add_action_buttons();
+    }
+}
index 0f73502fa8fbf82dddb342f39832612a184ed9a8..b59250adb24f486d2454ae4fce872d99952bc202 100755 (executable)
@@ -24,7 +24,7 @@
                 $path = $filterselect.'/'.$userid.'/blog/course/'.$filterselect;
             break;
             case 'group':
-                $path = SITEID.'/'.$userid.'/blog/group/'.$filterselect;  
+                $path = SITEID.'/'.$userid.'/blog/group/'.$filterselect;
             break;
             case 'user':
                 $path = SITEID.'/'.$userid.'/blog/user/'.$filterselect;
             }
         }
 
-    /// Get all the posts from the database
+    /// Get all the entries from the database
 
-        $blogposts = blog_fetch_entries('', 20, '', $type, $id, $tagid);
+        $blogentries = blog_fetch_entries('', 20, '', $type, $id, $tagid);
 
     /// Now generate an array of RSS items
-        if ($blogposts) {
+        if ($blogentries) {
             $items = array();
-            foreach ($blogposts as $blogpost) {
+            foreach ($blogentries as $blog_entry) {
                 $item = NULL;
-                $item->author = fullname($DB->get_record('user', array('id'=>$blogpost->userid))); // TODO: this is slow
-                $item->title = $blogpost->subject;
-                $item->pubdate = $blogpost->lastmodified;
-                $item->link = $CFG->wwwroot.'/blog/index.php?postid='.$blogpost->id;
-                $item->description = format_text($blogpost->summary, $blogpost->format);
-                if ( !empty($CFG->usetags) && ($blogtags = tag_get_tags_array('post', $blogpost->id)) ) {
+                $item->author = fullname($DB->get_record('user', array('id'=>$blog_entry->userid))); // TODO: this is slow
+                $item->title = $blog_entry->subject;
+                $item->pubdate = $blog_entry->lastmodified;
+                $item->link = $CFG->wwwroot.'/blog/index.php?entryid='.$blog_entry->id;
+                $item->description = format_text($blog_entry->summary, $blog_entry->format);
+                if ( !empty($CFG->usetags) && ($blogtags = tag_get_tags_array('post', $blog_entry->id)) ) {
                     if ($blogtags) {
                         $item->tags = $blogtags;
                     }
@@ -90,7 +90,7 @@
         }
 
     /// Get header and footer information
-     
+
         switch ($type) {
             case 'user':
                 $info = fullname($DB->get_record('user', array('id'=>$id), 'firstname,lastname'));
             $info .= ': '.$DB->get_field('tags', 'text', array('id'=>$tagid));
         }
 
-        $header = rss_standard_header(get_string($type.'blog','blog', $info), 
-                                      $CFG->wwwroot.'/blog/index.php', 
+        $header = rss_standard_header(get_string($type.'blog','blog', $info),
+                                      $CFG->wwwroot.'/blog/index.php',
                                       get_string('intro','blog'));
-                                                      
+
         $footer = rss_standard_footer();
 
 
             return "$CFG->dataroot/rss/blog/$type/$id.xml";
         }
     }
-    
+
     //This function saves to file the rss feed specified in the parameters
     function blog_rss_save_file($type, $id, $tagid=0, $contents='') {
         global $CFG;
diff --git a/blog/simpletest/testbloglib.php b/blog/simpletest/testbloglib.php
new file mode 100644 (file)
index 0000000..36a9823
--- /dev/null
@@ -0,0 +1,129 @@
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+
+/**
+ * Unit tests for blog
+ *
+ * @package    moodlecore
+ * @subpackage blog
+ * @copyright  2009 Nicolas Connault
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+require_once($CFG->dirroot . '/blog/locallib.php');
+
+class bloglib_test extends UnitTestCaseUsingDatabase {
+
+    public static $includecoverage = array('blog/locallib.php');
+
+    public function test_overrides() {
+        // Try all the filters at once: Only the entry filter is active
+        $blog_listing = new blog_listing(array('site' => 1, 'course' => 1, 'module' => 1, 'group' => 1, 'user' => 1, 'tag' => 1, 'entry' => 1));
+        $this->assertFalse(array_key_exists('site', $blog_listing->filters));
+        $this->assertFalse(array_key_exists('course', $blog_listing->filters));
+        $this->assertFalse(array_key_exists('module', $blog_listing->filters));
+        $this->assertFalse(array_key_exists('group', $blog_listing->filters));
+        $this->assertFalse(array_key_exists('user', $blog_listing->filters));
+        $this->assertFalse(array_key_exists('tag', $blog_listing->filters));
+        $this->assertTrue(array_key_exists('entry', $blog_listing->filters));
+
+        // Again, but without the entry filter: This time, the tag, user and module filters are active
+        $blog_listing = new blog_listing(array('site' => 1, 'course' => 1, 'module' => 1, 'group' => 1, 'user' => 1, 'tag' => 1));
+        $this->assertFalse(array_key_exists('site', $blog_listing->filters));
+        $this->assertFalse(array_key_exists('course', $blog_listing->filters));
+        $this->assertFalse(array_key_exists('group', $blog_listing->filters));
+        $this->assertTrue(array_key_exists('module', $blog_listing->filters));
+        $this->assertTrue(array_key_exists('user', $blog_listing->filters));
+        $this->assertTrue(array_key_exists('tag', $blog_listing->filters));
+
+        // We should get the same result by removing the 3 inactive filters: site, course and group:
+        $blog_listing = new blog_listing(array('module' => 1, 'user' => 1, 'tag' => 1));
+        $this->assertFalse(array_key_exists('site', $blog_listing->filters));
+        $this->assertFalse(array_key_exists('course', $blog_listing->filters));
+        $this->assertFalse(array_key_exists('group', $blog_listing->filters));
+        $this->assertTrue(array_key_exists('module', $blog_listing->filters));
+        $this->assertTrue(array_key_exists('user', $blog_listing->filters));
+        $this->assertTrue(array_key_exists('tag', $blog_listing->filters));
+
+        // Now use the group and module together
+        $blog_listing = new blog_listing(array('module' => 1, 'group' => 1, 'tag' => 1));
+        $this->assertTrue(array_key_exists('group', $blog_listing->filters));
+        $this->assertTrue(array_key_exists('module', $blog_listing->filters));
+        $this->assertFalse(array_key_exists('user', $blog_listing->filters));
+        $this->assertTrue(array_key_exists('tag', $blog_listing->filters));
+
+        $blog_listing = new blog_listing(array('course' => 2));
+        $this->assertTrue(array_key_exists('course', $blog_listing->filters));
+
+        $blog_listing = new blog_listing(array('course' => 2, 'group' => 12));
+        $this->assertFalse(array_key_exists('course', $blog_listing->filters));
+        $this->assertTrue(array_key_exists('group', $blog_listing->filters));
+
+        $blog_listing = new blog_listing(array('site' => 2, 'group' => 12));
+        $this->assertFalse(array_key_exists('site', $blog_listing->filters));
+        $this->assertTrue(array_key_exists('group', $blog_listing->filters));
+
+        $blog_listing = new blog_listing(array('user' => 2, 'group' => 12));
+        $this->assertFalse(array_key_exists('group', $blog_listing->filters));
+        $this->assertTrue(array_key_exists('user', $blog_listing->filters));
+
+    }
+
+    /**
+     * Some user, course, module, group and blog sample data needs to be setup for this test
+     */
+    public function test_blog_get_headers_case_1() {
+        global $CFG, $PAGE, $OUTPUT;
+        
+        $this->create_test_tables('post', 'tag', 'course', 'user', 'role', 'role_assignments', 'group', 'blog_associations', 
+                                  'course_modules', 'role_capabilities', 'assignment', 'tag_correlation', 'tag_instance');
+        
+        $contexts = $this->load_test_data('context',
+                array('contextlevel', 'instanceid', 'path', 'depth'), array(
+           1 => array(40, 666, '', 2),
+           2 => array(50, 666, '', 3),
+           3 => array(70, 666, '', 4),
+        ));
+
+        $this->load_test_data('course', 
+                              array('id', 'fullname', 'shortname', 'format'), 
+                              array(
+                                array(1, 'My Moodle Site', 'moodle', 'site'),
+                                array(2, 'Course 1', 'course1', 'weeks'),
+                                array(3, 'Course 2', 'course2', 'weeks')
+                                )
+                              );
+        $this->load_test_data('user',
+                              array('id', 'confirmed', 'username', 'firstname', 'lastname'),
+                              array( array(1, 1, 'joebloe', 'Joe', 'Bloe')));
+
+        $this->switch_to_test_db();
+        
+        $userrole = create_role(get_string('authenticateduser'), 'user', get_string('authenticateduserdescription'), 'moodle/legacy:user');
+        $student = $this->testdb->get_record('role', array('shortname' => 'student'));
+        
+        $ras = $this->load_test_data('role_assignments', array('userid', 'roleid', 'contextid'),
+                                     array(array(1, $student->id, $context[2]->id)));
+
+        // Case 1: A single blog entry
+        $PAGE->url = new moodle_url($CFG->wwwroot . '/blog/index.php', array('entryid' => 1));
+        $blog_headers = blog_get_headers();
+
+        $this->assertEqual($blog_headers['title'], '');
+    }
+}
index a90ced3976b0f6764ce4c6f138f90262a9ecfcc7..a77d43a2f83b8f9e5d24004e963f42139446c7e4 100644 (file)
@@ -5,6 +5,6 @@
 ///  This fragment is called by moodle_needs_upgrading() and /admin/index.php
 /////////////////////////////////////////////////////////////////////////////////
 
-$blog_version  = 2005030400;  // The current version of blog module (Date: YYYYMMDDXX)
+$blog_version  = 2009070600;  // The current version of blog module (Date: YYYYMMDDXX)
 $module->cron     = 1800;           // Period for cron to check this module (secs)
 ?>
index 1bc39ece56eb4756691e74fc413b8abf0d431981..29af1662b752de5b1106a711997ce36d971bd901 100644 (file)
@@ -2522,6 +2522,7 @@ function set_coursemodule_visible($id, $visible, $prevstateoverrides=false) {
 function delete_course_module($id) {
     global $CFG, $DB;
     require_once($CFG->libdir.'/gradelib.php');
+    require_once($CFG->dirroot.'/blog/lib.php');
 
     if (!$cm = $DB->get_record('course_modules', array('id'=>$id))) {
         return true;
@@ -2542,7 +2543,8 @@ function delete_course_module($id) {
     }
 
     delete_context(CONTEXT_MODULE, $cm->id);
-    return $DB->delete_records('course_modules', array('id'=>$cm->id));
+    return $DB->delete_records('course_modules', array('id'=>$cm->id)) &&
+           $DB->delete_records('blog_association', array('contextid'=>$context->id));
 }
 
 function delete_mod_from_section($mod, $section) {
index 2d90270939080370f53b85b64ae1d8a58ad59077..f94d8194d4bb3db2e9b91066179a3c9969f87eb6 100644 (file)
 // You should have received a copy of the GNU General Public License
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
+
+/**
+ * Form for grader report preferences.
+ *
+ * @package    moodlecore
+ * @subpackage grade
+ * @copyright  2009 Nicolas Connault
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
 require_once($CFG->libdir.'/formslib.php');
 
 /**
index 33cc7bdf000900620b8db640b7993f20eeba3634..1e76b7db6de7dd72ac47039a0a1530dcf96f4d32 100644 (file)
@@ -36,7 +36,7 @@ $string['blockediplist'] = 'Blocked IP List';
 $string['blockinstances'] = 'Instances';
 $string['blockmultiple'] = 'Multiple';
 $string['blocksettings'] = 'Manage blocks';
-$string['bloglevel'] = 'Blog Visibility';
+$string['bloglevel'] = 'Blog visibility';
 $string['bookmarkadded'] = 'Bookmark added.';
 $string['bookmarkalreadyexists'] = 'You have already bookmarked this page.';
 $string['bookmarkdeleted'] = 'Bookmark deleted.';
@@ -933,6 +933,8 @@ $string['webservicesystemsettings'] = 'common settings';
 $string['webserviceusersettings'] = 'Web service users settings';
 $string['xmlrpcrecommended'] = 'Installing the optional xmlrpc extension is useful for Moodle Networking functionality.';
 $string['xmlstrictheaders'] = 'XML strict headers';
+$string['useblogassociations'] = 'Enable associations';
+$string['configuseblogassociations'] = 'Should users be able to organize their blog by associating entries with courses and course modules?';
 $string['ziprequired'] = 'The Zip PHP extension is now required by Moodle, info-ZIP binaries or PclZip library are not used anymore.';
 
 ?>
index 7834ed14267b6b1a57093581208a58f0438f7922..8fb3f1d8184bb53a375f8c7f516502696e64424b 100644 (file)
@@ -133,6 +133,7 @@ $string['typeoffline'] = 'Offline activity';
 $string['typeonline'] = 'Online text';
 $string['typeupload'] = 'Advanced uploading of files';
 $string['typeuploadsingle'] = 'Upload a single file';
+$string['typeblog'] = 'Blog post';
 $string['unfinalize'] = 'Revert to draft';
 $string['unfinalizeerror'] = 'An error occurred and that submission could not be reverted to draft';
 $string['uploadbadname'] = 'This filename contained strange characters and couldn\'t be uploaded';
@@ -147,5 +148,7 @@ $string['usermisconf'] = 'User is misconfigured';
 $string['viewfeedback'] = 'View assignment grades and feedback';
 $string['viewsubmissions'] = 'View $a submitted assignments';
 $string['yoursubmission'] = 'Your submission';
-
+$string['maxpublishstate'] = 'Maximum visibility for blog entry before duedate';
+$string['selectblog'] = 'Select which blog entry you wish to submit';
+$string['noblogs'] = 'You have no blog entries to submit!';
 ?>
index 2dcec8721bf5b1c79f0cac8f35e7d471ff4b300b..a5596e3e09dc5dd69aa1eab204bc218987f38e08 100755 (executable)
@@ -3,43 +3,70 @@
 
 
 $string['addnewentry'] = 'Add a new entry';
+$string['addnewexternalblog'] = 'New external blog...';
+$string['associations'] = 'Associations';
+$string['associationunviewable'] = 'This entry cannot be viewed by others until a course is associated with it or the \'Publish To\' field is changed';
 $string['backupblogshelp'] = 'If enabled then blogs will be included in SITE automated backups';
+$string['blockexternalstitle'] = 'External Blogs';
 $string['blockmenutitle'] = 'Blog Menu';
+$string['blockrecenttitle'] = 'Recent Blog Entries';
 $string['blocktagstitle'] = 'Blog Tags';
 $string['blocktitle'] = 'Blog tags block title';
 $string['blog'] = 'Blog';
-$string['blogdisable'] = 'Blogging is disabled!';
 $string['blogdeleteconfirm'] = 'Delete this blog?';
+$string['blogdisable'] = 'Blogging is disabled!';
+$string['blogentries'] = 'Blog entries';
+$string['blogentriesabout'] = 'Blog entries about $a';
+$string['blogentriesbygroupaboutcourse'] = 'Blog entries about $a->course by $a->group';
+$string['blogentriesbygroupaboutmodule'] = 'Blog entries about $a->mod by $a->group';
+$string['blogentriesbyuseraboutcourse'] = 'Blog entries about $a->course by $a->user';
+$string['blogentriesbyuseraboutmodule'] = 'Blog entries about $a->mod by $a->user';
+$string['blogentrybyuser'] = 'Blog entry by $a';
 $string['blogpreferences'] = 'Blog preferences';
 $string['blogs'] = 'Blogs';
 $string['blogtags'] = 'Blog Tags';
-$string['cannotviewsiteblog'] = 'You do not have the required permissions to view all site blogs';
-$string['cannotviewuserblog'] = 'You do not have the required permissions to read user blogs';
 $string['cannotviewcourseblog'] = 'You do not have the required permissions to view blogs in this course';
 $string['cannotviewcourseorgroupblog'] = 'You do not have the required permissions to view blogs in this course/group';
+$string['cannotviewsiteblog'] = 'You do not have the required permissions to view all site blogs';
+$string['cannotviewuserblog'] = 'You do not have the required permissions to read user blogs';
+$string['configexternalblogcrontime'] = 'How often Moodle checks the external blogs for new entries.';
+$string['configuseexternalblogs'] = 'Enables users to add links to external blogs. Moodle regularly checks if these blogs, then copies new entries to the blog of the Moodle user.';
+$string['configmaxexternalblogsperuser'] = 'The number of external blogs each user is allowed to link to their Moodle blog.';
+$string['configuseblogassociations'] = 'Enables the association of blog entries with courses and course modules.';
 $string['courseblog'] = 'Course blog: $a';
 $string['courseblogdisable'] = 'Course blogs is not enabled';
 $string['courseblogs'] = 'Users can only see blogs for people who share a course';
-$string['donothaveblog'] = 'You do not have your own blog, sorry.';
 $string['deleteotagswarn'] = 'Are you sure you want to remove this / these tags <br />from all blog posts and remove it from the system?';
 $string['disableblogs'] = 'Disable blog system completely';
+$string['donothaveblog'] = 'You do not have your own blog, sorry.';
+$string['editentry'] = 'Edit a blog entry';
+$string['editexternalblog'] = 'Edit an external blog';
 $string['emptybody'] = 'Blog entry body can not be empty';
 $string['emptytitle'] = 'Blog entry title can not be empty';
+$string['emptyrssfeed'] = 'The URL you entered does not point to a valid RSS feed';
 $string['entrybody'] = 'Blog entry body';
 $string['entrybodyonlydesc'] = 'Entry description';
 $string['entryerrornotyours'] = 'This entry is not yours';
 $string['entrysaved'] = 'Your entry has been saved';
 $string['entrytitle'] = 'Entry title';
 $string['entryupdated'] = 'Blog entry updated';
+$string['externalblogcrontime'] = 'External blog cron schedule';
+$string['externalblogs'] = 'External blogs';
+$string['filterblogsby'] = 'Filter entries by...';
 $string['groupblog'] = 'Group blog: $a';
 $string['groupblogdisable'] = 'Group blog is not enabled';
+$string['groupblogentries'] = 'Blog entries associated with $a->coursename by group $a->groupname';
 $string['groupblogs'] = 'Users can only see blogs for people who share a group';
-$string['intro'] = 'This RSS feed was automatically generated from one or more blogs.';
 $string['incorrectblogfilter'] = 'Incorrect blog filter type specified';
+$string['intro'] = 'This RSS feed was automatically generated from one or more blogs.';
+$string['invalidurl'] = 'This URL is unreachable';
+$string['linktooriginalentry'] = 'Link to original blog entry';
+$string['maxexternalblogsperuser'] = 'Maximum number of external blogs per user';
+$string['mustassociatecourse'] = 'If you are publishing to course or group members, you must associate a course with this entry';
 $string['noentriesyet'] = 'No visible entries here';
-$string['nosuchentry'] = 'No such blog entry';
 $string['noguestpost'] = 'Guest can not post blogs!';
 $string['norighttodeletetag'] = 'You have no rights to delete this tag - $a';
+$string['nosuchentry'] = 'No such blog entry';
 $string['notallowedtoedit'] = 'You are not allowed to edit this entry';
 $string['numberofentries'] = 'Entries: $a';
 $string['numberoftags'] = 'Number of tags to display';
@@ -47,24 +74,42 @@ $string['pagesize'] = 'Number of blog entries per Page';
 $string['permalink'] = 'Permalink';
 $string['personalblogs'] = 'Users can only see their own blog';
 $string['publishto'] = 'Publish to';
+$string['publishtocourse'] = 'Users sharing a course with you';
+$string['publishtocourseassoc'] = 'Members of the associated course';
+$string['publishtocourseassocparam'] = 'Members of $a';
+$string['publishtogroup'] = 'Users sharing a group with you';
+$string['publishtogroupassoc'] = 'Your group members in the associated course';
+$string['publishtogroupassocparam'] = 'Your group members in $a';
 $string['publishtonoone'] = 'Yourself (draft)';
 $string['publishtosite'] = 'Anyone on this site';
 $string['publishtoworld'] = 'Anyone in the world';
 $string['settingsupdatederror'] = 'An error has occurred, blog preference setting could not be updated';
+$string['searchterm'] = 'Search: $a';
 $string['siteblog'] = 'Site blog: $a';
 $string['siteblogdisable'] = 'Site blog is not enabled';
 $string['siteblogs'] = 'All site users can see all blog entries';
 $string['tagdatelastused'] = 'Date tag was last used';
+$string['tagparam'] = 'Tag: $a';
+$string['tags'] = 'Tags';
 $string['tagsort'] = 'Sort the tag display by';
 $string['tagtext'] = 'Tag text';
-$string['tags'] = 'Tags';
 $string['timewithin'] = 'Display tags used within this many days';
 $string['updateentrywithid'] = 'Updating entry';
 $string['userblog'] = 'User blog: $a';
-$string['viewcourseentries'] = 'View course entries';
-$string['viewmyentries'] = 'View my entries';
-$string['viewsiteentries'] = 'View site entries';
-$string['wrongpostid'] = 'Wrong blog post id';
+$string['useblogassociations'] = 'Enable blog associations';
+$string['useexternalblogs'] = 'Enable external blogs';
+$string['userblogentries'] = 'Blog entries by $a';
+$string['viewallblogentries'] = 'All entries about this $a';
+$string['viewblogentries'] = 'Entries about this $a';
+$string['viewblogsfor'] = 'View all entries for...';
+$string['viewcourseblogs'] = 'View entries for course...';
+$string['viewgroupblogs'] = 'View entries for group...';
+$string['viewgroupentries'] = 'Group entries';
+$string['viewmodblogs'] = 'View entries for module...';
+$string['viewmodentries'] = 'Module entries';
+$string['viewmyentries'] = 'My entries';
+$string['viewsiteentries'] = 'All entries';
+$string['viewuserentries'] = 'User entries';
 $string['worldblogs'] = 'The world can read entries set to be world-accessible';
-
+$string['wrongpostid'] = 'Wrong blog post id';
 ?>
diff --git a/lang/en_utf8/help/blog/description.html b/lang/en_utf8/help/blog/description.html
new file mode 100644 (file)
index 0000000..bf79096
--- /dev/null
@@ -0,0 +1,4 @@
+<h1>Description</h1>
+
+<p>A description of the overall contents of your external blog. If left empty, this will default to the
+description recorded in your external blog (if any).</p>
diff --git a/lang/en_utf8/help/blog/name.html b/lang/en_utf8/help/blog/name.html
new file mode 100644 (file)
index 0000000..67bd2b2
--- /dev/null
@@ -0,0 +1,3 @@
+<h1>Name</h1>
+
+<p>A descriptive name for your external blog. If empty, will default to the title of your external blog.</p>
diff --git a/lang/en_utf8/help/blog/tags.html b/lang/en_utf8/help/blog/tags.html
new file mode 100644 (file)
index 0000000..3fd3deb
--- /dev/null
@@ -0,0 +1,5 @@
+<h1>Tags</h1>
+
+<p>A comma-separated list of Tags that can will be automatically attached to every blog entry copied from your
+external blog into this site. These tags can be used to filter blog entries and find the ones that are associated
+with this external blog.</p>
diff --git a/lang/en_utf8/help/blog/url.html b/lang/en_utf8/help/blog/url.html
new file mode 100644 (file)
index 0000000..e28e167
--- /dev/null
@@ -0,0 +1,5 @@
+<h1>URL</h1>
+
+<p>Almost every blog has the ability to publish its contents to the world in the form of an RSS URL. Consult your external blog's configuration
+and documentation if you are unsure of what this URL should look like. When you have it, enter it in this field. Once you submit the form,
+your link will be checked to see if it is a valid URL.</p>
index 88bf5690e17149907dfa21b12a92b695d4da339a..76c650a42c80a1419ca1b814e93ec51f8d2b2958 100755 (executable)
@@ -2309,8 +2309,10 @@ function delete_context($contextlevel, $instanceid) {
     if ($context = $DB->get_record('context', array('contextlevel'=>$contextlevel, 'instanceid'=>$instanceid))) {
         $result = $DB->delete_records('role_assignments', array('contextid'=>$context->id)) &&
                   $DB->delete_records('role_capabilities', array('contextid'=>$context->id)) &&
+                  $DB->delete_records('context', array('id'=>$context->id)) &&
                   $DB->delete_records('role_names', array('contextid'=>$context->id)) &&
-                  $DB->delete_records('context', array('id'=>$context->id));
+                  $DB->delete_records('blog_association', array('contextid'=>$context->id));
+                  
 
         // do not mark dirty contexts if parents unknown
         if (!is_null($context->path) and $context->depth > 0) {
index 79b8f3555f8d7ff944e6c98edc4f5169dd22f8ef..d9f45f275d42bf10f6bf2fcc506e7dd5262f9468 100644 (file)
@@ -5673,7 +5673,9 @@ function print_plugin_tables() {
                                         'admin',
                                         'admin_bookmarks',
                                         'admin_tree',
+                                        'blog_externals',
                                         'blog_menu',
+                                        'blog_recent',
                                         'blog_tags',
                                         'calendar_month',
                                         'calendar_upcoming',
index 8ff7b5c3c5805361d7b05dae20c8c96931ee88cd..9f389fd24bdce389ea6d6c04b5dfb99f6f8eb769 100644 (file)
@@ -799,6 +799,22 @@ $moodle_capabilities = array(
             'admin' => CAP_ALLOW
         )
     ),
+    
+    'moodle/blog:manageexternal' => array(
+
+        'riskbitmask' => RISK_SPAM,
+
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_USER,
+        'legacy' => array(
+            'student' => CAP_ALLOW,
+            'user' => CAP_ALLOW,
+            'teacher' => CAP_ALLOW,
+            'editingteacher' => CAP_ALLOW,
+            'admin' => CAP_ALLOW
+        )
+    ),
+
 
     'moodle/calendar:manageownentries' => array( // works in CONTEXT_SYSTEM only
 
index 6ba9fbbe7848842a04a1b3ccf4fca5658f7346a9..1686ffc1066c13d7d7d966b2ae840d16a3c31e60 100644 (file)
         <FIELD NAME="content" TYPE="text" LENGTH="big" NOTNULL="false" SEQUENCE="false" PREVIOUS="summary" NEXT="uniquehash"/>
         <FIELD NAME="uniquehash" TYPE="char" LENGTH="128" NOTNULL="true" SEQUENCE="false" PREVIOUS="content" NEXT="rating"/>
         <FIELD NAME="rating" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="uniquehash" NEXT="format"/>
-        <FIELD NAME="format" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="rating" NEXT="attachment"/>
-        <FIELD NAME="attachment" TYPE="char" LENGTH="100" NOTNULL="false" SEQUENCE="false" COMMENT="attachment" PREVIOUS="format" NEXT="publishstate"/>
+        <FIELD NAME="format" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="rating" NEXT="summaryformat"/>
+        <FIELD NAME="summaryformat" TYPE="int" LENGTH="2" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="format" NEXT="attachment"/>
+        <FIELD NAME="attachment" TYPE="char" LENGTH="100" NOTNULL="false" SEQUENCE="false" COMMENT="attachment" PREVIOUS="summaryformat" NEXT="publishstate"/>
         <FIELD NAME="publishstate" TYPE="char" LENGTH="20" NOTNULL="true" DEFAULT="draft" SEQUENCE="false" PREVIOUS="attachment" NEXT="lastmodified"/>
         <FIELD NAME="lastmodified" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="publishstate" NEXT="created"/>
         <FIELD NAME="created" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="lastmodified" NEXT="usermodified"/>
         <INDEX NAME="parentcontextid-showinsubcontexts-pagetypepattern-subpagepattern" UNIQUE="false" FIELDS="parentcontextid, showinsubcontexts, pagetypepattern, subpagepattern"/>
       </INDEXES>
     </TABLE>
-    <TABLE NAME="block_positions" COMMENT="Stores the position of a sticky block_instance on a another page than the one where it was added." PREVIOUS="block_instances" NEXT="comments">
+    <TABLE NAME="block_positions" COMMENT="Stores the position of a sticky block_instance on a another page than the one where it was added." PREVIOUS="block_instances" NEXT="blog_association">
       <FIELDS>
         <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="true" NEXT="blockinstanceid"/>
         <FIELD NAME="blockinstanceid" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="false" COMMENT="The block_instance this position relates to." PREVIOUS="id" NEXT="contextid"/>
         <INDEX NAME="blockinstanceid-contextid-pagetype-subpage" UNIQUE="true" FIELDS="blockinstanceid, contextid, pagetype, subpage"/>
       </INDEXES>
     </TABLE>
-    <TABLE NAME="comments" COMMENT="moodle comments module" PREVIOUS="block_positions">
+    <TABLE NAME="blog_association" COMMENT="Associations of blog entries with courses and module instances." PREVIOUS="block_positions" NEXT="blog_external">
+      <FIELDS>
+        <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="true" NEXT="contextid"/>
+        <FIELD NAME="contextid" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="false" PREVIOUS="id" NEXT="blogid"/>
+        <FIELD NAME="blogid" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="false" PREVIOUS="contextid"/>
+      </FIELDS>
+      <KEYS>
+        <KEY NAME="id" TYPE="primary" FIELDS="id"/>
+      </KEYS>
+      <INDEXES>
+        <INDEX NAME="contextid" UNIQUE="false" FIELDS="contextid" NEXT="blogid"/>
+        <INDEX NAME="blogid" UNIQUE="false" FIELDS="blogid" PREVIOUS="contextid"/>
+      </INDEXES>
+    </TABLE>
+    <TABLE NAME="blog_external" COMMENT="External blog links used for RSS copying of blog entries to Moodle." PREVIOUS="blog_association" NEXT="comments">
+      <FIELDS>
+        <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="true" NEXT="userid"/>
+        <FIELD NAME="userid" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="false" PREVIOUS="id" NEXT="name"/>
+        <FIELD NAME="name" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" PREVIOUS="userid" NEXT="description"/>
+        <FIELD NAME="description" TYPE="text" LENGTH="small" NOTNULL="false" SEQUENCE="false" PREVIOUS="name" NEXT="url"/>
+        <FIELD NAME="url" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" PREVIOUS="description" NEXT="timemodified"/>
+        <FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="false" UNSIGNED="true" SEQUENCE="false" PREVIOUS="url" NEXT="timefetched"/>
+        <FIELD NAME="timefetched" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="timemodified"/>
+      </FIELDS>
+      <KEYS>
+        <KEY NAME="id_key" TYPE="primary" FIELDS="id"/>
+      </KEYS>
+      <INDEXES>
+        <INDEX NAME="mdl1_blogexte_use_ix" UNIQUE="false" FIELDS="userid"/>
+      </INDEXES>
+    </TABLE>
+    <TABLE NAME="comments" COMMENT="moodle comments module" PREVIOUS="blog_external">
       <FIELDS>
         <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="true" NEXT="contextid"/>
         <FIELD NAME="contextid" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="false" PREVIOUS="id" NEXT="commentarea"/>
index be20f161e1328838bb34f0d657f3e5eb087af502..3ffd1e153cd14a3974fa29d29e1b4f1f9e0c8f6d 100644 (file)
@@ -2310,6 +2310,74 @@ WHERE gradeitemid IS NOT NULL AND grademax IS NOT NULL");
         upgrade_main_savepoint($result, 2009070100);
     }
 
+    if ($result && $oldversion < 2009070200) {
+    /// Define table blog_association to be created
+        $table = new xmldb_table('blog_association');
+
+    /// Adding fields to table blog_association
+        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null, null, null);
+        $table->add_field('contextid', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, null);
+        $table->add_field('blogid', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, null);
+    /// Adding keys to table blog_association
+        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
+        $table->add_key('contextid', XMLDB_KEY_FOREIGN, array('contextid'), 'context', array('id'));
+        $table->add_key('blogid', XMLDB_KEY_FOREIGN, array('blogid'), 'post', array('id'));
+
+        if (!$dbman->table_exists($table)) {
+        /// Launch create table for blog_association
+            $dbman->create_table($table);
+        }
+
+
+    /// Main savepoint reached
+        upgrade_main_savepoint($result, 2009070200);
+    }
+
+    if ($result && $oldversion < 2009070300) {
+
+    /// Define table blog_external to be created
+        $table = new xmldb_table('blog_external');
+
+    /// Adding fields to table blog_external
+        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
+        $table->add_field('userid', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null);
+        $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
+        $table->add_field('description', XMLDB_TYPE_TEXT, 'small', null, null, null, null);
+        $table->add_field('url', XMLDB_TYPE_TEXT, 'small', null, XMLDB_NOTNULL, null, null);
+        $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, null, null, null);
+
+    /// Adding keys to table blog_external
+        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
+
+    /// Conditionally launch create table for blog_external
+        if (!$dbman->table_exists($table)) {
+            $dbman->create_table($table);
+        }
+
+    /// Main savepoint reached
+        upgrade_main_savepoint($result, 2009070300);
+    }
+     
+    if ($result && $oldversion < 2009070800) {
+
+    /// Define field timefetched to be added to blog_external
+        $table = new xmldb_table('blog_external');
+        $field = new xmldb_field('timefetched', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0', 'timemodified');
+        $index = new xmldb_index('userid_idx', XMLDB_INDEX_NOTUNIQUE, array('userid'));
+
+    /// Conditionally launch add field timefetched
+        if (!$dbman->field_exists($table, $field)) {
+            $dbman->add_field($table, $field);
+        }
+        
+    /// Conditionally launch add index userid_idx
+        if (!$dbman->index_exists($table, $index)) {
+            $dbman->add_index($table, $index);
+        }
+    /// Main savepoint reached
+        upgrade_main_savepoint($result, 2009070800);
+    }
+
     if ($result && $oldversion < 2009071000) {
 
     /// Rename field contextid on table block_instances to parentcontextid
@@ -2342,6 +2410,21 @@ WHERE gradeitemid IS NOT NULL AND grademax IS NOT NULL");
     /// Main savepoint reached
         upgrade_main_savepoint($result, 2009071300);
     }
+    
+    if ($result && $oldversion < 2009071600) {
+
+    /// Define field summaryformat to be added to post
+        $table = new xmldb_table('post');
+        $field = new xmldb_field('summaryformat', XMLDB_TYPE_INTEGER, '2', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0', 'format');
+
+    /// Conditionally launch add field summaryformat
+        if (!$dbman->field_exists($table, $field)) {
+            $dbman->add_field($table, $field);
+        }
+
+    /// Main savepoint reached
+        upgrade_main_savepoint($result, 2009071600);
+    }
 
     if ($result && $oldversion < 2009072400) {
 
index c2b3e0e8daa3353c338f8879dcd62c10919ff166..ce08b6b5efd9bf80bf622f45b3eaed37efce1ac6 100644 (file)
@@ -51,6 +51,34 @@ class MoodleQuickForm_format extends MoodleQuickForm_select{
         }
     } //end constructor
 
+    /**
+     * Add a single button.
+     *
+     * @param string $elementname name of the element to add the item to
+     * @param array $button arguments to pass to function $function
+     * @param boolean $suppresscheck whether to throw an error if the element
+     *                                  doesn't exist.
+     * @param string $function - function to generate html from the arguments in $button
+     * @param string $function
+     */
+    function setHelpButton($button, $function='helpbutton'){
+        global $OUTPUT;
+        //_elements has a numeric index, this code accesses the elements by name
+        $buttonparams = array('page', 'text', 'module', 'image', 'linktext', 'text', 'return', 'imagetext');
+        $helpiconoptions = array('page' => null, 'text' => null, 'module' => 'moodle', 'image' => null, 'linktext' => false);
+
+        foreach ($button as $key => $val) {
+            if (isset($button[$key])) {
+                $helpiconoptions[$buttonparams[$key]] = $val;
+            }
+        }
+        $helpicon = moodle_help_icon::make($helpiconoptions['page'], $helpiconoptions['text'], $helpiconoptions['module'], $helpiconoptions['linktext']);
+        if (!$helpiconoptions['image']) {
+            $helpicon->image = false;
+        }
+
+        $this->_helpbutton = $OUTPUT->help_icon($helpicon);
+    }
     /**
      * Called by HTML_QuickForm whenever form event is made on this element
      *
@@ -96,4 +124,4 @@ class MoodleQuickForm_format extends MoodleQuickForm_select{
     }
 
 }
-?>
\ No newline at end of file
+?>
index 92a69cba198143dce8f0af329eab93a2a49f25d4..bdb81c35733213b45633bbbdb0e18afacde3a52a 100644 (file)
@@ -129,4 +129,4 @@ class MoodleQuickForm_select extends HTML_QuickForm_select{
         }
     }
 }
-?>
\ No newline at end of file
+?>
index 027447f1b37b8dee5b534f1314985330a48d23c6..bc1618d2d57e5b12de55285c401cef0f625d22cc 100644 (file)
@@ -1349,6 +1349,17 @@ class html_image extends labelled_html_component {
         $this->add_class('image');
         parent::prepare();
     }
+
+    /**
+     * Shortcut for initialising a html_image.
+     *
+     * @param mixed $url The URL to the image (string or moodle_url)
+     */
+    public function make($url) {
+        $image = new html_image();
+        $image->src = $url;
+        return $image;
+    }
 }
 
 /**
diff --git a/mod/assignment/type/blog/assignment.class.php b/mod/assignment/type/blog/assignment.class.php
new file mode 100644 (file)
index 0000000..4a79003
--- /dev/null
@@ -0,0 +1,326 @@
+<?php 
+require_once($CFG->dirroot .'/blog/lib.php');
+require_once($CFG->libdir.'/formslib.php');
+
+
+/**
+ * Extend the base assignment class for offline assignments
+ *
+ */
+class assignment_blog extends assignment_base {
+
+    function assignment_blog($cmid='staticonly', $assignment=NULL, $cm=NULL, $course=NULL) {
+        parent::assignment_base($cmid, $assignment, $cm, $course);
+        $this->type = 'blog';
+    }
+
+    function display_lateness($timesubmitted) {
+        return '';
+    }
+
+    function print_student_answer($userid, $return=false){
+        global $CFG, $DB;
+        if (!$submission = $this->get_submission($userid)) {
+            return '';
+        }
+    $post = $DB->get_record('post', array('id' => $submission->data1));
+        $ret = '<b>'.$post->subject.': </b><br>'.shorten_text(format_text($post->summary));
+    $ret .= '<a href="'.$CFG->wwwroot.'/blog/index.php?postid='.$post->id.'" target="_blank">Full Entry</a><br>';
+
+        return $ret;
+    }
+
+
+    function setup_elements(&$mform) {
+        $ynoptions = array( 0 => get_string('no'), 1 => get_string('yes'));
+        //$mform->addElement('select', 'var1', get_string('multiassoc', 'assignment'), $ynoptions);
+        //$mform->setHelpButton('var1', array('multiassoc', get_string('multiassoc', 'assignment'), 'assignment'));
+        //$mform->setDefault('var1', 0);
+        
+        $publishstates = array();
+        $i = 0;
+        foreach(blog_applicable_publish_states() as $state) $publishstates[$i++] = $state; 
+        $mform->addElement('select', 'var2', get_string('maxpublishstate', 'assignment'), $publishstates);
+        $mform->setDefault('var2', 0);
+    }
+
+    function prepare_new_submission($userid) {
+        $submission = new Object;
+        $submission->assignment   = $this->assignment->id;
+        $submission->userid       = $userid;
+        $submission->timecreated  = time(); // needed for offline assignments
+        $submission->timemodified = $submission->timecreated;
+        $submission->numfiles     = 0;
+        $submission->data1        = '';
+        $submission->data2        = '';
+        $submission->grade        = -1;
+        $submission->submissioncomment      = '';
+        $submission->format       = 0;
+        $submission->teacher      = 0;
+        $submission->timemarked   = 0;
+        $submission->mailed       = 0;
+        return $submission;
+    }
+
+    // needed for the timemodified override
+    function process_feedback() {
+        global $CFG, $USER, $DB;
+        require_once($CFG->libdir.'/gradelib.php');
+
+        if (!$feedback = data_submitted()) {      // No incoming data?
+            return false;
+        }
+
+        ///For save and next, we need to know the userid to save, and the userid to go
+        ///We use a new hidden field in the form, and set it to -1. If it's set, we use this
+        ///as the userid to store
+        if ((int)$feedback->saveuserid !== -1){
+            $feedback->userid = $feedback->saveuserid;
+        }
+
+        if (!empty($feedback->cancel)) {          // User hit cancel button
+            return false;
+        }
+
+        $grading_info = grade_get_grades($this->course->id, 'mod', 'assignment', $this->assignment->id, $feedback->userid);
+
+        // store outcomes if needed
+        $this->process_outcomes($feedback->userid);
+
+        $submission = $this->get_submission($feedback->userid, true);  // Get or make one
+
+        if (!$grading_info->items[0]->grades[$feedback->userid]->locked and
+            !$grading_info->items[0]->grades[$feedback->userid]->overridden) {
+
+            $submission->grade      = $feedback->grade;
+            $submission->submissioncomment    = $feedback->submissioncomment;
+            $submission->format     = $feedback->format;
+            $submission->teacher    = $USER->id;
+            $mailinfo = get_user_preferences('assignment_mailinfo', 0);
+            if (!$mailinfo) {
+                $submission->mailed = 1;       // treat as already mailed
+            } else {
+                $submission->mailed = 0;       // Make sure mail goes out (again, even)
+            }
+            $submission->timemarked = time();
+
+            unset($submission->data1);  // Don't need to update this.
+            unset($submission->data2);  // Don't need to update this.
+
+            if (empty($submission->timemodified)) {   // eg for offline assignments
+                $submission->timemodified = time();
+            }
+
+            if (! $DB->update_record('assignment_submissions', $submission)) {
+                return false;
+            }
+
+            // triger grade event
+            $this->update_grade($submission);
+
+            add_to_log($this->course->id, 'assignment', 'update grades',
+                       'submissions.php?id='.$this->assignment->id.'&user='.$feedback->userid, $feedback->userid, $this->cm->id);
+        }
+
+        return $submission;
+
+    }
+
+
+    function view() {
+
+        global $USER, $DB, $CFG, $COURSE;
+
+        $edit  = optional_param('edit', 0, PARAM_BOOL);
+        $saved = optional_param('saved', 0, PARAM_BOOL);
+
+        $context = get_context_instance(CONTEXT_MODULE, $this->cm->id);
+        require_capability('mod/assignment:view', $context);
+
+        $submission = $this->get_submission();
+
+        //Guest can not submit nor edit an assignment (bug: 4604)
+        if (!has_capability('mod/assignment:submit', $context)) {
+            $editable = null;
+        } else {
+            $editable = $this->isopen();
+        }
+        $editmode = ($editable and $edit);
+
+        if ($editmode) {
+            //guest can not edit or submit assignment
+            if (!has_capability('mod/assignment:submit', $context)) {
+                print_error('guestnosubmit', 'assignment');
+            }
+        }
+
+        add_to_log($this->course->id, "assignment", "view", "view.php?id={$this->cm->id}", $this->assignment->id, $this->cm->id);
+
+/// prepare form and process submitted data
+        $mform = new mod_assignment_blog_edit_form();
+        if($this->assignment->var1) {  //allow multiple associations
+            $mform->set_multiple_assoc();
+        }
+
+        $defaults = new object();
+       if($submission = $this->get_submission()) {
+            $defaults->selectblog = $submission->data1;
+        }
+        $defaults->id = $this->cm->id;
+
+        $mform->set_data($defaults);
+
+        if ($mform->is_cancelled()) {
+            redirect('view.php?id='.$this->cm->id);
+        }
+
+        if ($data = $mform->get_data()) {      // No incoming data?
+            if ($editable && $this->update_submission($data)) {
+                //TODO fix log actions - needs db upgrade
+                $submission = $this->get_submission();
+                add_to_log($this->course->id, 'assignment', 'upload',
+                        'view.php?a='.$this->assignment->id, $this->assignment->id, $this->cm->id);
+                $this->email_teachers($submission);
+                //redirect to get updated submission date and word count
+                redirect('view.php?id='.$this->cm->id.'&saved=1');
+            } else {
+                // TODO: add better error message
+                notify(get_string("error")); //submitting not allowed!
+            }
+        }
+
+/// print header, etc. and display form if needed
+        if ($editmode) {
+            $this->view_header(get_string('editmysubmission', 'assignment'));
+        } else {
+            $this->view_header();
+        }
+
+        $this->view_intro();
+
+        $this->view_dates();
+
+        if ($saved) {
+            notify(get_string('submissionsaved', 'assignment'), 'notifysuccess');
+        }
+
+        if (has_capability('mod/assignment:submit', $context)) {
+            print_simple_box_start('center', '70%', '', 0, 'generalbox', 'online');
+            if ($editmode) {
+                if($DB->record_exists('post', array('module'=>'blog', 'userid'=>$USER->id))) {
+                   $mform->display();
+                } else {
+                    echo '<div class="noticebox">'.get_string('noblogs', 'assignment').'</div>';
+                    echo '<br><a href="'. $CFG->wwwroot. '/blog/edit.php?action=add&courseid='
+                                   .$COURSE->id.'">'.get_string('addnewentry', 'blog') ."</a>";
+                }
+            } else {
+                if ($submission) {
+                    blog_print_entry($DB->get_record('post', array('id' => $submission->data1)));
+                } else if (!has_capability('mod/assignment:submit', $context)) { //fix for #4604
+                    echo '<div style="text-align:center">'. get_string('guestnosubmit', 'assignment').'</div>';
+                } else if ($this->isopen()) {    //fix for #4206
+                    echo '<div style="text-align:center">'.get_string('emptysubmission', 'assignment').'</div>';
+                }
+            }
+            print_simple_box_end();
+            if (!$editmode && $editable) {
+                echo "<div style='text-align:center'>";
+                print_single_button('view.php', array('id'=>$this->cm->id,'edit'=>'1'),
+                        get_string('editmysubmission', 'assignment'));
+                echo "</div>";
+            }
+
+        }
+
+        $this->view_feedback();
+
+        $this->view_footer();
+    }
+
+
+    function update_submission($data) {
+        global $CFG, $USER, $DB, $COURSE;
+
+        $submission = $this->get_submission($USER->id, true);
+
+        $update = new object();
+        $update->id           = $submission->id;
+        $update->data1        = $data->selectblog;
+        $update->timemodified = time();
+        
+        //enforce access restriction
+        $postaccess = -1;
+        $i=0;
+        $post = $DB->get_record('post', array('id' => $data->selectblog));
+        if(!$post) {
+            print_error('blognotfound', 'blog');
+        }
+        $publishstates = array();
+        foreach(blog_applicable_publish_states() as $state => $desc) {
+            if($state == $post->publishstate) {
+                $postaccess = $i;
+            }
+            $publishstates[$i++] = $state;
+        } 
+
+        if($this->assignment->var2 < $postaccess) {
+            $post->publishstate = $publishstates[$this->assignment->var2];
+            $DB->update_record('post', $post);
+        } 
+        
+        //force the user to have strict associations with this post
+        blog_remove_associations_for_post($post->id);  //remove all existing associations
+        //add assignment association
+        $assignmentmodid = $DB->get_field('modules', 'id', array('name' => 'assignment'));
+        $modcontext = get_context_instance(CONTEXT_MODULE, $DB->get_field('course_modules', 'id', 
+                                           array('module' => $assignmentmodid, 'instance' => $this->assignment->id))); 
+        blog_add_association($post->id, $modcontext->id);
+        //add course association
+        $coursecontext = get_context_instance(CONTEXT_COURSE, $DB->get_field('course_modules', 'course', 
+                                           array('module' => $assignmentmodid, 'instance' => $this->assignment->id))); 
+        blog_add_association($post->id, $coursecontext->id);
+        
+        if (!$DB->update_record('assignment_submissions', $update)) {
+            return false;
+        }
+        
+        $submission = $this->get_submission($USER->id);
+        $this->update_grade($submission);
+        return true;
+    }
+
+
+}
+
+class mod_assignment_blog_edit_form extends moodleform {
+    function definition() {
+        global $USER, $DB;
+        $mform =& $this->_form;
+
+        // visible elements
+        //$mform->addRule('text', get_string('required'), 'required', null, 'client');
+       
+        $blogentries = array();
+        foreach($DB->get_records('post', array('userid' => $USER->id)) as $rec) {
+            $blogentries[$rec->id] = userdate($rec->created) . ' - ' . $rec->summary;
+        }
+        
+        $mform->addElement('select', 'selectblog', get_string('selectblog', 'assignment'), $blogentries); 
+
+        // hidden params
+        $mform->addElement('hidden', 'id', 0);
+        $mform->setType('id', PARAM_INT);
+
+        // buttons
+        $this->add_action_buttons();
+    }
+    
+    function set_multiple_assoc() {
+        $mform =& $this->_form;
+        $selectblog = $mform->getElement('selectblog');
+        $selectblog->setMultiple(true);
+    }
+}
+
+?>
index b00df242e4ded01c705ed7b9e008a2bde6b3ca8c..6ea4d55d97e37c90c050cc33d9a546e734dff5ce 100644 (file)
@@ -5,7 +5,7 @@
 //  This fragment is called by /admin/index.php
 ////////////////////////////////////////////////////////////////////////////////
 
-$module->version  = 2009042001;
+$module->version  = 2009062500;
 $module->requires = 2009041700;  // Requires this Moodle version
 $module->cron     = 60;
 
index 9ff6e0c5469a20a3bc530ed3480ae0329651652b..395a31d59801864cd56798b7f6645b63de649ead 100644 (file)
@@ -100,7 +100,7 @@ if ($courses = coursetag_get_tagged_courses($tag->id)) {
 if (has_capability('moodle/blog:view', $systemcontext)) {  // You have to see blogs obviously
 
     $count = 10;
-    if ($blogs = blog_fetch_entries('', $count, 0, 'site', '', $tag->id)) {
+    if ($blogs = blog_fetch_entries(array('tag'=>$tag->id)), $count) {
 
         echo $OUTPUT->box_start('generalbox', 'tag-blogs');
         $heading = get_string('relatedblogs', 'tag', $tagname). ' ' . get_string('taggedwith', 'tag', $tagname);
@@ -127,7 +127,7 @@ if (has_capability('moodle/blog:view', $systemcontext)) {  // You have to see bl
         }
         echo '</ul>';
 
-        echo '<p class="moreblogs"><a href="'.$CFG->wwwroot.'/blog/index.php?filtertype=site&amp;filterselect=0&amp;tagid='.$tag->id.'">'.get_string('seeallblogs', 'tag', $tagname).'</a></p>';
+        echo '<p class="moreblogs"><a href="'.blog_get_blogs_url(array('tag'=>$tag->id)).'">'.get_string('seeallblogs', 'tag', $tagname).'</a></p>';
 
         echo $OUTPUT->box_end();
     }
index bd7eec9c05bef274d239ab7fbc5611cd97783527..e396b1a30432fc78813c3d4c41b7e038ad65d886 100644 (file)
@@ -511,7 +511,7 @@ table.flexible .r1 {
  *** Blogs
  ***/
 
-.blogpost.blogdraft .content {
+.blog_entry.blogdraft .content {
   background-color:#EEEEEE;
 }
 
index 3dcda73c195ffafade96402d18c67d81c4ea776c..6675f060767919bdf18caca9b33029bb94a32fa7 100644 (file)
@@ -406,11 +406,11 @@ a.skip-block {
  *** Blogs
  ***/
 
-.blogpost .audience {
+.blog_entry .audience {
   font-size: 0.85em;
 }
 
-.blogpost .tags {
+.blog_entry .tags {
   font-size: 0.85em;
 }
 
index 4ea1795873f19e30c690f6e8bada2980d47ee0c0..39114f0ff8ba40a2165fb654d6036c560a297f62 100644 (file)
@@ -1977,15 +1977,31 @@ body.has_navigation_bar {
   text-align: center;
 }
 
-.blogpost .audience {
+.blog_entry .audience {
   text-align: right;
 }
 
-.blogpost .tags {
+.blog_entry .tags {
   margin-top: 15px;
 }
 
+#blog-external form input {
+  width: 260px;
+}
+
+#blog-external #id_submitbutton, #blog-external #id_cancel {
+  width: auto;
+}
+
+.block_blog_externals a.delete {
+  margin-left: 6px;
+}
 
+.block_blog_externals div.newlink {
+  margin-top: 10px;
+  text-align: center;
+  width: 100%;
+}
 /***
  *** Calendar
  ***/
index a2238b2af78ba22fd765bd21d70fa82834c5202b..181351721cd035d60de59c36feeacea986fd2517 100644 (file)
@@ -2,6 +2,7 @@
 /// This file to be included so we can assume config.php has already been included.
 /// We also assume that $user, $course, $currenttab have been set
 
+    require_once($CFG->dirroot.'/blog/lib.php');
     require_once($CFG->libdir . '/portfoliolib.php');
 
     if (!isset($filtertype)) {
@@ -42,7 +43,7 @@
                     get_string('participants'));
             }
 
-            $toprow[] = new tabobject('blogs', $CFG->wwwroot.'/blog/index.php?filtertype=site&amp;',
+            $toprow[] = new tabobject('blogs', blog_get_blogs_url(array()),
                 get_string('blogs','blog'));
         }
 
@@ -59,7 +60,7 @@
             get_string('participants'));
 
         if ($CFG->bloglevel >= 3) {
-            $toprow[] = new tabobject('blogs', $CFG->wwwroot.'/blog/index.php?filtertype=course&amp;filterselect='.$filterselect, get_string('blogs','blog'));
+            $toprow[] = new tabobject('blogs', blog_get_blogs_url(array('course'=>$filterselect)), get_string('blogs','blog'));
         }
 
         if (!empty($CFG->enablenotes) and (has_capability('moodle/notes:manage', $coursecontext) || has_capability('moodle/notes:view', $coursecontext))) {
@@ -80,7 +81,7 @@
                 get_string('participants'));
 
 
-            $toprow[] = new tabobject('blogs', $CFG->wwwroot.'/blog/index.php?filtertype=group&amp;filterselect='.$filterselect, get_string('blogs','blog'));
+            $toprow[] = new tabobject('blogs', blog_get_blogs_url(array('group'=>$filterselect)), get_string('blogs','blog'));
         }
 
     /**************************************
             ) // able to read blogs in site or course context
         ) { //end if
 
-            $toprow[] = new tabobject('blogs', $CFG->wwwroot.'/blog/index.php?userid='.$user->id.'&amp;courseid='.$course->id, get_string('blog', 'blog'));
+            $toprow[] = new tabobject('blogs', blog_get_blogs_url(array('user'=>$user->id,'course'=>$course->id)), get_string('blog', 'blog'));
         }
 
         if (!empty($CFG->enablenotes) and (has_capability('moodle/notes:manage', $coursecontext) || has_capability('moodle/notes:view', $coursecontext))) {