From 38fb8190286e32cabd4be75e783d10dcfcd94dde Mon Sep 17 00:00:00 2001 From: scyrma Date: Mon, 30 Jun 2008 09:04:07 +0000 Subject: [PATCH] MDL-11992: adding course tagging patch, by John Beedell. This feature is not active by default at this time. Related help files are not included in this commit, as they are being revised (see issue 15385) and will be sent in soon. --- blocks/tags/block_tags.php | 273 +++++++++++++- blocks/tags/coursetags.js | 62 ++++ blocks/tags/settings.php | 6 + blocks/tags/styles.php | 116 ++++++ course/lib.php | 3 + lang/en_utf8/block_tags.php | 66 ++++ lang/en_utf8/tag.php | 12 +- lib/db/install.xml | 7 +- lib/db/upgrade.php | 22 ++ lib/moodlelib.php | 10 +- tag/coursetags_add.php | 34 ++ tag/coursetags_edit.php | 177 +++++++++ tag/coursetags_more.php | 187 ++++++++++ tag/coursetagslib.php | 698 ++++++++++++++++++++++++++++++++++++ tag/edit.php | 2 +- tag/index.php | 104 +++--- tag/lib.php | 29 +- version.php | 2 +- 18 files changed, 1740 insertions(+), 70 deletions(-) create mode 100644 blocks/tags/coursetags.js create mode 100644 blocks/tags/settings.php create mode 100644 blocks/tags/styles.php create mode 100644 lang/en_utf8/block_tags.php create mode 100644 tag/coursetags_add.php create mode 100644 tag/coursetags_edit.php create mode 100644 tag/coursetags_more.php create mode 100644 tag/coursetagslib.php diff --git a/blocks/tags/block_tags.php b/blocks/tags/block_tags.php index 0b21493b171..4aff6fc9fea 100644 --- a/blocks/tags/block_tags.php +++ b/blocks/tags/block_tags.php @@ -2,8 +2,12 @@ class block_tags extends block_base { function init() { - $this->version = 2007101509; + $this->version = 2008063001; $this->title = get_string('blocktagstitle', 'tag'); + // the cron function goes through all users, so only do daily + // (this creates rss feeds for personal course tags) + // removed until rsslib supports dc/cc + // $this->cron = 60*60*24; } function instance_allow_multiple() { @@ -11,7 +15,7 @@ class block_tags extends block_base { } function has_config() { - return false; + return true; } function applicable_formats() { @@ -61,7 +65,253 @@ class block_tags extends block_base { require_once($CFG->dirroot.'/tag/lib.php'); - $this->content->text = tag_print_cloud($this->config->numberoftags, true); + if (empty($CFG->block_tags_showcoursetags) or !$CFG->block_tags_showcoursetags) { + + $this->content->text = tag_print_cloud($this->config->numberoftags, true); + + // start of show course tags section + } else { + + require_once($CFG->dirroot.'/tag/coursetagslib.php'); + + // Permissions and page awareness + $sitecontext = get_context_instance(CONTEXT_SYSTEM, SITEID); + $isguest = has_capability('moodle/legacy:guest', $sitecontext, $USER->id, false); + $loggedin = isloggedin() && !$isguest; + $coursepage = $canedit = false; + $coursepage = (isset($COURSE->id) && $COURSE->id != SITEID); + $mymoodlepage = strpos($_SERVER['PHP_SELF'], 'my') > 0 ? true : false; + $sitepage = (isset($COURSE->id) && $COURSE->id == SITEID && !$mymoodlepage); + $coursecontext = get_context_instance(CONTEXT_COURSE, $COURSE->id); + if ($coursepage) { + $canedit = has_capability('moodle/tag:create', $sitecontext); + } + + // Check rss feed - temporarily removed until Dublin Core tags added + // provides a feed of users course tags for each unit they have tagged + //$rssfeed = ''; + //if (file_exists($CFG->dataroot.'/'.SITEID.'/usertagsrss/'.$USER->id.'/user_unit_tags_rss.xml')) { + // $rssfeed = '/file.php/'.SITEID.'/usertagsrss/'.$USER->id.'/user_unit_tags_rss.xml'; + //} + + // Language strings + $tagslang = 'block_tags'; + + // DB hits to get groups of marked up tags (if available) + //TODO check whether time limited personal tags are required + $numoftags = $this->config->numberoftags; + $sort = 'name'; + $alltags = $officialtags = $coursetags = $commtags = $mytags = $coursetagdivs = $courseflag = ''; + if ($sitepage or $coursepage) { + $alltags = coursetag_print_cloud(coursetag_get_all_tags($sort, $this->config->numberoftags), true); + $officialtags = coursetag_print_cloud(coursetag_get_tags(0, 0, 'official', $numoftags, $sort), true); + $commtags = coursetag_print_cloud(coursetag_get_tags(0, 0, 'default', $numoftags, $sort), true); + if ($loggedin) { + $mytags = coursetag_print_cloud(coursetag_get_tags(0, $USER->id, 'default', $numoftags, $sort), true); + } + } + if ($coursepage) { + $coursetags = coursetag_print_cloud(coursetag_get_tags($COURSE->id, 0, '', $numoftags, $sort), true); + if (!$coursetags) $coursetags = get_string('notagsyet', $tagslang); + $courseflag = '&courseid='.$COURSE->id; + } + if ($mymoodlepage) { + $mytags = coursetag_print_cloud(coursetag_get_tags(0, $USER->id, 'default', $numoftags, $sort), true); + $officialtags = coursetag_print_cloud(coursetag_get_tags(0, 0, 'official', $numoftags, $sort), true); + $commtags = coursetag_print_cloud(coursetag_get_tags(0, 0, 'default', $numoftags, $sort), true); + } + + // Prepare the divs and javascript that displays the groups of tags (and which is displayed first) + $moretags = $CFG->wwwroot.'/tag/coursetags_more.php'; + $moretagstitle = get_string('moretags', $tagslang); + $moretagsstring = get_string('more', $tagslang); + $displayblock = 'style="display:block"'; + $displaynone = 'style="display:none"'; //only one div created below will be displayed at a time + if ($alltags) { + if ($sitepage) { + $display = $displayblock; + } else { + $display = $displaynone; + } + $alltagscontent = ' +
'. + get_string("alltags", $tagslang). + '
'.$alltags.'
+ +
'; + $coursetagdivs .= '"f_alltags", '; + } + if ($mytags) { + if ($mymoodlepage) { + $display = $displayblock; + } else { + $display = $displaynone; + } + $mytagscontent = ' +
'; + /*if ($rssfeed) { // - temporarily removed + $mytagscontent .= link_to_popup_window( + $rssfeed, $name='popup', + 'User Unit Tags RSS My Unit Tags RSS', + $height=600, $width=800, + $title='My Unit Tags RSS', $options='menubar=1,scrollbars,resizable', $return=true).'
'; + }*/ + $mytagscontent .= + get_string('mytags', $tagslang). + '
'.$mytags.'
+ +
'; + $coursetagdivs .= '"f_mytags", '; + } + if ($officialtags) { + if ($mytags or $alltags) { + $display = $displaynone; + } else { + $display = $displayblock; + } + $officialtagscontent = ' +
'. + get_string('officialtags', $tagslang). + '
'.$officialtags.'
+ +
'; + $coursetagdivs .= '"f_officialtags", '; + } + if ($coursetags) { + if ($coursepage) { + $display = $displayblock; + } else { + $display = $displaynone; + } + $coursetagscontent = ' +
'. + get_string('coursetags', $tagslang). + '
'.$coursetags.'
+ +
'; + $coursetagdivs .= '"f_coursetags", '; + } + if ($commtags) { + $commtagscontent = ' +
'. + get_string('communitytags', $tagslang). + '
'.$commtags.'
+ +
'; + $coursetagdivs .= '"f_commtags", '; + } + // Tidy up the end of a javascript array and add javascript + $coursetagdivs = rtrim($coursetagdivs, ', '); + $this->content->text .= coursetag_get_jscript($coursetagdivs); + + // Add the divs (containing the tags) to the block's content + if ($alltags) { $this->content->text .= $alltagscontent; } + if ($mytags) { $this->content->text .= $mytagscontent; } + if ($officialtags) { $this->content->text .= $officialtagscontent; } + if ($coursetags) { $this->content->text .= $coursetagscontent; } + if ($commtags) { $this->content->text .= $commtagscontent; } + + // add the input form section (allowing a user to tag the current course) and navigation, or loggin message + if ($loggedin) { + // only show the input form on course pages for those allowed (or not barred) + if ($coursepage && $canedit) { + //$this->content->footer .= coursetag_get_jscript(); + $tagthisunit = get_string('tagthisunit', $tagslang); + $buttonadd = get_string('add', $tagslang); + $arrowtitle = get_string('arrowtitle', $tagslang); + $coursetaghelpbutton = helpbutton('addtags', 'adding tags', $tagslang, TRUE, FALSE, '', TRUE); + $this->content->footer .= << +
+
+ + +
+
+
+
+
+ +
+
+ +
+
+ + enter + +
+
+
+ + $coursetaghelpbutton +
+
+
+EOT; + // add the edit link + $this->content->footer .= ' +
+ '.get_string('edittags', $tagslang).' +
'; + } + + // Navigation elements at the bottom of the block + // show the alternative displays options if available + if ($mytags or $officialtags or $commtags or $coursetags) { + $this->content->footer .= ''; + } + // This section sets the order of the links + $coursetagslinks = array(); + if ($mytags) { + $coursetagslinks['my'] = array('title'=>get_string('mytags2', $tagslang), + 'onclick'=>'f_mytags', + 'text'=>get_string('mytags1', $tagslang)); + } + // because alltags is always present, only show link if there is something else as well + if ($alltags and ($mytags or $officialtags or $commtags or $coursetags)) { + $coursetagslinks['all'] = array('title'=>get_string('alltags2', $tagslang), + 'onclick'=>'f_alltags', + 'text'=>get_string('alltags1', $tagslang)); + } + if ($officialtags) { + $coursetagslinks['off'] = array('title'=>get_string('officialtags2', $tagslang), + 'onclick'=>'f_officialtags', + 'text'=>get_string('officialtags1', $tagslang)); + } + //if ($commtags) { + // $coursetagslinks['com'] = array('title'=>get_string('communitytags2', $tagslang), + // 'onclick'=>'f_commtags', + // 'text'=>get_string('communitytags1', $tagslang)); + //} + if ($coursetags) { + $coursetagslinks['crs'] = array('title'=>get_string('coursetags2', $tagslang), + 'onclick'=>'f_coursetags', + 'text'=>get_string('coursetags1', $tagslang)); + } + $this->content->footer .= coursetag_get_jscript_links($coursetagslinks); + + } else { + //if not logged in + $this->content->footer = '
'.get_string('please', $tagslang).' + '.get_string('login', $tagslang).' + '.get_string('tagunits', $tagslang); + } + } + // end of show course tags section return $this->content; } @@ -81,6 +331,21 @@ class block_tags extends block_base { notice(get_string('blockconfigbad'), str_replace('blockaction=', 'dummy=', qualified_me())); } } -} + /* + * function removed until rsslib supports dc/cc + */ + /* + function cron() { + if (SHOWCOURSETAGS) { + global $CFG; + require_once($CFG->dirroot.'/tag/coursetagslib.php'); + return coursetag_rss_feeds(); + } else { + return TRUE; +} + } + */ + +} ?> diff --git a/blocks/tags/coursetags.js b/blocks/tags/coursetags.js new file mode 100644 index 00000000000..de4f1780c21 --- /dev/null +++ b/blocks/tags/coursetags.js @@ -0,0 +1,62 @@ +/** + * coursetags.js + * @author j.beedell@open.ac.uk July07 + * + * getKeywords modified from an original script (Auto Complete Textfield) + * from The JavaScript Source http://javascript.internet.com + * originally created by: Timothy Groves http://www.brandspankingnew.net/ + */ + + +function ctags_show_div(mydiv) { + for(x in coursetagdivs) { + if(mydiv == coursetagdivs[x]) { + document.getElementById(coursetagdivs[x]).style.display="block"; + } else { + document.getElementById(coursetagdivs[x]).style.display="none"; + } + } + return false; +} + +var sug = ""; +var sug_disp = ""; + +function ctags_getKeywords() { + /* + // This 'workaround' removing the xhtml strict form autocomplete="off" needs to + // be added to the body onload() script to work - but decided not to include + // (having the browser list might help with screen readers more than this script) + // document.forms['coursetag'].setAttribute("autocomplete", "off"); + */ + var input = document.forms['coursetag'].coursetag_new_tag.value; + var len = input.length; + sug_disp = ""; sug = ""; + + if (input.length) { + for (ele in coursetag_tags) + { + if (coursetag_tags[ele].substr(0,len).toLowerCase() == input.toLowerCase()) + { + sug_disp = input + coursetag_tags[ele].substr(len); + sug = coursetag_tags[ele]; + break; + } + } + } + document.forms['coursetag'].coursetag_sug_keyword.value = sug_disp; + if (!sug.length || input == sug_disp) + document.getElementById('coursetag_sug_btn').style.display = "none"; + else + document.getElementById('coursetag_sug_btn').style.display = "block"; +} + +function ctags_setKeywords() { + document.forms['coursetag'].coursetag_new_tag.value = sug; + ctags_hideSug(); +} + +function ctags_hideSug() { + document.forms['coursetag'].coursetag_sug_keyword.value = ""; + document.getElementById('coursetag_sug_btn').style.display = "none"; +} diff --git a/blocks/tags/settings.php b/blocks/tags/settings.php new file mode 100644 index 00000000000..3e5bdea81bb --- /dev/null +++ b/blocks/tags/settings.php @@ -0,0 +1,6 @@ +add(new admin_setting_configcheckbox('block_tags_showcoursetags', get_string('showcoursetags', 'block_tags'), + get_string('showcoursetagsdef', 'block_tags'), 0)); + +?> diff --git a/blocks/tags/styles.php b/blocks/tags/styles.php new file mode 100644 index 00000000000..ef743369225 --- /dev/null +++ b/blocks/tags/styles.php @@ -0,0 +1,116 @@ +/* + * CSS for course tags + * @author j.beedell@open.ac.uk July07 + * + * Styles for block_tags.php + */ + +.coursetag_form_wrapper { + margin: auto; + width: 13em; +} + +.coursetag_form_positioner { + position: relative; + margin: 5px 0 0 0; + height: 25px; +} + +.coursetag_form_input1 { + position: absolute; + top: 0; + left: 0; + z-index: 1; +} + +.coursetag_form_input2 { + position: absolute; + top: 0; + left: 0; + z-index: 2; +} + +.coursetag_form_input3 { + position: absolute; + top: 3px; + left: 12.8em; + display: none; +} + +.coursetag_form_input1a { + background-color: white; + border: 1px solid #999; + width: 12em; + padding: 2px; +} + +.coursetag_form_input2a { + background: transparent; + color: #669954; + border: 1px solid #999; + width: 12em; + padding: 2px; +} + +.coursetag_morelink { + float: right; + font-size: 0.8em; + margin: -5px 5px 5px 0; +} + +.coursetag_list { + padding-top: 4px; +} + +/* Styles for edit_tags.php */ + +.coursetag_edit_centered { + position: relative; + width: 600px; + margin: 20px auto; +} + +.coursetag_edit_row { + margin: 5px 0 5px 0; + height: 30px; +} + +.coursetag_edit_left { + position: relative; + float: left; + padding: 3px 5px; +} + +.coursetag_edit_right { + position: relative; + float: left; + padding: 3px 0px; +} + +.coursetag_edit_input3 { + position: relative; + left: 10.5em; + display: none; +} + +/* Styles for more_tags.php */ + +.coursetag_more_title { + margin: 30px 30px -25px 30px; +} + +.coursetag_more_tags { + margin: 30px; +} + +.coursetag_more_large { + font-size: 120% +} + +.coursetag_more_small { + font-size: 80% +} + +.coursetag_more_link { + font-size: 80%; +} diff --git a/course/lib.php b/course/lib.php index 562f9863dc3..a6cb74bab79 100644 --- a/course/lib.php +++ b/course/lib.php @@ -40,6 +40,9 @@ function make_log_url($module, $url) { case 'upload': return $url; break; + case 'coursetags': + return '/'.$url; + break; case 'library': case '': return '/'; diff --git a/lang/en_utf8/block_tags.php b/lang/en_utf8/block_tags.php new file mode 100644 index 00000000000..559fdf1cd5a --- /dev/null +++ b/lang/en_utf8/block_tags.php @@ -0,0 +1,66 @@ + diff --git a/lang/en_utf8/tag.php b/lang/en_utf8/tag.php index a9976fb937e..256291ebcb4 100644 --- a/lang/en_utf8/tag.php +++ b/lang/en_utf8/tag.php @@ -10,12 +10,16 @@ $string['changetype'] = 'Change tag type'; $string['description'] = 'Description'; $string['delete'] = 'Delete'; $string['deleted'] = 'Deleted'; +$string['deletedcoursetags'] = 'Deleted - course tags'; $string['edittag'] = 'Edit this tag'; +$string['errordeleting'] = 'Error deleting tag with id $a, please report to your system administrator.'; +$string['errortagfrontpage'] = 'Tagging the site main page is not allowed'; +$string['errorupdatingrecord'] = 'Error updating tag record'; $string['flag'] = 'Flag'; $string['flagasinappropriate'] = 'Flag as inappropriate'; $string['helprelatedtags'] = 'Comma separated related tags'; $string['id'] = 'id'; -$string['relatedblogs'] = 'Recent blog entries with this tag'; +$string['relatedblogs'] = 'Most recent blog entries tagged with \"$a\"'; $string['managetags'] = 'Manage tags'; $string['name'] = 'Tag name'; $string['namesalreadybeeingused'] = 'Tag names already being used'; @@ -30,8 +34,10 @@ $string['removetagfrommyinterests'] = 'Remove \"$a\" from my interests'; $string['responsiblewillbenotified'] = 'The person responsible will be notified'; $string['resetflag'] = 'Reset flag'; $string['reset'] = 'Reset'; +$string['rsstitle'] = 'Course Tags RSS Feed for user: $a'; +$string['rssdesc'] = 'This RSS feed was automatically generated by Moodle and contains user generated tags for courses.'; $string['search'] = 'Search'; -$string['seeallblogs'] = 'See all blogs with this tag'; +$string['seeallblogs'] = 'See all blog entries tagged with \"$a\"...'; $string['searchresultsfor'] = 'Search results for \"$a\"'; $string['searchtags'] = 'Search tags'; $string['select'] = 'Select'; @@ -40,9 +46,9 @@ $string['tag'] = 'Tag'; $string['tagtype'] = 'Tag type'; $string['tagtype_official'] = 'Official'; $string['tagtype_default'] = 'Default'; +$string['tagindex_coursetitle'] = 'Courses tagged with \"$a\"'; $string['tags'] = 'Tags'; $string['tagsaredisabled'] = 'Tags are disabled'; -$string['thingstaggedwith'] = '$a->count things tagged with \"$a->name\"'; $string['thistaghasnodesc'] = 'This tag currently has no description.'; $string['timemodified'] = 'Modified'; $string['typechanged'] = 'Tag type changed'; diff --git a/lib/db/install.xml b/lib/db/install.xml index d0d1168a97d..3668dd7229d 100644 --- a/lib/db/install.xml +++ b/lib/db/install.xml @@ -1503,8 +1503,9 @@ - - + + + @@ -1512,7 +1513,7 @@ - + diff --git a/lib/db/upgrade.php b/lib/db/upgrade.php index b7255b4b5dc..4c20ff283b6 100644 --- a/lib/db/upgrade.php +++ b/lib/db/upgrade.php @@ -134,6 +134,28 @@ function xmldb_main_upgrade($oldversion=0) { upgrade_main_savepoint($result, 2008051203); } + if ($result && $oldversion < 2008063001) { + // table to be modified + $table = new xmldb_table('tag_instance'); + // add field + $field = new xmldb_field('tiuserid'); + if (!$dbman->field_exists($table, $field)) { + $field->set_attributes(XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, 0, 'itemid'); + $dbman->add_field($table, $field); + } + // modify index + $index = new xmldb_index('itemtype-itemid-tagid'); + $index->set_attributes(XMLDB_INDEX_UNIQUE, array('itemtype', 'itemid', 'tagid')); + $dbman->drop_index($table, $index); + $index = new xmldb_index('itemtype-itemid-tagid-tiuserid'); + $index->set_attributes(XMLDB_INDEX_UNIQUE, array('itemtype', 'itemid', 'tagid', 'tiuserid')); + $dbman->add_index($table, $index); + + /// Main savepoint reached + upgrade_main_savepoint($result, 2008063001); + } + + /* * TODO: * drop adodb_logsql table and create a new general sql log table diff --git a/lib/moodlelib.php b/lib/moodlelib.php index 8acd3d621f5..62d065216b5 100644 --- a/lib/moodlelib.php +++ b/lib/moodlelib.php @@ -154,8 +154,8 @@ define('PARAM_FILE', 0x0010); define('PARAM_TAG', 0x0011); /** - * PARAM_TAGLIST - list of tags separated by commas (interests, blogs, etc.) - */ + * PARAM_TAGLIST - list of tags separated by commas (interests, blogs, etc.) + */ define('PARAM_TAGLIST', 0x0012); /** @@ -2817,7 +2817,7 @@ function update_user_record($username, $authplugin) { } /** - * will truncate userinfo as it comes from auth_get_userinfo (from external auth) + * will truncate userinfo as it comes from auth_get_userinfo (from external auth) * which may have large fields */ function truncate_userinfo($info) { @@ -3543,6 +3543,10 @@ function remove_course_contents($courseid, $showfeedback=true) { remove_course_grades($courseid, $showfeedback); remove_grade_letters($context, $showfeedback); +/// Delete course tags + require_once($CFG->dirroot.'/tag/coursetagslib.php'); + coursetag_delete_course_tags($course->id, $showfeedback); + return $result; } diff --git a/tag/coursetags_add.php b/tag/coursetags_add.php new file mode 100644 index 00000000000..6154c9a21cd --- /dev/null +++ b/tag/coursetags_add.php @@ -0,0 +1,34 @@ +dirroot.'/tag/coursetagslib.php'); + + if ($courseid > 0 and $userid > 0) { + $myurl = 'tag/search.php'; + $keywords = explode(',', $keyword); + coursetag_store_keywords($keywords, $courseid, $userid, 'default', $myurl); + } +} + +// send back to originating page, where the new tag will be visible in the block +if ($courseid > 0) { + $myurl = $CFG->wwwroot.'/course/view.php?id='.$courseid; +} else { + $myurl = $CFG->wwwroot.'/'; +} + +redirect($myurl); + +?> diff --git a/tag/coursetags_edit.php b/tag/coursetags_edit.php new file mode 100644 index 00000000000..68375cbeb86 --- /dev/null +++ b/tag/coursetags_edit.php @@ -0,0 +1,177 @@ +dirroot.'/tag/coursetagslib.php'); +require_once($CFG->dirroot.'/tag/lib.php'); + +$courseid = optional_param('courseid', 0, PARAM_INT); +$keyword = optional_param('coursetag_new_tag', '', PARAM_TEXT); +$deltag = optional_param('del_tag', 0, PARAM_INT); + +if ($courseid != SITEID) { + if (! ($course = $DB->get_record('course', array('id' => $courseid), '*')) ) { + print_error('invalidcourse'); + } +} else { + print_error('errortagfrontpage', 'tag'); +} + +// Permissions +$sitecontext = get_context_instance(CONTEXT_SYSTEM, SITEID); +require_login($course->id); +$canedit = has_capability('moodle/tag:create', $sitecontext); + +// Language strings +$tagslang = 'block_tags'; + +// Store data +if ($data = data_submitted()) { + if (confirm_sesskey() and $courseid > 0 and $USER->id > 0 and $canedit) { + // store personal tag + if (trim(strip_tags($keyword))) { + $myurl = 'tag/search.php'; + $keywords = explode(',', $keyword); + try { + coursetag_store_keywords($keywords, $courseid, $USER->id, 'default', $myurl); + } + catch (Exception $e) { + notice($e->getmessage()); + } + } + // delete personal tag + if ($deltag > 0) { + coursetag_delete_keyword($deltag, $USER->id, $courseid); + } + } +} + +// The title and breadcrumb +$title = get_string('edittitle', $tagslang); +$coursefullname = format_string($course->fullname); +$courseshortname = format_string($course->shortname); +//$navigation[] = array('name' => $coursefullname, 'link' => $CFG->wwwroot.'/course/view.php?id='.$courseid, 'type' => 'misc'); +$navigation[] = array('name' => $title, 'link' => null, 'type' => 'misc'); +$nav = build_navigation($navigation); +print_header_simple($title, '', $nav, '', '', false); + + // Print personal tags for all courses + $title = get_string('edittitle', $tagslang); + print_heading($title, 'center'); + + $mytags = coursetag_print_cloud(coursetag_get_tags(0, $USER->id, 'default'), true); + $outstr = ' +
+
+ '.get_string('editmytags', $tagslang).' +
+
'; + + if ($mytags) { + $outstr .= $mytags; + } else { + $outstr .= get_string('editnopersonaltags', $tagslang); + } + + $outstr .= ' +
+
'; + echo $outstr; + + // Personal tag editing + if ($canedit) { + $title = get_string('editmytagsfor', $tagslang, '"'.$coursefullname.' ('.$courseshortname.')"'); + print_heading($title); + + // Deletion here is open to the users own tags for this course only + $selectoptions = ''; + $coursetabs = ''; + if ($options = coursetag_get_records($courseid, $USER->id)) { + $coursetabs = '"'; + foreach ($options as $option) { + $selectoptions .= ''; + $coursetabs .= $option->rawname . ', '; + } + $coursetabs = rtrim($coursetabs, ', '); + $coursetabs .= '"'; + } + if ($coursetabs) { + $outstr = ' +
+ '.get_string('editthiscoursetags', $tagslang, $coursetabs).' +
'; + } else { + $outstr = ' +
+ '.get_string('editnopersonaltags', $tagslang).' +
'; + } + + // Print the add and delete form + $script = coursetag_get_jscript(); + $addtagshelp = helpbutton('addtags', 'adding tags', $tagslang, TRUE, FALSE, '', TRUE); + $edittagthisunit = get_string('edittagthisunit', $tagslang); + $arrowtitle = get_string('arrowtitle', $tagslang); + $outstr .= << +
+ + +
+
+
+
+ $addtagshelp$edittagthisunit +
+
+
+ +
+
+ +
+
+ + enter + +
+
+
+EOT; + if ($coursetabs) { + $deletetagshelp = helpbutton('deletetags', 'deleting tags', $tagslang, TRUE, FALSE, '', TRUE); + $editdeletemytag = get_string('editdeletemytag', $tagslang); + $outstr .= << +
+ $deletetagshelp$editdeletemytag +
+
+ +
+
+EOT1; + } + $submitstr = get_string('submit'); + $outstr .= << +
+ +
+ + +EOT2; + echo $outstr; + } + +print_footer(); +?> diff --git a/tag/coursetags_more.php b/tag/coursetags_more.php new file mode 100644 index 00000000000..22cab395eab --- /dev/null +++ b/tag/coursetags_more.php @@ -0,0 +1,187 @@ +dirroot.'/tag/coursetagslib.php'); +require_once($CFG->dirroot.'/tag/lib.php'); + +$sort = optional_param('sort', 'alpha', PARAM_TEXT); //alpha, date or popularity +$show = optional_param('show', 'all', PARAM_TEXT); //all, my, official, community or course +$courseid = optional_param('courseid', 0, PARAM_INT); + +// Some things require logging in +if ($CFG->forcelogin or $show == 'my') { + require_login(); +} + +// Permissions +$sitecontext = get_context_instance(CONTEXT_SYSTEM, SITEID); +$isguest = has_capability('moodle/legacy:guest', $sitecontext, $USER->id, false); +$loggedin = isloggedin() && !$isguest; + +// Course check +if ($courseid) { + if (!($course = $DB->get_record('course', array('id'=>$courseid)))) { + $courseid = 0; + } + if ($courseid == SITEID) $courseid = 0; +} + +// Language strings +$tagslang = 'block_tags'; +$title = get_string('moretitle', $tagslang); +$link1 = get_string('moreshow', $tagslang); +$link2 = get_string('moreorder', $tagslang); +$showalltags = get_string('moreshowalltags', $tagslang); +$showofficialtags = get_string('moreshowofficialtags', $tagslang); +$showmytags = get_string('moreshowmytags', $tagslang); +$showcommtags = get_string('moreshowcommtags', $tagslang); +$orderalpha = get_string('moreorderalpha', $tagslang); +$orderdate = get_string('moreorderdate', $tagslang); +$orderpop = get_string('moreorderpop', $tagslang); +$welcome = get_string('morewelcome', $tagslang); + +// The title and breadcrumb +if ($courseid) { + $navigation[] = array('name' => format_string($course->shortname), 'link' => $CFG->wwwroot.'/course/view.php?id='.$courseid, 'type' => 'misc'); + $navigation[] = array('name' => $title, 'link' => null, 'type' => 'misc'); +} else { + $navigation[] = array('name' => $title, 'link' => null, 'type' => 'misc'); +} +$nav = build_navigation($navigation); +print_header_simple($title, '', $nav, '', '', false); +print_heading($title, 'centre'); + +// Prepare data for tags +$courselink = ''; +if ($courseid) { $courselink = '&courseid='.$courseid; } +$myurl = $CFG->wwwroot.'/tag/coursetags_more.php'; +$myurl2 = $CFG->wwwroot.'/tag/coursetags_more.php?show='.$show; + +// Course tags +if ($show == 'course' and $courseid) { + + if ($sort == 'popularity') { + $tags = coursetag_print_cloud(coursetag_get_tags($courseid, 0, '', 0, 'popularity'), true, 200, 90); + } else if ($sort == 'date') { + $tags = coursetag_print_cloud(coursetag_get_tags($courseid, 0, '', 0, 'timemodified'), true, 200, 90); + } else { + $tags = coursetag_print_cloud(coursetag_get_tags($courseid, 0, '', 0, 'name'), true, 200, 90); + } + +// My tags +} else if ($show == 'my' and $loggedin) { + + if ($sort == 'popularity') { + $tags = coursetag_print_cloud(coursetag_get_tags(0, $USER->id, 'default', 0, 'popularity'), true, 200, 90); + } else if ($sort == 'date') { + $tags = coursetag_print_cloud(coursetag_get_tags(0, $USER->id, 'default', 0, 'timemodified'), true, 200, 90); + } else { + $tags = coursetag_print_cloud(coursetag_get_tags(0, $USER->id, 'default', 0, 'name'), true, 200, 90); + } + +// Official course tags +} else if ($show == 'official') { + + if ($sort == 'popularity') { + $tags = coursetag_print_cloud(coursetag_get_tags(0, 0, 'official', 0, 'popularity'), true, 200, 90); + } else if ($sort == 'date') { + $tags = coursetag_print_cloud(coursetag_get_tags(0, 0, 'official', 0, 'timemodified'), true, 200, 90); + } else { + $tags = coursetag_print_cloud(coursetag_get_tags(0, 0, 'official', 0, 'name'), true, 200, 90); + } + +// Community (official and personal together) also called user tags +} else if ($show == 'community') { + + if ($sort == 'popularity') { + $tags = coursetag_print_cloud(coursetag_get_tags(0, 0, 'default', 0, 'popularity'), true, 200, 90); + } else if ($sort == 'date') { + $tags = coursetag_print_cloud(coursetag_get_tags(0, 0, 'default', 0, 'timemodified'), true, 200, 90); + } else { + $tags = coursetag_print_cloud(coursetag_get_tags(0, 0, 'default', 0, 'name'), true, 200, 90); + } + +// All tags for courses and blogs and any thing else tagged - the fallback default ($show == all) +} else { + + $subtitle = $showalltags; + if ($sort == 'popularity') { + $tags = coursetag_print_cloud(coursetag_get_all_tags('popularity'), true, 200, 90); + } else if ($sort == 'date') { + $tags = coursetag_print_cloud(coursetag_get_all_tags('timemodified'), true, 200, 90); + } else { + $tags = coursetag_print_cloud(coursetag_get_all_tags('name'), true, 200, 90); + } + +} + +// Prepare the links for the show and order lines +if ($show == 'all') { + $link1 .= ''.$showalltags.''; +} else { + $link1 .= ''.$showalltags.''; +} +//if ($show == 'official') { //add back in if you start to use official course tags +// $link1 .= ' | '.$showofficialtags.''; +//} else { +// $link1 .= ' | '.$showofficialtags.''; +//} +if ($show == 'community') { + $link1 .= ' | '.$showcommtags.''; +} else { + $link1 .= ' | '.$showcommtags.''; +} +if ($loggedin) { + if ($show == 'my') { + $link1 .= ' | '.$showmytags.''; + } else { + $link1 .= ' | '.$showmytags.''; + } +} +if ($courseid) { + if ($show == 'course') { + $link1 .= ' | '.get_string('moreshowcoursetags', $tagslang, $course->fullname).''; + } else { + $link1 .= ' | '.get_string('moreshowcoursetags', $tagslang, $course->fullname).''; + } +} +if ($sort == 'alpha') { + $link2 .= ''.$orderalpha.' | '; +} else { + $link2 .= ''.$orderalpha.' | '; +} +if ($sort == 'popularity') { + $link2 .= ''.$orderpop.' | '; +} else { + $link2 .= ''.$orderpop.' | '; +} +if ($sort == 'date') { + $link2 .= ''.$orderdate.''; +} else { + $link2 .= ''.$orderdate.''; +} + +// Prepare output +$fclass = ''; +// make the tags larger when there are not so many +if (strlen($tags) < 10000) { $fclass = 'coursetag_more_large'; } +$outstr = ' +
+
'.$welcome. + helpbutton('usingtags', 'using tags', $tagslang, TRUE, FALSE, '', TRUE).' +
+ + +
+
'. + $tags.' +
'; +echo $outstr; + +print_footer(); +?> diff --git a/tag/coursetagslib.php b/tag/coursetagslib.php new file mode 100644 index 00000000000..cc898ba94bf --- /dev/null +++ b/tag/coursetagslib.php @@ -0,0 +1,698 @@ +dirroot.'/tag/lib.php'; + +/** + * Returns an ordered array of tags associated with visible courses + * (boosted replacement of get_all_tags() allowing association with user and tagtype). + * + * @uses $CFG + * @param int $courseid, a 0 will return all distinct tags for visible courses + * @param int $userid optional the user id, a default of 0 will return all users tags for the course + * @param string $tagtype optional 'official' or 'default', empty returns both tag types + * @param int $numtags optional number of tags to display, default of 80 is set in the block, 0 returns all + * @param string $sort optional selected sorting, default is alpha sort (name) also timemodified or popularity + * @return array + */ +function coursetag_get_tags($courseid, $userid=0, $tagtype='', $numtags=0, $sort='name') { + + global $CFG, $DB; + + // get visible course ids + $courselist = array(); + if ($courseid === 0) { + if ($courses = $DB->get_records_select('course', 'visible=1 AND category>0', null, '', 'id')) { + foreach ($courses as $key => $value) { + $courselist[] = $key; + } + } + } + + // get tags from the db ordered by highest count first + $params = array(); + $sql = "SELECT id as tkey, name, id, tagtype, rawname, f.timemodified, flag, count + FROM {tag} t, + (SELECT tagid, MAX(timemodified) as timemodified, COUNT(id) as count + FROM {tag_instance} + WHERE itemtype = 'course' "; + + if ($courseid > 0) { + $sql .= " AND itemid = :courseid "; + $params['courseid'] = $courseid; + } else { + if (!empty($courselist)) { + list($usql, $uparams) = $DB->get_in_or_equal($courselist, SQL_PARAMS_NAMED); + $sql .= "AND itemid $usql "; + $params = $params + $uparams; + } + } + + if ($userid > 0) { + $sql .= " AND tiuserid = :userid "; + $params['userid'] = $userid; + } + + $sql .= " GROUP BY tagid) f + WHERE t.id = f.tagid "; + if ($tagtype != '') { + $sql .= "AND tagtype = :tagtype "; + $params['tagtype'] = $tagtype; + } + $sql .= "ORDER BY count DESC, name ASC"; + + // limit the number of tags for output + if ($numtags == 0) { + $tags = $DB->get_records_sql($sql, $params); + } else { + $tags = $DB->get_records_sql($sql, $params, 0, $numtags); + } + + // prepare the return + $return = array(); + if ($tags) { + // sort the tag display order + if ($sort != 'popularity') { + $CFG->tagsort = $sort; + usort($tags, "coursetag_sort"); + } + // avoid print_tag_cloud()'s ksort upsetting ordering by setting the key here + foreach ($tags as $value) { + $return[] = $value; + } + } + + return $return; + +} + +/** + * Returns an ordered array of tags + * (replaces popular_tags_count() allowing sorting). + * + * @uses $CFG + * @param string $sort optional selected sorting, default is alpha sort (name) also timemodified or popularity + * @param int $numtags optional number of tags to display, default of 20 is set in the block, 0 returns all + * @return array + */ +function coursetag_get_all_tags($sort='name', $numtags=0) { + + global $CFG, $DB; + + // note that this selects all tags except for courses that are not visible + $sql = "SELECT id, name, id, tagtype, rawname, f.timemodified, flag, count + FROM {tag} t, + (SELECT tagid, MAX(timemodified) as timemodified, COUNT(id) as count + FROM {tag_instance} WHERE tagid NOT IN + (SELECT tagid FROM {tag_instance} ti, {course} c + WHERE c.visible = 0 + AND ti.itemtype = 'course' + AND ti.itemid = c.id) + GROUP BY tagid) f + WHERE t.id = f.tagid + ORDER BY count DESC, name ASC"; + if ($numtags == 0) { + $tags = $DB->get_records_sql($sql); + } else { + $tags = $DB->get_records_sql($sql, null, 0, $numtags); + } + + $return = array(); + if ($tags) { + if ($sort != 'popularity') { + $CFG->tagsort = $sort; + usort($tags, "coursetag_sort"); + } + foreach ($tags as $value) { + $return[] = $value; + } + } + + return $return; +} + +/** + * Callback function for coursetag_get_tags() and coursetag_get_all_tags() only + * @uses $CFG + */ +function coursetag_sort($a, $b) { + // originally from block_blog_tags + global $CFG; + + // set up the variable $tagsort as either 'name' or 'timemodified' only, 'popularity' does not need sorting + if (empty($CFG->tagsort)) { + $tagsort = 'name'; + } else { + $tagsort = $CFG->tagsort; + } + + if (is_numeric($a->$tagsort)) { + return ($a->$tagsort == $b->$tagsort) ? 0 : ($a->$tagsort > $b->$tagsort) ? 1 : -1; + } elseif (is_string($a->$tagsort)) { + return strcmp($a->$tagsort, $b->$tagsort); + } else { + return 0; + } +} + +/** + * Prints a tag cloud + * + * @param array $tagcloud array of tag objects (fields: id, name, rawname, count and flag) + * @param int $max_size maximum text size, in percentage + * @param int $min_size minimum text size, in percentage + * @param $return if true return html string + */ +function coursetag_print_cloud($tagcloud, $return=false, $max_size=180, $min_size=80) { + + global $CFG; + + if (empty($tagcloud)) { + return; + } + + ksort($tagcloud); + + $count = array(); + foreach ($tagcloud as $key => $value) { + if(!empty($value->count)) { + $count[$key] = log10($value->count); + } else { + $count[$key] = 0; + } + } + + $max = max($count); + $min = min($count); + + $spread = $max - $min; + if (0 == $spread) { // we don't want to divide by zero + $spread = 1; + } + + $step = ($max_size - $min_size)/($spread); + + $systemcontext = get_context_instance(CONTEXT_SYSTEM); + $can_manage_tags = has_capability('moodle/tag:manage', $systemcontext); + + //prints the tag cloud + $output = '
    '; + foreach ($tagcloud as $key => $tag) { + + $size = $min_size + ((log10($tag->count) - $min) * $step); + $size = ceil($size); + + $style = 'style="font-size: '.$size.'%"'; + + if ($tag->count > 1) { + $title = 'title="'.s(get_string('thingstaggedwith','tag', $tag)).'"'; + } else { + $title = 'title="'.s(get_string('thingtaggedwith','tag', $tag)).'"'; + } + + $href = 'href="'.$CFG->wwwroot.'/tag/index.php?id='.$tag->id.'"'; + + //highlight tags that have been flagged as inappropriate for those who can manage them + $tagname = tag_display_name($tag); + if ($tag->flag > 0 && $can_manage_tags) { + $tagname = '' . tag_display_name($tag) . ''; + } + + $tag_link = '
  • '.$tagname.'
  • '; + + $output .= $tag_link; + + } + $output .= '
'."\n"; + + if ($return) { + return $output; + } else { + echo $output; + } +} + +/** + * Returns javascript for use in tags block and supporting pages + * @param string $coursetagdivs comma separated divs ids + * @uses $CFG + */ +function coursetag_get_jscript($coursetagdivs = '') { + + global $CFG, $DB; + + $tabscript = ''; + if ($coursetagdivs) { + $tabscript = 'var coursetagdivs = new Array('.$coursetagdivs.');'; + } + + $coursetags = $DB->get_records('tag', null, 'name ASC', 'name, id'); + $a = 0; + $coursetagscript = ''; + if (!empty($coursetags)) { + foreach ($coursetags as $key => $value) { + $coursetagscript .= "coursetag_tags[$a] = \"".addslashes_js($key)."\"; "; + $a++; + } + } + + $jserror1 = get_string('jserror1', 'block_tags'); + $jserror2 = get_string('jserror2', 'block_tags'); + + $inputscript = << 50) { + alert("$jserror1"); + return false; + //can't check this - unterminated string error } else if (val.indexOf("\\") > 0) { + } else if (val.indexOf("<") > 0) { + alert("$jserror2"); + return false; + } else if (val.indexOf(">") > 0) { + alert("$jserror2"); + return false; + } else { + return true; + } + } +EOT; + + $str = ' + + '; + + return $str; +} + +/** + * Returns javascript to create the links in the tag block footer. + */ +function coursetag_get_jscript_links($coursetagslinks) { + + $links = ''; + if (!empty($coursetagslinks)) { + $links .= '
'; + foreach ($coursetagslinks as $a) { + $links .= ''.$a['text'].' |'; + } + $links = addslashes_js(rtrim($links, '|')); + } + + $str = ' + '; + + return $str; +} + +/** + * Returns all tags created by a user for a course + * + * @uses $CFG + * @param int $courseid + * @param int $userid + */ +function coursetag_get_records($courseid, $userid) { + + global $CFG, $DB; + + $sql = "SELECT t.id, name, rawname + FROM {tag} t, {tag_instance} ti + WHERE t.id = ti.tagid + AND ti.tiuserid = :userid + AND ti.itemid = :courseid + ORDER BY name ASC"; + + return $DB->get_records_sql($sql, array('userid'=>$userid, 'courseid'=>$courseid)); +} + +/** + * Stores a tag for a course for a user + * + * @uses $CFG + * @param array $tags simple array of keywords to be stored + * @param integer $courseid + * @param integer $userid + * @param string $tagtype official or default only + * @param string $myurl optional for logging creation of course tags + */ +function coursetag_store_keywords($tags, $courseid, $userid=0, $tagtype='official', $myurl='') { + + global $CFG; + + if (is_array($tags) and !empty($tags)) { + + //tag_set_add('course', $courseid, $tags, $userid); + //if ($tagtype == 'official') { + // $tags_ids = tag_get_id($tags); + //} + + foreach($tags as $tag) { + $tag = trim($tag); + if (strlen($tag) > 0) { + tag_set_add('course', $courseid, $tag, $userid); + if ($myurl) { + $url = $myurl.'?query='.urlencode($tag); + } + if ($tagtype == 'default' and $myurl != '') { + // log the tagging request - note only for user added tags + add_to_log($courseid, 'coursetags', 'add', $url, 'Course tagged'); + } + if ($tagtype == 'official') { + tag_type_set(tag_get_id($tag), $tagtype); + } + } + } + } + +} + +/** + * Deletes a personal tag for a user for a course. + * + * @uses $CFG + * @param int $tagid + * @param int $userid + * @param int $courseid + */ +function coursetag_delete_keyword($tagid, $userid, $courseid) { + + global $CFG, $DB; + + $sql = "SELECT COUNT(*) + FROM {tag_instance} + WHERE tagid = $tagid + AND tiuserid = $userid + AND itemtype = 'course' + AND itemid = $courseid"; + if ($DB->count_records_sql($sql) == 1) { + $sql = "tagid = $tagid + AND tiuserid = $userid + AND itemtype = 'course' + AND itemid = $courseid"; + $DB->delete_records_select('tag_instance', $sql); + // if there are no other instances of the tag then consider deleting the tag as well + if (!$DB->record_exists('tag_instance', array('tagid' => $tagid))) { + // if the tag is a personal tag then delete it - don't do official tags + if ($DB->record_exists('tag', array('id' => $tagid, 'tagtype' => 'default'))) { + $DB->delete_records('tag', array('id' => $tagid, 'tagtype' => 'default')); + } + } + } else { + print_error("errordeleting", 'tag', '', $tagid); + } + +} + +/** + * Get courses tagged with a tag + * + * @param int $tagid + * @return array of course objects + */ +function coursetag_get_tagged_courses($tagid) { + + global $DB; + + $courses = array(); + if ($crs = $DB->get_records_select('tag_instance', "tagid=:tagid AND itemtype='course'", array('tagid'=>$tagid))) { + foreach ($crs as $c) { + //this capability check was introduced to stop display of courses that a student could not + //view, but arguably it is best that when clicking on a tag, the tagged course summary should + //be seen and then if the student clicks on that they will be given the opportunity to join + //note courses not visible should not have their tagid sent to this function + //if (has_capability('moodle/course:view', get_context_instance(CONTEXT_COURSE, $c->itemid))) { + $course = $DB->get_record('course', array('id'=>$c->itemid)); + $courses[$c->itemid] = $course; + //} + } + } + return $courses; + +} + +/** + * Course tagging function used only during the deletion of a + * course (called by lib/moodlelib.php) to clean up associated tags + * + * @param $courseid + * @param $showfeedback + */ +function coursetag_delete_course_tags($courseid, $showfeedback=false) { + + global $DB; + + if ($tags = $DB->get_records_select('tag_instance', "itemtype='course' AND itemid=:courseid", array('courseid'=>$courseid))) { + foreach ($tags as $tag) { + //delete the course tag instance record + $DB->delete_records('tag_instance', array('tagid'=>$tag->tagid, 'itemtype'=>'course', 'itemid'=> $courseid)); + // delete tag if there are no other tag_instance entries now + if (!($DB->record_exists('tag_instance', array('tagid'=>$tag->tagid)))) { + $DB->delete_records('tag', array('id'=>$tag->tagid)); + } + } + } + + if ($showfeedback) { + notify(get_string('deletedcoursetags', 'tag')); + } +} + +/** + * Function called by cron to create/update users rss feeds + * + * @uses $CFG + * @return true + * + * Function removed. + * rsslib.php needs updating to accept Dublin Core tags (dc/cc) input before this can work. + */ +/* +function coursetag_rss_feeds() { + + global $CFG, $DB; + require_once($CFG->dirroot.'/lib/dmllib.php'); + require_once($CFG->dirroot.'/lib/rsslib.php'); + + $status = true; + mtrace(' Preparing to update all user unit tags RSS feeds'); + if (empty($CFG->enablerssfeeds)) { + mtrace(' RSS DISABLED (admin variables - enablerssfeeds)'); + } else { + + // Load all the categories for use later on + $categories = $DB->get_records('course_categories'); + + // get list of users who have tagged a unit + $sql = " + SELECT DISTINCT u.id as userid, u.username, u.firstname, u.lastname, u.email + FROM {user} u, {course} c, {tag_instance} cti, {tag} t + WHERE c.id = cti.itemid + AND u.id = cti.tiuserid + AND t.id = cti.tagid + AND t.tagtype = 'personal' + AND u.confirmed = 1 + AND u.deleted = 0 + ORDER BY userid"; + if ($users = $DB->get_records_sql($sql)) { + + $items = array(); //contains rss data items for each user + foreach ($users as $user) { + + // loop through each user, getting the data (tags for courses) + $sql = " + SELECT cti.id, c.id as courseid, c.fullname, c.shortname, c.category, t.rawname, cti.timemodified + FROM {course} c, {tag_instance} cti, {tag} t + WHERE c.id = cti.itemid + AND cti.tiuserid = :userid{$user->userid} + AND cti.tagid = t.id + AND t.tagtype = 'personal' + ORDER BY courseid"; + if ($usertags = $DB->get_records_sql($sql, array('userid' => $user->userid))) { + $latest_date = 0; //latest date any tag was created by a user + $c = 0; //course identifier + + foreach ($usertags as $usertag) { + if ($usertag->courseid != $c) { + $c = $usertag->courseid; + $items[$c] = new stdClass(); + $items[$c]->title = $usertag->fullname . '(' . $usertag->shortname . ')'; + $items[$c]->link = $CFG->wwwroot . '/course/view.php?name=' . $usertag->shortname; + $items[$c]->description = ''; //needs to be blank + $items[$c]->category = $categories[$usertag->category]->name; + $items[$c]->subject[] = $usertag->rawname; + $items[$c]->pubdate = $usertag->timemodified; + $items[$c]->tag = true; + } else { + $items[$c]->subject[] .= $usertag->rawname; + } + // Check and set the latest modified date. + $latest_date = $usertag->timemodified > $latest_date ? $usertag->timemodified : $latest_date; + } + + // Setup some vars for use while creating the file + $path = $CFG->dataroot.'/1/usertagsrss/'.$user->userid; + $file_name = 'user_unit_tags_rss.xml'; + $title = get_string('rsstitle', 'tag', ucwords(strtolower($user->firstname.' '.$user->lastname))); + $desc = get_string('rssdesc', 'tag'); + // check that the path exists + if (!file_exists($path)) { + mtrace(' Creating folder '.$path); + check_dir_exists($path, TRUE, TRUE); + } + + // create or update the feed for the user + // this functionality can be copied into seperate lib as in next two lines + //require_once($CFG->dirroot.'/local/ocilib.php'); + //oci_create_rss_feed( $path, $file_name, $latest_date, $items, $title, $desc, $dc=true, $cc=false); + + // Set path to RSS file + $full_path = "$save_path/$file_name"; + + mtrace(" Preparing to update RSS feed for $file_name"); + + // First let's make sure there is work to do by checking the time the file was last modified, + // if a course was update after the file was mofified + if (file_exists($full_path)) { + if ($lastmodified = filemtime($full_path)) { + mtrace(" XML File $file_name Created on ".date( "D, j M Y G:i:s T", $lastmodified )); + mtrace(' Lastest course modification on '.date( "D, j M Y G:i:s T", $latest_date )); + if ($latest_date > $lastmodified) { + mtrace(" XML File $file_name needs updating"); + $changes = true; + } else { + mtrace(" XML File $file_name doesn't need updating"); + $changes = false; + } + } + } else { + mtrace(" XML File $file_name needs updating"); + $changes = true; + } + + if ($changes) { + // Now we know something has changed, write the new file + + if (!empty($items)) { + // First set rss feeds common headers + $header = rss_standard_header(strip_tags(format_string($title,true)), + $CFG->wwwroot, + $desc, + true, true); + // Now all the rss items + if (!empty($header)) { + $articles = rss_add_items($items,$dc,$cc); + } + // Now all rss feeds common footers + if (!empty($header) && !empty($articles)) { + $footer = rss_standard_footer(); + } + // Now, if everything is ok, concatenate it + if (!empty($header) && !empty($articles) && !empty($footer)) { + $result = $header.$articles.$footer; + } else { + $result = false; + } + } else { + $result = false; + } + + // Save the XML contents to file + if (!empty($result)) { + $rss_file = fopen($full_path, "w"); + if ($rss_file) { + $status = fwrite ($rss_file, $result); + fclose($rss_file); + } else { + $status = false; + } + } + + // Output result + if (empty($result)) { + // There was nothing to put into the XML file. Delete it! + if( is_file($full_path) ) { + mtrace(" There were no items for XML File $file_name. Deleting XML File"); + unlink($full_path); + mtrace(" $full_path -> (deleted)"); + } else { + mtrace(" There were no items for the XML File $file_name and no file to delete. Ignore."); + } + } else { + if (!empty($status)) { + mtrace(" $full_path -> OK"); + } else { + mtrace(" $full_path -> FAILED"); + } + } + } + //end of oci_create_rss_feed() + } + } + } + } + + return $status; +} + */ + +/** + * Get official keywords for the in header.html + * use: echo ''; + * @uses $CFG + * @param int $courseid + * @return string + * + * Function removed but fully working + * This function is potentially useful to anyone wanting to improve search results for course pages. + * The idea is to add official tags (not personal tags to prevent their deletion) to all + * courses (facility not added yet) which will be automatically added to the page header to boost + * search engine specificity/ratings. + */ +/* +function coursetag_get_official_keywords($courseid, $asarray=false) { + global $CFG; + $returnstr = ''; + $sql = "SELECT t.id, name, rawname + FROM {tag} t, {tag_instance} ti + WHERE ti.itemid = :courseid + AND ti.itemtype = 'course' + AND t.tagtype = 'official' + AND ti.tagid = t.id + ORDER BY name ASC"; + if ($tags = $DB->get_records_sql($sql, array('courseid' => $courseid))) { + if ($asarray) { + return $tags; + } + foreach ($tags as $tag) { + if( empty($CFG->keeptagnamecase) ) { + $textlib = textlib_get_instance(); + $name = $textlib->strtotitle($tag->name); + } else { + $name = $tag->rawname; + } + $returnstr .= $name.', '; + } + $returnstr = rtrim($returnstr, ', '); + } + return $returnstr; +} +*/ + +?> diff --git a/tag/edit.php b/tag/edit.php index 4c2696719e5..c17c2907664 100644 --- a/tag/edit.php +++ b/tag/edit.php @@ -90,7 +90,7 @@ if ($tagnew = $tagform->get_data()) { if (has_capability('moodle/tag:manage', $systemcontext)) { // rename tag if(!tag_rename($tag->id, $tagnew->rawname)) { - error('Error updating tag record'); + print_error('errorupdatingrecord', 'tag'); } } diff --git a/tag/index.php b/tag/index.php index 11d941b04bf..2e9747d19d1 100644 --- a/tag/index.php +++ b/tag/index.php @@ -14,7 +14,7 @@ if (empty($CFG->usetags)) { } $tagid = optional_param('id', 0, PARAM_INT); // tag id -$tagname = optional_param('tag', '', PARAM_TAG); // tag +$tagname = optional_param('tag', '', PARAM_TAG); // tag $edit = optional_param('edit', -1, PARAM_BOOL); $userpage = optional_param('userpage', 0, PARAM_INT); // which page to show @@ -78,8 +78,64 @@ print_heading($tagname, '', 2, 'headingblock header tag-heading'); tag_print_management_box($tag); tag_print_description_box($tag); -$usercount = tag_record_count('user', $tag->id); +// Display courses tagged with the tag +require_once($CFG->dirroot.'/tag/coursetagslib.php'); +if ($courses = coursetag_get_tagged_courses($tag->id)) { + $totalcount = count( $courses ); + print_box_start('generalbox', 'tag-blogs'); //could use an id separate from tag-blogs, but would have to copy the css style to make it look the same + + $heading = get_string('tagindex_coursetitle', 'tag', $tagname) .': '. $totalcount; + print_heading($heading, '', 3); + + foreach ($courses as $course) { + print_course($course); + } + + print_box_end(); +} + +// Print up to 10 previous blogs entries + +// I was not able to use get_items_tagged_with() because it automatically +// tries to join on 'blog' table, since the itemtype is 'blog'. However blogs +// uses the post table so this would not really work. - Yu 29/8/07 +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)) { + + print_box_start('generalbox', 'tag-blogs'); + $heading = get_string('relatedblogs', 'tag', $tagname); + print_heading($heading, '', 3); + + echo ''; + + echo '

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

'; + + print_box_end(); + } +} + +$usercount = tag_record_count('user', $tag->id); if ($usercount > 0) { //user table box @@ -95,49 +151,8 @@ if ($usercount > 0) { print_box_end(); } -// Print last 10 blogs - -// I was not able to use get_items_tagged_with() because it automatically -// tries to join on 'blog' table, since the itemtype is 'blog'. However blogs -// uses the post table so this would not really work. - Yu 29/8/07 -if (has_capability('moodle/blog:view', $systemcontext)) { // You have to see blogs obviously - - if ($blogs = blog_fetch_entries('', 10, 0, 'site', '', $tag->id)) { - - print_box_start('generalbox', 'tag-blogs'); - - print_heading(get_string('relatedblogs', 'tag'), '', 3); - - echo ''; - - echo '

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

'; - - print_box_end(); - } -} - - echo ''; - //----------------- right column ----------------- $blocks_preferred_width = bounded_number(180, blocks_preferred_width($pageblocks[BLOCK_POS_RIGHT]), 210); @@ -151,9 +166,6 @@ if (blocks_have_content($pageblocks, BLOCK_POS_RIGHT) || $PAGE->user_is_editing( /// Finish the page echo '
'; - - $PAGE->print_footer(); - ?> diff --git a/tag/lib.php b/tag/lib.php index 14c9a26efc7..4e2b1e27fa0 100644 --- a/tag/lib.php +++ b/tag/lib.php @@ -63,9 +63,10 @@ define('TAG_RELATED_CORRELATED', 2); * @param int $record_id the id of the record to tag * @param array $tags the array of tags to set on the record. If * given an empty array, all tags will be removed. + * @param int $userid optional only required for course tagging * @return void */ -function tag_set($record_type, $record_id, $tags) { +function tag_set($record_type, $record_id, $tags, $userid = 0) { static $in_recursion_semaphore = false; // this is to prevent loops when tagging a tag if ( $record_type == 'tag' && !$in_recursion_semaphore) { @@ -108,7 +109,7 @@ function tag_set($record_type, $record_id, $tags) { $tag_current_id = $new_tag[$clean_tag]; } - tag_assign($record_type, $record_id, $tag_current_id, $ordering); + tag_assign($record_type, $record_id, $tag_current_id, $ordering, $userid); // if we are tagging a tag (adding a manually-assigned related tag), we // need to create the opposite relationship as well. @@ -127,17 +128,18 @@ function tag_set($record_type, $record_id, $tags) { * 'user' for users, etc. * @param int $record_id the id of the record to tag * @param string $tag the tag to add + * @param int $userid optional only required for course tagging * @return void */ -function tag_set_add($record_type, $record_id, $tag) { +function tag_set_add($record_type, $record_id, $tag, $userid = 0) { $new_tags = array(); - foreach( tag_get_tags($record_type, $record_id) as $current_tag ) { + foreach( tag_get_tags($record_type, $record_id, NULL, $userid) as $current_tag ) { $new_tags[] = $current_tag->rawname; } $new_tags[] = $tag; - return tag_set($record_type, $record_id, $new_tags); + return tag_set($record_type, $record_id, $new_tags, $userid); } /** @@ -236,9 +238,10 @@ function tag_get($field, $value, $returnfields='id, name, rawname') { * @param int $record_id the record id for which we want to get the tags * @param string $type the tag type (either 'default' or 'official'). By default, * all tags are returned. + * @param int $userid optional only required for course tagging * @return array the array of tags */ -function tag_get_tags($record_type, $record_id, $type=null) { +function tag_get_tags($record_type, $record_id, $type=null, $userid=0) { global $CFG, $DB; $params = array(); @@ -250,9 +253,15 @@ function tag_get_tags($record_type, $record_id, $type=null) { $sql_type = ''; } + $u = null; + if ($userid) { + $u = "AND ti.tiuserid = :userid "; + $params['userid'] = $userid; + } + $sql = "SELECT tg.id, tg.tagtype, tg.name, tg.rawname, tg.flag, ti.ordering FROM {tag_instance} ti JOIN {tag} tg ON tg.id = ti.tagid - WHERE ti.itemtype = :recordtype AND ti.itemid = :recordid $sql_type + WHERE ti.itemtype = :recordtype AND ti.itemid = :recordid $u $sql_type ORDER BY ti.ordering ASC"; $params['recordtype'] = $record_type; $params['recordid'] = $record_id; @@ -662,12 +671,13 @@ function tag_add($tags, $type="default") { * @param int $record_id the id of the record that will be tagged * @param string $tagid the tag id to set on the record. * @param int $ordering the order of the instance for this record + * @param int $userid optional only required for course tagging * @return bool true on success, false otherwise */ -function tag_assign($record_type, $record_id, $tagid, $ordering) { +function tag_assign($record_type, $record_id, $tagid, $ordering, $userid = 0) { global $DB; - if ( $tag_instance_object = $DB->get_record('tag_instance', array('tagid'=>$tagid, 'itemtype'=>$record_type, 'itemid'=>$record_id), 'id')) { + if ( $tag_instance_object = $DB->get_record('tag_instance', array('tagid'=>$tagid, 'itemtype'=>$record_type, 'itemid'=>$record_id, 'tiuserid'=>$userid), 'id')) { $tag_instance_object->ordering = $ordering; $tag_instance_object->timemodified = time(); return $DB->update_record('tag_instance', $tag_instance_object); @@ -678,6 +688,7 @@ function tag_assign($record_type, $record_id, $tagid, $ordering) { $tag_instance_object->itemtype = $record_type; $tag_instance_object->ordering = $ordering; $tag_instance_object->timemodified = time(); + $tag_instance_object->tiuserid = $userid; return $DB->insert_record('tag_instance', $tag_instance_object); } } diff --git a/version.php b/version.php index 7f6a528c15d..829a6299713 100644 --- a/version.php +++ b/version.php @@ -6,7 +6,7 @@ // This is compared against the values stored in the database to determine // whether upgrades should be performed (see lib/db/*.php) - $version = 2008051203; // YYYYMMDD = date of the last version bump + $version = 2008063001; // YYYYMMDD = date of the last version bump // XX = daily increments $release = '2.0 dev (Build: 20080630)'; // Human-friendly version name