From: nicolasconnault Date: Fri, 4 Sep 2009 00:36:43 +0000 (+0000) Subject: MDL-19676 Blog improvements X-Git-Url: http://git.mjollnir.org/gw?a=commitdiff_plain;h=cae837087adcb175ecc33935560aebaabcca5e1f;p=moodle.git MDL-19676 Blog improvements --- diff --git a/admin/cron.php b/admin/cron.php index 20f7d970fa..cd6982811a 100644 --- a/admin/cron.php +++ b/admin/cron.php @@ -544,6 +544,17 @@ } } } + + // 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(); diff --git a/admin/settings/appearance.php b/admin/settings/appearance.php index 73467fdfee..78d962fe88 100644 --- a/admin/settings/appearance.php +++ b/admin/settings/appearance.php @@ -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'))); diff --git a/admin/settings/security.php b/admin/settings/security.php index 5799bce1d4..9b253d7ca8 100644 --- a/admin/settings/security.php +++ b/admin/settings/security.php @@ -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')); diff --git a/backup/backuplib.php b/backup/backuplib.php index a391e6d6d3..2adc6cdce6 100644 --- a/backup/backuplib.php +++ b/backup/backuplib.php @@ -155,9 +155,9 @@ //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) { @@ -922,54 +922,10 @@ 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++; @@ -990,6 +946,69 @@ 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) */ @@ -3353,6 +3372,23 @@ } } + //Backup course blog assignment data, if any. + if (!defined('BACKUP_SILENTLY')) { + echo '
  • '.get_string("courseblogdata").'
  • '; + } + 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 index 0000000000..86ed24f6d4 --- /dev/null +++ b/blocks/blog_externals/block_blog_externals.php @@ -0,0 +1,92 @@ +. + + +/** + * 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 = '' . + ''.$strdelete.'' . + "\n"; + $output .= '
  • '.shorten_text($eb->name, 20)."$deleteicon
  • \n"; + } + + $this->content->text = '\n"; + $this->content->text .= ''; + return $this->content; + } +} diff --git a/blocks/blog_menu/block_blog_menu.php b/blocks/blog_menu/block_blog_menu.php index 2967304084..19823d92e3 100755 --- a/blocks/blog_menu/block_blog_menu.php +++ b/blocks/blog_menu/block_blog_menu.php @@ -1,4 +1,30 @@ -. + + +/** + * 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 = '
  • '.get_string('viewblogentries', 'blog', $strlevel).'
  • '; + } - /// 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 = '&courseid='.$this->page->course->id; - // a course is specified + // show View site entries link + if ($CFG->bloglevel >= BLOG_SITE_LEVEL && $canviewblogs) { + $output .= '
  • '; + $output .= get_string('viewsiteentries', 'blog')."
  • \n"; + } - $courseviewlink = '
  • '; - $courseviewlink .= get_string('viewcourseentries', 'blog') ."
  • \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 = '
  • '.get_string('addnewentry', 'blog') ."
  • \n"; - } - // show View my entries link - $addentrylink .= '
  • '.get_string('viewmyentries', 'blog'). - "
  • \n"; - - // show link to manage blog prefs - $addentrylink .= '
  • '. - get_string('blogpreferences', 'blog')."
  • \n"; - - $output = $addentrylink; - $output .= $courseviewlink; + // show View my entries link + if ($context->contextlevel != CONTEXT_USER) { + $output .= '
  • \n"; + } - // show View site entries link - if ($CFG->bloglevel >= BLOG_SITE_LEVEL && $canviewblogs) { - $output .= '
  • '; - $output .= get_string('viewsiteentries', 'blog')."
  • \n"; + // show link to manage blog prefs + $output .= '
  • '. + get_string('blogpreferences', 'blog')."
  • \n"; + + // show Add entry link + $sitecontext = get_context_instance(CONTEXT_SYSTEM); + if (has_capability('moodle/blog:create', $sitecontext)) { + $output .= '
  • \n"; + } - // took out tag management interface/link, should use tag/manage.php + // Full-text search field - // show Help with blogging link - //$output .= '
  • '; - //$output .= get_string('helpblogging', 'blog') ."
  • \n"; - //} else { - // $output = ''; //guest users and users who are not logged in do not get menus - //} + $output .= '
  • '; + $output .= '
    '; + if (!empty($parts)) { + foreach ($parts as $var => $val) { + $output .= ''; + } + } + + $output .= '
  • '; $this->content->text = '\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 index 0000000000..9e895744a1 --- /dev/null +++ b/blocks/blog_recent/block_blog_recent.php @@ -0,0 +1,112 @@ +. + + +/** + * 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 = ''; + } +} diff --git a/blocks/tags/block_tags.php b/blocks/tags/block_tags.php index e27b5315c2..f53203f2c8 100644 --- a/blocks/tags/block_tags.php +++ b/blocks/tags/block_tags.php @@ -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 {
    - +
    diff --git a/blog/edit.php b/blog/edit.php index 97d5516c68..6b37aa5ec8 100755 --- a/blog/edit.php +++ b/blog/edit.php @@ -1,14 +1,42 @@ -. + +/** + * 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 .= '&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 '
    '; 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 index 0000000000..69a9abb412 --- /dev/null +++ b/blog/edit_form.js @@ -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 . + +//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; + } + } + } + } + } +} + diff --git a/blog/edit_form.php b/blog/edit_form.php index 2c26d0e456..00b82f6650 100644 --- a/blog/edit_form.php +++ b/blog/edit_form.php @@ -1,32 +1,91 @@ -. 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 index 0000000000..2fa1a3f481 --- /dev/null +++ b/blog/external.php @@ -0,0 +1,130 @@ +. + + +/** + * 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 index 0000000000..c9c69108b7 --- /dev/null +++ b/blog/external_form.php @@ -0,0 +1,107 @@ +. + + +/** + * 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))); + } + } +} diff --git a/blog/header.php b/blog/header.php index 4efbc0a5bb..0c14c6703a 100755 --- a/blog/header.php +++ b/blog/header.php @@ -2,228 +2,112 @@ /// 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&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)?'':"&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&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&group=$filterselect", - 'type' => 'misc'); - $navlinks[] = array('name' => $blogstring, - 'link' => "index.php?filtertype=group&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&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&course=$course->id", - 'type' => 'misc'); - - if ($tagid || !empty($tag)) { - $navlinks[] = array('name' => $blogstring, - 'link' => "index.php?courseid=$course->id&filtertype=user&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&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&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'; -?> - - -
    +$user = $USER; +$userid = $USER->id; diff --git a/blog/index.php b/blog/index.php index ae0cf64ec6..dc3fcc3dc5 100755 --- a/blog/index.php +++ b/blog/index.php @@ -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.'&filterselect='.$filterselect.'&postid='.$postid.'&tagid='.$tagid.'&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.'&tagid='.@$tagid.'&tag='.$tag, 'view blog entry'); diff --git a/blog/lib.php b/blog/lib.php index f752590ffb..28eddc662a 100755 --- a/blog/lib.php +++ b/blog/lib.php @@ -1,33 +1,57 @@ -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 +. + + +/** + * 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 @@ -45,52 +69,73 @@ // $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 = '
      '; + 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 = ''; - 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. @@ -100,581 +145,579 @@ $pagingbar->pagevar = 'blogpage'; echo $OUTPUT->paging_bar($pagingbar); - if (!$count) { - print '
    '. get_string('noentriesyet', 'blog') .'

    '; + 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.'
    '."\n"; - return; - } - - $output = '
    '. get_string('noentriesyet', 'blog') .'

    '; - - 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'] = ''; - //enclose the title in nolink tags so that moodle formatting doesn't autolink the text - $template['title'] .= ''. format_string($blogEntry->subject) .''; - $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'].'&'). + (empty($filters['mod']) ? '' : 'modid='.$filters['mod'].'&'). + (empty($filters['group']) ? '' : 'groupid='.$filters['group'].'&'). + (empty($filters['user']) ? '' : 'userid='.$filters['user'].'&'). + (empty($filters['entry']) ? '' : 'entryid='.$filters['entry'].'&'). + (empty($filters['tag']) ? '' : 'tagid='.$filters['tag'].'&'). + (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 ''; + $url = array_map('trim', $url); - echo ''; + if (empty($url['port'])) { + $url['port'] = 80; + } else { + $url['port'] = (int)$url['port']; + } - echo ''; + $path = ''; + if (!empty($url['path'])) { + $path = $url['path']; + } - echo '
    '; - echo $OUTPUT->user_picture(moodle_user_picture::make($user, SITEID)); - echo '
    '.$template['title'].'
    '; - $fullname = fullname($user, has_capability('moodle/site:viewfullnames', get_context_instance(CONTEXT_COURSE, $COURSE->id))); - $by = new object(); - $by->name = ''.$fullname.''; - $by->date = $template['created']; - print_string('bynameondate', 'forum', $by); - echo '
    '; - /// Actual content + if ($path == '') { + $path = '/'; + } - echo ''."\n"; + if (!empty($url['query'])) { + $path .= "?{$url['query']}"; + } - if ($blogEntry->attachment) { - echo '
    '; - $attachedimages = blog_print_attachments($blogEntry); - echo '
    '; + 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 '
    '.$blogtype.'
    '; - - // 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 '
    '; - if ($blogtags) { - print(get_string('tags', 'tag') .': '. $blogtags); - } - echo '
    '; - } - - /// Commands - - echo '
    '; + if (!$fp) { + return false; + } - if (blog_user_can_edit_post($blogEntry)) { - echo ''.$stredit.''; - echo '| '.$strdelete.' | '; + fputs($fp, "HEAD $path HTTP/1.1\r\nHost: {$url['host']}\r\n\r\n"); + $headers = fread($fp, 128); + fclose($fp); } - echo ''.get_string('permalink', 'blog').''; - - echo '
    '; - - if( isset($template['lastmod']) ){ - echo '
    '; - echo ' [ '.get_string('modified').': '.$template['lastmod'].' ]'; - echo '
    '; + if (is_array($headers)) { + $headers = implode("\n", $headers); } - echo '
    '."\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'] = '
    '; + //enclose the title in nolink tags so that moodle formatting doesn't autolink the text + $template['title'] .= ''. format_string($blogEntry->subject) .''; + $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 ''; - $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 ''; - $image = "old_icon_url(file_mimetype_icon($type)) . "\" class=\"icon\" alt=\"\" />"; + echo ''; - if ($return == "html") { - $output .= "$image "; - $output .= "$filename
    "; + echo '
    '; + echo $OUTPUT->user_picture(moodle_user_picture::make($user, SITEID)); + echo '
    '.$template['title'].'
    '; + $fullname = fullname($user, has_capability('moodle/site:viewfullnames', get_context_instance(CONTEXT_COURSE, $COURSE->id))); + $by = new object(); + $by->name = ''.$fullname.''; + $by->date = $template['created']; + print_string('bynameondate', 'forum', $by); + echo '
    '; - } 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 .= "
    \"\""; - } else { - echo "$image "; - echo filter_text("$filename
    "); - } - } - } + echo '
    '."\n"; - if ($return) { - return $output; - } - - return $imagereturn; + if ($blogEntry->attachment) { + echo '
    '; + $attachedimages = blog_print_attachments($blogEntry); + echo '
    '; + } 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 '
    '.$blogtype.'
    '; - /** - * 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 '
    '; + if ($blogtags) { + print(get_string('tags', 'tag') .': '. $blogtags); + } + echo '
    '; } +/// 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 '
    '; - // 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 ''.$stredit.''; + echo '| '.$strdelete.' | '; + } - // coming for 1 post, make sure user is logged in, if not a public blog - if ($blogEntry && $blogEntry->publishstate != 'public' && !isloggedin()) { - return false; - } + echo ''.get_string('permalink', 'blog').''; - switch ($CFG->bloglevel) { - case BLOG_GLOBAL_LEVEL: - return true; - break; + echo '
    '; - case BLOG_SITE_LEVEL: - if (!empty($USER->id)) { // not logged in viewers forbidden - return true; - } - return false; - break; + if( isset($template['lastmod']) ){ + echo '
    '; + echo ' [ '.get_string('modified').': '.$template['lastmod'].' ]'; + echo '
    '; + } - 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 '
    '."\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 .= '&'.$var.'='.$val; - $hasparam = true; - } - } - } - if (isset($hasparam)) { - $querystring .= '&'; - } 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.'&filterselect='.$filterselect.'&'; + $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 index 0000000000..7551f3c188 --- /dev/null +++ b/blog/locallib.php @@ -0,0 +1,1139 @@ +. + + +/** + * 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'] = ''; + //enclose the title in nolink tags so that moodle formatting doesn't autolink the text + $template['title'] .= ''. format_string($this->subject) .''; + $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 .= '
    '; + $contentcell->text .= ' [ '.get_string('modified').': '.$template['lastmod'].' ]'; + $contentcell->text .= '
    '; + } + + $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 = "pixpath/f/$icon\" class=\"icon\" alt=\"\" />"; + + if ($return == "html") { + $output .= "
    $image "; + $output .= "$filename
    "; + + } 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 .= "
    \"\""; + } else { + $imagereturn .= "$image "; + $imagereturn .= filter_text("$filename
    "); + } + } + } + + 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 = '
      '; + + 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 = ''; + 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 '
    '. get_string('noentriesyet', 'blog') .'

    '; + } + + print $morelink.'
    '."\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 .= '&'.$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%')"); + } +} diff --git a/blog/preferences.php b/blog/preferences.php index ad798e584b..e5e9ed9f9b 100755 --- a/blog/preferences.php +++ b/blog/preferences.php @@ -1,57 +1,84 @@ -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 . - $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&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 index 0000000000..4d94ec91fc --- /dev/null +++ b/blog/preferences_form.php @@ -0,0 +1,42 @@ +. + + +/** + * 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(); + } +} diff --git a/blog/rsslib.php b/blog/rsslib.php index 0f73502fa8..b59250adb2 100755 --- a/blog/rsslib.php +++ b/blog/rsslib.php @@ -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; @@ -62,21 +62,21 @@ } } - /// 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')); @@ -114,10 +114,10 @@ $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(); @@ -142,7 +142,7 @@ 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 index 0000000000..36a9823e30 --- /dev/null +++ b/blog/simpletest/testbloglib.php @@ -0,0 +1,129 @@ +. + + +/** + * 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'], ''); + } +} diff --git a/blog/version.php b/blog/version.php index a90ced3976..a77d43a2f8 100644 --- a/blog/version.php +++ b/blog/version.php @@ -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) ?> diff --git a/course/lib.php b/course/lib.php index 1bc39ece56..29af1662b7 100644 --- a/course/lib.php +++ b/course/lib.php @@ -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) { diff --git a/grade/report/grader/preferences_form.php b/grade/report/grader/preferences_form.php index 2d90270939..f94d8194d4 100644 --- a/grade/report/grader/preferences_form.php +++ b/grade/report/grader/preferences_form.php @@ -15,6 +15,16 @@ // You should have received a copy of the GNU General Public License // along with Moodle. If not, see . + +/** + * 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'); /** diff --git a/lang/en_utf8/admin.php b/lang/en_utf8/admin.php index 33cc7bdf00..1e76b7db6d 100644 --- a/lang/en_utf8/admin.php +++ b/lang/en_utf8/admin.php @@ -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.'; ?> diff --git a/lang/en_utf8/assignment.php b/lang/en_utf8/assignment.php index 7834ed1426..8fb3f1d818 100644 --- a/lang/en_utf8/assignment.php +++ b/lang/en_utf8/assignment.php @@ -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!'; ?> diff --git a/lang/en_utf8/blog.php b/lang/en_utf8/blog.php index 2dcec8721b..a5596e3e09 100755 --- a/lang/en_utf8/blog.php +++ b/lang/en_utf8/blog.php @@ -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
    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 index 0000000000..bf79096bb2 --- /dev/null +++ b/lang/en_utf8/help/blog/description.html @@ -0,0 +1,4 @@ +

    Description

    + +

    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).

    diff --git a/lang/en_utf8/help/blog/name.html b/lang/en_utf8/help/blog/name.html new file mode 100644 index 0000000000..67bd2b2335 --- /dev/null +++ b/lang/en_utf8/help/blog/name.html @@ -0,0 +1,3 @@ +

    Name

    + +

    A descriptive name for your external blog. If empty, will default to the title of your external blog.

    diff --git a/lang/en_utf8/help/blog/tags.html b/lang/en_utf8/help/blog/tags.html new file mode 100644 index 0000000000..3fd3deb91a --- /dev/null +++ b/lang/en_utf8/help/blog/tags.html @@ -0,0 +1,5 @@ +

    Tags

    + +

    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.

    diff --git a/lang/en_utf8/help/blog/url.html b/lang/en_utf8/help/blog/url.html new file mode 100644 index 0000000000..e28e16724a --- /dev/null +++ b/lang/en_utf8/help/blog/url.html @@ -0,0 +1,5 @@ +

    URL

    + +

    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.

    diff --git a/lib/accesslib.php b/lib/accesslib.php index 88bf5690e1..76c650a42c 100755 --- a/lib/accesslib.php +++ b/lib/accesslib.php @@ -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) { diff --git a/lib/adminlib.php b/lib/adminlib.php index 79b8f3555f..d9f45f275d 100644 --- a/lib/adminlib.php +++ b/lib/adminlib.php @@ -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', diff --git a/lib/db/access.php b/lib/db/access.php index 8ff7b5c3c5..9f389fd24b 100644 --- a/lib/db/access.php +++ b/lib/db/access.php @@ -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 diff --git a/lib/db/install.xml b/lib/db/install.xml index 6ba9fbbe78..1686ffc106 100644 --- a/lib/db/install.xml +++ b/lib/db/install.xml @@ -824,8 +824,9 @@ - - + + + @@ -2197,7 +2198,7 @@
    - +
    @@ -2217,7 +2218,38 @@
    - +
    + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + +
    + diff --git a/lib/db/upgrade.php b/lib/db/upgrade.php index be20f161e1..3ffd1e153c 100644 --- a/lib/db/upgrade.php +++ b/lib/db/upgrade.php @@ -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) { diff --git a/lib/form/format.php b/lib/form/format.php index c2b3e0e8da..ce08b6b5ef 100644 --- a/lib/form/format.php +++ b/lib/form/format.php @@ -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 +?> diff --git a/lib/form/select.php b/lib/form/select.php index 92a69cba19..bdb81c3573 100644 --- a/lib/form/select.php +++ b/lib/form/select.php @@ -129,4 +129,4 @@ class MoodleQuickForm_select extends HTML_QuickForm_select{ } } } -?> \ No newline at end of file +?> diff --git a/lib/outputcomponents.php b/lib/outputcomponents.php index 027447f1b3..bc1618d2d5 100644 --- a/lib/outputcomponents.php +++ b/lib/outputcomponents.php @@ -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 index 0000000000..4a79003ecf --- /dev/null +++ b/mod/assignment/type/blog/assignment.class.php @@ -0,0 +1,326 @@ +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 = ''.$post->subject.':
    '.shorten_text(format_text($post->summary)); + $ret .= 'Full Entry
    '; + + 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 '
    '.get_string('noblogs', 'assignment').'
    '; + echo '
    '.get_string('addnewentry', 'blog') .""; + } + } 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 '
    '. get_string('guestnosubmit', 'assignment').'
    '; + } else if ($this->isopen()) { //fix for #4206 + echo '
    '.get_string('emptysubmission', 'assignment').'
    '; + } + } + print_simple_box_end(); + if (!$editmode && $editable) { + echo "
    "; + print_single_button('view.php', array('id'=>$this->cm->id,'edit'=>'1'), + get_string('editmysubmission', 'assignment')); + echo "
    "; + } + + } + + $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); + } +} + +?> diff --git a/mod/assignment/version.php b/mod/assignment/version.php index b00df242e4..6ea4d55d97 100644 --- a/mod/assignment/version.php +++ b/mod/assignment/version.php @@ -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; diff --git a/tag/index.php b/tag/index.php index 9ff6e0c546..395a31d598 100644 --- a/tag/index.php +++ b/tag/index.php @@ -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 ''; - echo '

    '.get_string('seeallblogs', 'tag', $tagname).'

    '; + echo '

    '.get_string('seeallblogs', 'tag', $tagname).'

    '; echo $OUTPUT->box_end(); } diff --git a/theme/standard/styles_color.css b/theme/standard/styles_color.css index bd7eec9c05..e396b1a304 100644 --- a/theme/standard/styles_color.css +++ b/theme/standard/styles_color.css @@ -511,7 +511,7 @@ table.flexible .r1 { *** Blogs ***/ -.blogpost.blogdraft .content { +.blog_entry.blogdraft .content { background-color:#EEEEEE; } diff --git a/theme/standard/styles_fonts.css b/theme/standard/styles_fonts.css index 3dcda73c19..6675f06076 100644 --- a/theme/standard/styles_fonts.css +++ b/theme/standard/styles_fonts.css @@ -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; } diff --git a/theme/standard/styles_layout.css b/theme/standard/styles_layout.css index 4ea1795873..39114f0ff8 100644 --- a/theme/standard/styles_layout.css +++ b/theme/standard/styles_layout.css @@ -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 ***/ diff --git a/user/tabs.php b/user/tabs.php index a2238b2af7..181351721c 100644 --- a/user/tabs.php +++ b/user/tabs.php @@ -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&', + $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&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&filterselect='.$filterselect, get_string('blogs','blog')); + $toprow[] = new tabobject('blogs', blog_get_blogs_url(array('group'=>$filterselect)), get_string('blogs','blog')); } /************************************** @@ -138,7 +139,7 @@ ) // able to read blogs in site or course context ) { //end if - $toprow[] = new tabobject('blogs', $CFG->wwwroot.'/blog/index.php?userid='.$user->id.'&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))) {