/** * Returns the html of a feed to be displaed in the block * * @param mixed feedrecord The feed record from the database * @param int maxentries The maximum number of entries to be displayed * @param boolean showtitle Should the feed title be displayed in html * @return string html representing the rss feed content */ function get_feed_html($feedrecord, $maxentries, $showtitle) { global $CFG; require_once $CFG->libdir . '/simplepie/moodle_simplepie.php'; $feed = new moodle_simplepie($feedrecord->url); if (isset($CFG->block_rss_client_timeout)) { $feed->set_cache_duration($CFG->block_rss_client_timeout * 60); } if (debugging() && $feed->error()) { return '<p>' . $feedrecord->url . ' Failed with code: ' . $feed->error() . '</p>'; } $r = ''; // return string if ($this->config->block_rss_client_show_channel_image) { if ($image = $feed->get_image_url()) { $imagetitle = s($feed->get_image_title()); $imagelink = $feed->get_image_link(); $r .= '<div class="image" title="' . $imagetitle . '">' . "\n"; if ($imagelink) { $r .= '<a href="' . $imagelink . '">'; } $r .= '<img src="' . $image . '" alt="' . $imagetitle . '" />' . "\n"; if ($imagelink) { $r .= '</a>'; } $r .= '</div>'; } } if (empty($feedrecord->preferredtitle)) { $feedtitle = $this->format_title($feed->get_title()); } else { $feedtitle = $this->format_title($feedrecord->preferredtitle); } if ($showtitle) { $r .= '<div class="title">' . $feedtitle . '</div>'; } $r .= '<ul class="list no-overflow">' . "\n"; $feeditems = $feed->get_items(0, $maxentries); foreach ($feeditems as $item) { $r .= $this->get_item_html($item); } $r .= '</ul>'; if ($this->config->block_rss_client_show_channel_link) { $channellink = $feed->get_link(); if (!empty($channellink)) { //NOTE: this means the 'last feed' display wins the block title - but //this is exiting behaviour.. $this->content->footer = '<a href="' . htmlspecialchars(clean_param($channellink, PARAM_URL)) . '">' . get_string('clientchannellink', 'block_rss_client') . '</a>'; } } if (empty($this->config->title)) { //NOTE: this means the 'last feed' displayed wins the block title - but //this is exiting behaviour.. $this->title = strip_tags($feedtitle); } return $r; }
debugging($rss->error()); print_error('errorfetchingrssfeed'); } $strviewfeed = get_string('viewfeed', 'block_rss_client'); $PAGE->set_title($strviewfeed); $PAGE->set_heading($strviewfeed); $managefeeds = new moodle_url('/blocks/rss_client/managefeeds.php', $urlparams); $PAGE->navbar->add(get_string('blocks')); $PAGE->navbar->add(get_string('pluginname', 'block_rss_client')); $PAGE->navbar->add(get_string('managefeeds', 'block_rss_client'), $managefeeds); $PAGE->navbar->add($strviewfeed); echo $OUTPUT->header(); if (!empty($rssrecord->preferredtitle)) { $feedtitle = $rssrecord->preferredtitle; } else { $feedtitle = $rss->get_title(); } echo '<table align="center" width="50%" cellspacing="1">' . "\n"; echo '<tr><td colspan="2"><strong>' . s($feedtitle) . '</strong></td></tr>' . "\n"; foreach ($rss->get_items() as $item) { echo '<tr><td valign="middle">' . "\n"; echo '<a href="' . $item->get_link() . '" target="_blank"><strong>'; echo s($item->get_title()); echo '</strong></a>' . "\n"; echo '</td>' . "\n"; echo '</tr>' . "\n"; echo '<tr><td colspan="2"><small>'; echo format_text($item->get_description(), FORMAT_HTML) . '</small></td></tr>' . "\n"; } echo '</table>' . "\n"; echo $OUTPUT->footer();
/** * Given a record in the {blog_external} table, checks the blog's URL * for new entries not yet copied into Moodle. * Also attempts to identify and remove deleted blog entries * * @param object $externalblog * @return boolean False if the Feed is invalid */ function blog_sync_external_entries($externalblog) { global $CFG, $DB; require_once $CFG->libdir . '/simplepie/moodle_simplepie.php'; $rssfile = new moodle_simplepie_file($externalblog->url); $filetest = new SimplePie_Locator($rssfile); if (!$filetest->is_feed($rssfile)) { $externalblog->failedlastsync = 1; $DB->update_record('blog_external', $externalblog); return false; } else { if (!empty($externalblog->failedlastsync)) { $externalblog->failedlastsync = 0; $DB->update_record('blog_external', $externalblog); } } $rss = new moodle_simplepie($externalblog->url); if (empty($rss->data)) { return null; } //used to identify blog posts that have been deleted from the source feed $oldesttimestamp = null; $uniquehashes = array(); foreach ($rss->get_items() as $entry) { // If filtertags are defined, use them to filter the entries by RSS category if (!empty($externalblog->filtertags)) { $containsfiltertag = false; $categories = $entry->get_categories(); $filtertags = explode(',', $externalblog->filtertags); $filtertags = array_map('trim', $filtertags); $filtertags = array_map('strtolower', $filtertags); foreach ($categories as $category) { if (in_array(trim(strtolower($category->term)), $filtertags)) { $containsfiltertag = true; } } if (!$containsfiltertag) { continue; } } $uniquehashes[] = $entry->get_permalink(); $newentry = new stdClass(); $newentry->userid = $externalblog->userid; $newentry->module = 'blog_external'; $newentry->content = $externalblog->id; $newentry->uniquehash = $entry->get_permalink(); $newentry->publishstate = 'site'; $newentry->format = FORMAT_HTML; // Clean subject of html, just in case $newentry->subject = clean_param($entry->get_title(), PARAM_TEXT); // Observe 128 max chars in DB // TODO: +1 to raise this to 255 if (textlib::strlen($newentry->subject) > 128) { $newentry->subject = textlib::substr($newentry->subject, 0, 125) . '...'; } $newentry->summary = $entry->get_description(); //used to decide whether to insert or update //uses enty permalink plus creation date if available $existingpostconditions = array('uniquehash' => $entry->get_permalink()); //our DB doesnt allow null creation or modified timestamps so check the external blog supplied one $entrydate = $entry->get_date('U'); if (!empty($entrydate)) { $existingpostconditions['created'] = $entrydate; } //the post ID or false if post not found in DB $postid = $DB->get_field('post', 'id', $existingpostconditions); $timestamp = null; if (empty($entrydate)) { $timestamp = time(); } else { $timestamp = $entrydate; } //only set created if its a new post so we retain the original creation timestamp if the post is edited if ($postid === false) { $newentry->created = $timestamp; } $newentry->lastmodified = $timestamp; if (empty($oldesttimestamp) || $timestamp < $oldesttimestamp) { //found an older post $oldesttimestamp = $timestamp; } if (textlib::strlen($newentry->uniquehash) > 255) { // The URL for this item is too long for the field. Rather than add // the entry without the link we will skip straight over it. // RSS spec says recommended length 500, we use 255. debugging('External blog entry skipped because of oversized URL', DEBUG_DEVELOPER); continue; } if ($postid === false) { $id = $DB->insert_record('post', $newentry); // Set tags if ($tags = tag_get_tags_array('blog_external', $externalblog->id)) { tag_set('post', $id, $tags); } } else { $newentry->id = $postid; $DB->update_record('post', $newentry); } } // Look at the posts we have in the database to check if any of them have been deleted from the feed. // Only checking posts within the time frame returned by the rss feed. Older items may have been deleted or // may just not be returned anymore. We can't tell the difference so we leave older posts alone. $sql = "SELECT id, uniquehash\n FROM {post}\n WHERE module = 'blog_external'\n AND " . $DB->sql_compare_text('content') . " = " . $DB->sql_compare_text(':blogid') . "\n AND created > :ts"; $dbposts = $DB->get_records_sql($sql, array('blogid' => $externalblog->id, 'ts' => $oldesttimestamp)); $todelete = array(); foreach ($dbposts as $dbpost) { if (!in_array($dbpost->uniquehash, $uniquehashes)) { $todelete[] = $dbpost->id; } } $DB->delete_records_list('post', 'id', $todelete); $DB->update_record('blog_external', array('id' => $externalblog->id, 'timefetched' => time())); }
/** * Fetch the activity stream from the tracker and register the activity items * * @param int $before optionally filter activity that happened before this timestamp * @param int $after optionally filter activity that happened after this timestamp * @internal */ function dev_register_tracker_activity($before = null, $after = null) { global $DB; $filters = array(); $filters[] = 'streams=' . rawurlencode('key+IS+MDL+MDLQA+MDLSITE+MOBILE'); if (!is_null($before) and !is_null($after)) { $filters[] = 'streams=' . rawurlencode('update-date+BETWEEN+' . $after * 1000 . '+' . $before * 1000); } else { if (!is_null($before)) { $filters[] = 'streams=' . rawurlencode('update-date+BEFORE+' . $before * 1000); } else { if (!is_null($after)) { $filters[] = 'streams=' . rawurlencode('update-date+AFTER+' . $after * 1000); } } } $url = 'https://tracker.moodle.org/activity?' . implode('&', $filters); if (!is_null($after)) { fputs(STDOUT, date("Y-m-d H:i:s", $after)); } else { fputs(STDOUT, '*'); } fputs(STDOUT, ' - '); if (!is_null($before)) { fputs(STDOUT, date("Y-m-d H:i:s", $before)); } else { fputs(STDOUT, '*'); } $feed = new moodle_simplepie(); $feed->set_timeout(10); $feed->set_feed_url($url); $feed->init(); if ($error = $feed->error()) { fputs(STDERR, $error . PHP_EOL); exit(1); } $fetched = 0; $created = 0; foreach ($feed->get_items() as $item) { $fetched++; $activity = new stdClass(); $activity->uuid = $item->get_id(); $activity->title = $item->get_title(); $activity->timecreated = $item->get_date('U'); $activity->link = $item->get_link(); if ($tmp = $item->get_category()) { $activity->category = $tmp->get_term(); } if ($tmp = $item->get_author()) { $activity->personfullname = $tmp->get_name(); $activity->personemail = $tmp->get_email(); $activity->personlink = $tmp->get_link(); } if (!$DB->record_exists('dev_tracker_activities', array('uuid' => $activity->uuid))) { $DB->insert_record('dev_tracker_activities', $activity, false, true); $created++; } } fputs(STDOUT, sprintf(" %d %d %s\n", $fetched, $created, rawurldecode($url))); }
function get_content() { global $SESSION, $CFG, $USER, $OUTPUT; // quick and simple way to prevent block from showing up on front page if (!isloggedin()) { $this->content = NULL; return $this->content; } // which field is the username in $this->userfield = get_config('blocks/gmail', 'username') ? get_config('blocks/gmail', 'username') : 'username'; // quick and simple way to prevent block from showing up on users My Moodle if their email does not match the Google registered domain $this->domain = get_config('blocks/gmail', 'domainname') ? get_config('blocks/gmail', 'domainname') : get_config('auth/gsaml', 'domainname'); if ($this->content !== NULL) { return $this->content; } $this->content = new stdClass(); $this->content->items = array(); $this->content->icons = array(); $this->content->footer = ''; // This lib breaks install if left at top level only include // when we know we need it if ($USER->id !== 0) { require_once $CFG->libdir . '/simplepie/moodle_simplepie.php'; } // Test for domain settings if (empty($this->domain)) { $this->content->items = array(get_string('mustusegoogleauthenticaion', 'block_gmail')); $this->content->icons = array(); return $this->content; } if (!($this->oauthsecret = get_config('blocks/gmail', 'oauthsecret'))) { $this->content->items = array(get_string('missingoauthkey', 'block_gmail')); $this->content->icons = array(); return $this->content; } $feederror = false; // Obtain gmail feed data $feeddata = $this->obtain_gmail_feed(); if (empty($feeddata)) { $feederror = true; } else { // Parse google atom feed $feed = new moodle_simplepie(); $feed->set_raw_data($feeddata); $status = $feed->init(); $msgs = $feed->get_items(); } if ($feederror) { $this->content->items[] = get_string('sorrycannotgetmail', 'block_gmail'); } else { //$unreadmsgsstr = get_string('unreadmsgs','block_gmail'); $unreadmsgsstr = ''; $composestr = get_string('compose', 'block_gmail'); $inboxstr = get_string('inbox', 'block_gmail'); // Obtain link option $newwinlnk = get_config('blocks/gmail', 'newwinlink'); $composelink = '<a ' . ($newwinlnk ? 'target="_new"' : '') . ' href="' . 'http://mail.google.com/a/' . $this->domain . '/?AuthEventSource=SSO#compose">' . $composestr . '</a>'; $inboxlink = '<a ' . ($newwinlnk ? 'target="_new"' : '') . ' href="' . 'http://mail.google.com/a/' . $this->domain . '">' . $inboxstr . '</a>'; $this->content->items[] = '<img src="' . $OUTPUT->pix_url('gmail', 'block_gmail') . '" alt="message" /> ' . $inboxlink . ' ' . $composelink . ' ' . $unreadmsgsstr . '<br/>'; // Only show as many messages as specified in config $countmsg = true; if (!($msgnumber = get_config('blocks/gmail', 'msgnumber'))) { // 0 msg means as many as you want. $countmsg = false; } $mc = 0; // only show the detail if they have access to it if (!has_capability('block/gmail:viewlist', $this->page->context)) { $mc = count($msgs); $this->content->items[] = get_string('unread', 'block_gmail', $mc) . ($mc == 1 ? '' : 's') . '<br/>'; } else { foreach ($msgs as $msg) { if ($countmsg and $mc == $msgnumber) { break; } $mc++; // Displaying Message Data $author = $msg->get_author(); $author->get_name(); $summary = $msg->get_description(); // Google partners need a special gmail url $servicelink = $msg->get_link(); $servicelink = str_replace('http://mail.google.com/mail', 'http://mail.google.com/a/' . $this->domain, $servicelink); // To Save Space given them option to show first and last or just last name $authornames = explode(" ", $author->get_name()); $author_first = array_shift($authornames); $author_last = array_shift($authornames); // Show first Name if (!($showfirstname = get_config('blocks/gmail', 'showfirstname'))) { $author_first = ''; } // Show last Name if (!($showlastname = get_config('blocks/gmail', 'showlastname'))) { $author_last = ''; } // I should do clean_param($summary, PARAM_TEXT) But then ' will have \' if ($newwinlnk) { $text = '<a target="_new" title="' . format_string($summary); $text .= '" href="' . $servicelink . '">' . format_string($msg->get_title()) . '</a> ' . $author_first . ' ' . $author_last; $this->content->items[] = $text; } else { $text = '<a title="' . format_string($summary); $text .= '" href="' . $servicelink . '">' . format_string($msg->get_title()) . '</a> ' . $author_first . ' ' . $author_last; $this->content->items[] = $text; } } } } return $this->content; }
/** * Returns the html of a feed to be displaed in the block * * @param mixed feedrecord The feed record from the database * @param int maxentries The maximum number of entries to be displayed * @param boolean showtitle Should the feed title be displayed in html * @return block_rss_client\output\feed|null The renderable feed or null of there is an error */ public function get_feed($feedrecord, $maxentries, $showtitle) { global $CFG; require_once $CFG->libdir . '/simplepie/moodle_simplepie.php'; $simplepiefeed = new moodle_simplepie($feedrecord->url); if (isset($CFG->block_rss_client_timeout)) { $simplepiefeed->set_cache_duration($CFG->block_rss_client_timeout * 60); } if ($simplepiefeed->error()) { debugging($feedrecord->url . ' Failed with code: ' . $simplepiefeed->error()); return null; } if (empty($feedrecord->preferredtitle)) { $feedtitle = $this->format_title($simplepiefeed->get_title()); } else { $feedtitle = $this->format_title($feedrecord->preferredtitle); } if (empty($this->config->title)) { //NOTE: this means the 'last feed' displayed wins the block title - but //this is exiting behaviour.. $this->title = strip_tags($feedtitle); } $feed = new \block_rss_client\output\feed($feedtitle, $showtitle, $this->config->block_rss_client_show_channel_image); if ($simplepieitems = $simplepiefeed->get_items(0, $maxentries)) { foreach ($simplepieitems as $simplepieitem) { try { $item = new \block_rss_client\output\item($simplepieitem->get_id(), new moodle_url($simplepieitem->get_link()), $simplepieitem->get_title(), $simplepieitem->get_description(), new moodle_url($simplepieitem->get_permalink()), $simplepieitem->get_date('U'), $this->config->display_description); $feed->add_item($item); } catch (moodle_exception $e) { // If there is an error with the RSS item, we don't // want to crash the page. Specifically, moodle_url can // throw an exception of the param is an extremely // malformed url. debugging($e->getMessage()); } } } // Feed image. if ($imageurl = $simplepiefeed->get_image_url()) { try { $image = new \block_rss_client\output\channel_image(new moodle_url($imageurl), $simplepiefeed->get_image_title(), new moodle_url($simplepiefeed->get_image_link())); $feed->set_image($image); } catch (moodle_exception $e) { // If there is an error with the RSS image, we don'twant to // crash the page. Specifically, moodle_url can throw an // exception if the param is an extremely malformed url. debugging($e->getMessage()); } } return $feed; }
/** * Returns the html of a feed to be displaed in the block * * @param mixed feedrecord The feed record from the database * @param int maxentries The maximum number of entries to be displayed * @param boolean showtitle Should the feed title be displayed in html * @return string html representing the rss feed content */ function get_feed_html($feedrecord, $maxentries, $showtitle) { global $CFG; require_once $CFG->libdir . '/simplepie/moodle_simplepie.php'; $feed = new moodle_simplepie($feedrecord->url); if (isset($CFG->block_rss_plus_timeout)) { $feed->set_cache_duration($CFG->block_rss_plus_timeout * 60); } if (debugging() && $feed->error()) { return '<p>' . $feedrecord->url . ' Failed with code: ' . $feed->error() . '</p>'; } $r = ''; // return string if (empty($feedrecord->preferredtitle)) { $feedtitle = $this->format_title($feed->get_title()); } else { $feedtitle = $this->format_title($feedrecord->preferredtitle); } $r .= '<div class="rsswrap">'; $r .= '<ul class="list no-overflow">' . "\n"; $feeditems = $feed->get_items(0, $maxentries); foreach ($feeditems as $item) { $r .= $this->get_item_html($item); } $r .= '</ul>'; $r .= '</div>'; return $r; }
/** * Given a record in the {blog_external} table, checks the blog's URL * for new entries not yet copied into Moodle. * * @param object $externalblog * @return boolean False if the Feed is invalid */ function blog_sync_external_entries($externalblog) { global $CFG, $DB; require_once $CFG->libdir . '/simplepie/moodle_simplepie.php'; $rssfile = new moodle_simplepie_file($externalblog->url); $filetest = new SimplePie_Locator($rssfile); if (!$filetest->is_feed($rssfile)) { $externalblog->failedlastsync = 1; $DB->update_record('blog_external', $externalblog); return false; } else { if (!empty($externalblog->failedlastsync)) { $externalblog->failedlastsync = 0; $DB->update_record('blog_external', $externalblog); } } // Delete all blog entries associated with this external blog blog_delete_external_entries($externalblog); $rss = new moodle_simplepie($externalblog->url); if (empty($rss->data)) { return null; } foreach ($rss->get_items() as $entry) { // If filtertags are defined, use them to filter the entries by RSS category if (!empty($externalblog->filtertags)) { $containsfiltertag = false; $categories = $entry->get_categories(); $filtertags = explode(',', $externalblog->filtertags); $filtertags = array_map('trim', $filtertags); $filtertags = array_map('strtolower', $filtertags); foreach ($categories as $category) { if (in_array(trim(strtolower($category->term)), $filtertags)) { $containsfiltertag = true; } } if (!$containsfiltertag) { continue; } } $newentry = new stdClass(); $newentry->userid = $externalblog->userid; $newentry->module = 'blog_external'; $newentry->content = $externalblog->id; $newentry->uniquehash = $entry->get_permalink(); $newentry->publishstate = 'site'; $newentry->format = FORMAT_HTML; $newentry->subject = $entry->get_title(); $newentry->summary = $entry->get_description(); //our DB doesnt allow null creation or modified timestamps so check the external blog didnt supply one $entrydate = $entry->get_date('U'); if (empty($entrydate)) { $newentry->created = time(); $newentry->lastmodified = time(); } else { $newentry->created = $entrydate; $newentry->lastmodified = $entrydate; } $textlib = textlib_get_instance(); if ($textlib->strlen($newentry->uniquehash) > 255) { // The URL for this item is too long for the field. Rather than add // the entry without the link we will skip straight over it. // RSS spec says recommended length 500, we use 255. debugging('External blog entry skipped because of oversized URL', DEBUG_DEVELOPER); continue; } $id = $DB->insert_record('post', $newentry); // Set tags if ($tags = tag_get_tags_array('blog_external', $externalblog->id)) { tag_set('post', $id, $tags); } } $DB->update_record('blog_external', array('id' => $externalblog->id, 'timefetched' => mktime())); }