|
| 1 | +<?php |
| 2 | +// This file is part of Moodle - http://moodle.org/ |
| 3 | +// |
| 4 | +// Moodle is free software: you can redistribute it and/or modify |
| 5 | +// it under the terms of the GNU General Public License as published by |
| 6 | +// the Free Software Foundation, either version 3 of the License, or |
| 7 | +// (at your option) any later version. |
| 8 | +// |
| 9 | +// Moodle is distributed in the hope that it will be useful, |
| 10 | +// but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 | +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 12 | +// GNU General Public License for more details. |
| 13 | +// |
| 14 | +// You should have received a copy of the GNU General Public License |
| 15 | +// along with Moodle. If not, see <http://www.gnu.org/licenses/>. |
| 16 | + |
| 17 | +/** |
| 18 | + * RSS Thumbnail Block |
| 19 | + * |
| 20 | + * @package block_rss_thumbnails |
| 21 | + * @copyright 2020 - CALL Learning - Laurent David <laurent@call-learning> |
| 22 | + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later |
| 23 | + */ |
| 24 | + |
| 25 | +use block_rss_thumbnails\output\block; |
| 26 | + |
| 27 | +defined('MOODLE_INTERNAL') || die(); |
| 28 | +global $CFG; |
| 29 | +require_once($CFG->dirroot . '/blocks/rss_client/block_rss_client.php'); |
| 30 | + |
| 31 | +/** |
| 32 | + * Class block_rss_thumbnails |
| 33 | + * |
| 34 | + * @package block_rss_thumbnails |
| 35 | + * @copyright 2020 - CALL Learning - Laurent David <laurent@call-learning> |
| 36 | + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later |
| 37 | + */ |
| 38 | +class block_rss_thumbnails extends block_rss_client { |
| 39 | + |
| 40 | + const DEFAULT_CAROUSSEL_SPEED = 4000; |
| 41 | + |
| 42 | + /** @var bool track whether any of the output feeds have recorded failures */ |
| 43 | + private $hasfailedfeeds = false; |
| 44 | + |
| 45 | + /** |
| 46 | + * Init function |
| 47 | + * |
| 48 | + * @throws coding_exception |
| 49 | + */ |
| 50 | + public function init() { |
| 51 | + $this->title = get_string('pluginname', 'block_rss_thumbnails'); |
| 52 | + } |
| 53 | + |
| 54 | + /** |
| 55 | + * Content for the block |
| 56 | + * |
| 57 | + * @return \stdClass|string|null |
| 58 | + * @throws coding_exception |
| 59 | + */ |
| 60 | + public function get_content() { |
| 61 | + $this->page->requires->css( |
| 62 | + new moodle_url('/blocks/rss_thumbnails/js/glide/dist/css/glide.core' . |
| 63 | + (debugging() ? '.min' : '') . '.css')); |
| 64 | + global $CFG, $DB; |
| 65 | + |
| 66 | + if ($this->content !== null) { |
| 67 | + return $this->content; |
| 68 | + } |
| 69 | + |
| 70 | + // initalise block content object |
| 71 | + $this->content = new stdClass; |
| 72 | + $this->content->text = ''; |
| 73 | + $this->content->footer = ''; |
| 74 | + |
| 75 | + if (empty($this->instance)) { |
| 76 | + return $this->content; |
| 77 | + } |
| 78 | + |
| 79 | + if (!isset($this->config)) { |
| 80 | + // The block has yet to be configured - just display configure message in |
| 81 | + // the block if user has permission to configure it |
| 82 | + |
| 83 | + if (has_capability('block/rss_client:manageanyfeeds', $this->context)) { |
| 84 | + $this->content->text = get_string('feedsconfigurenewinstance2', 'block_rss_client'); |
| 85 | + } |
| 86 | + |
| 87 | + return $this->content; |
| 88 | + } |
| 89 | + |
| 90 | + // How many feed items should we display? |
| 91 | + $maxentries = 5; |
| 92 | + if (!empty($this->config->shownumentries)) { |
| 93 | + $maxentries = intval($this->config->shownumentries); |
| 94 | + } else if (isset($CFG->block_rss_client_num_entries)) { |
| 95 | + $maxentries = intval($CFG->block_rss_client_num_entries); |
| 96 | + } |
| 97 | + |
| 98 | + /* --------------------------------- |
| 99 | + * Begin Normal Display of Block Content |
| 100 | + * --------------------------------- */ |
| 101 | + |
| 102 | + $renderer = $this->page->get_renderer('block_rss_thumbnails'); |
| 103 | + $carousselspeed = empty($this->config->carousselspeed) ? self::DEFAULT_CAROUSSEL_SPEED : $this->config->carousselspeed; |
| 104 | + $block = new block($carousselspeed); |
| 105 | + |
| 106 | + if (!empty($this->config->rssid)) { |
| 107 | + list($rssidssql, $params) = $DB->get_in_or_equal($this->config->rssid); |
| 108 | + $rssfeeds = $DB->get_records_select('block_rss_client', "id $rssidssql", $params); |
| 109 | + |
| 110 | + if (!empty($rssfeeds)) { |
| 111 | + $showtitle = false; |
| 112 | + if (count($rssfeeds) > 1) { |
| 113 | + // When many feeds show the title for each feed. |
| 114 | + $showtitle = true; |
| 115 | + } |
| 116 | + |
| 117 | + foreach ($rssfeeds as $feed) { |
| 118 | + if ($renderablefeed = $this->get_feed($feed, $maxentries, $showtitle)) { |
| 119 | + $block->add_feed($renderablefeed); |
| 120 | + } |
| 121 | + } |
| 122 | + |
| 123 | + $footer = $this->get_footer($rssfeeds); |
| 124 | + } |
| 125 | + } |
| 126 | + |
| 127 | + $this->content->text = $renderer->render_block($block); |
| 128 | + if (isset($footer)) { |
| 129 | + $this->content->footer = $renderer->render_footer($footer); |
| 130 | + } |
| 131 | + |
| 132 | + return $this->content; |
| 133 | + } |
| 134 | + |
| 135 | + /** |
| 136 | + * Gets the footer, which is the channel link of the last feed in our list of feeds |
| 137 | + * |
| 138 | + * @param array $feedrecords The feed records from the database. |
| 139 | + * @return block_rss_client\output\footer|null The renderable footer or null if none should be displayed. |
| 140 | + */ |
| 141 | + protected function get_footer($feedrecords) { |
| 142 | + $footer = null; |
| 143 | + |
| 144 | + if (!empty($this->config->show_channel_link)) { |
| 145 | + global $CFG; |
| 146 | + require_once($CFG->libdir . '/simplepie/moodle_simplepie.php'); |
| 147 | + |
| 148 | + $feedrecord = array_pop($feedrecords); |
| 149 | + $feed = new moodle_simplepie($feedrecord->url); |
| 150 | + $channellink = new moodle_url($feed->get_link()); |
| 151 | + |
| 152 | + if (!empty($channellink)) { |
| 153 | + $footer = new block_rss_client\output\footer($channellink); |
| 154 | + } |
| 155 | + } |
| 156 | + |
| 157 | + if ($this->hasfailedfeeds) { |
| 158 | + if (has_any_capability(['block/rss_client:manageownfeeds', 'block/rss_client:manageanyfeeds'], $this->context)) { |
| 159 | + if ($footer === null) { |
| 160 | + $footer = new block_rss_client\output\footer(); |
| 161 | + } |
| 162 | + $manageurl = new moodle_url('/blocks/rss_client/managefeeds.php', |
| 163 | + ['courseid' => $this->page->course->id]); |
| 164 | + $footer->set_failed($manageurl); |
| 165 | + } |
| 166 | + } |
| 167 | + |
| 168 | + return $footer; |
| 169 | + } |
| 170 | + |
| 171 | + /** |
| 172 | + * Returns the html of a feed to be displaed in the block |
| 173 | + * |
| 174 | + * @param mixed feedrecord The feed record from the database |
| 175 | + * @param int maxentries The maximum number of entries to be displayed |
| 176 | + * @param boolean showtitle Should the feed title be displayed in html |
| 177 | + * @return block_rss_client\output\feed|null The renderable feed or null of there is an error |
| 178 | + */ |
| 179 | + public function get_feed($feedrecord, $maxentries, $showtitle) { |
| 180 | + global $CFG; |
| 181 | + require_once($CFG->libdir . '/simplepie/moodle_simplepie.php'); |
| 182 | + |
| 183 | + if ($feedrecord->skipuntil) { |
| 184 | + // Last attempt to gather this feed via cron failed - do not try to fetch it now. |
| 185 | + $this->hasfailedfeeds = true; |
| 186 | + return null; |
| 187 | + } |
| 188 | + |
| 189 | + $simplepiefeed = new moodle_simplepie($feedrecord->url); |
| 190 | + |
| 191 | + if (isset($CFG->block_rss_client_timeout)) { |
| 192 | + $simplepiefeed->set_cache_duration($CFG->block_rss_client_timeout * 60); |
| 193 | + } |
| 194 | + |
| 195 | + if ($simplepiefeed->error()) { |
| 196 | + debugging($feedrecord->url . ' Failed with code: ' . $simplepiefeed->error()); |
| 197 | + return null; |
| 198 | + } |
| 199 | + |
| 200 | + if (empty($feedrecord->preferredtitle)) { |
| 201 | + // Simplepie does escape HTML entities. |
| 202 | + $feedtitle = $this->format_title($simplepiefeed->get_title()); |
| 203 | + } else { |
| 204 | + // Moodle custom title does not does escape HTML entities. |
| 205 | + $feedtitle = $this->format_title(s($feedrecord->preferredtitle)); |
| 206 | + } |
| 207 | + |
| 208 | + if (empty($this->config->title)) { |
| 209 | + //NOTE: this means the 'last feed' displayed wins the block title - but |
| 210 | + //this is exiting behaviour.. |
| 211 | + $this->title = strip_tags($feedtitle); |
| 212 | + } |
| 213 | + |
| 214 | + $feed = new \block_rss_client\output\feed($feedtitle, $showtitle, false); |
| 215 | + |
| 216 | + if ($simplepieitems = $simplepiefeed->get_items(0, $maxentries)) { |
| 217 | + foreach ($simplepieitems as $simplepieitem) { |
| 218 | + try { |
| 219 | + $imageurl = null; |
| 220 | + $content = $simplepieitem->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'content'); |
| 221 | + if ($content && !empty($content[0])) { |
| 222 | + $imageurl = $content[0]['attribs']['']['url']; |
| 223 | + if (!empty($this->config->remove_image_size_suffix)) { |
| 224 | + $imageurl = preg_replace('/-[0-9]+x[0-9]+/', '', $imageurl); |
| 225 | + } |
| 226 | + } |
| 227 | + $categories = array_map(function($cat) { |
| 228 | + return $cat->term; |
| 229 | + }, $simplepieitem->get_categories()); |
| 230 | + |
| 231 | + $item = new \block_rss_thumbnails\output\item( |
| 232 | + $simplepieitem->get_id(), |
| 233 | + new moodle_url($simplepieitem->get_link()), |
| 234 | + $simplepieitem->get_title(), |
| 235 | + $simplepieitem->get_description(), |
| 236 | + new moodle_url($simplepieitem->get_permalink()), |
| 237 | + $simplepieitem->get_date('U'), |
| 238 | + $this->config->display_description, |
| 239 | + $imageurl, |
| 240 | + $categories |
| 241 | + ); |
| 242 | + |
| 243 | + $feed->add_item($item); |
| 244 | + } catch (moodle_exception $e) { |
| 245 | + // If there is an error with the RSS item, we don't |
| 246 | + // want to crash the page. Specifically, moodle_url can |
| 247 | + // throw an exception of the param is an extremely |
| 248 | + // malformed url. |
| 249 | + debugging($e->getMessage()); |
| 250 | + } |
| 251 | + } |
| 252 | + } |
| 253 | + |
| 254 | + // Feed image. |
| 255 | + if ($imageurl = $simplepiefeed->get_image_url()) { |
| 256 | + try { |
| 257 | + $image = new \block_rss_client\output\channel_image( |
| 258 | + new moodle_url($imageurl), |
| 259 | + $simplepiefeed->get_image_title(), |
| 260 | + new moodle_url($simplepiefeed->get_image_link()) |
| 261 | + ); |
| 262 | + |
| 263 | + $feed->set_image($image); |
| 264 | + } catch (moodle_exception $e) { |
| 265 | + // If there is an error with the RSS image, we don'twant to |
| 266 | + // crash the page. Specifically, moodle_url can throw an |
| 267 | + // exception if the param is an extremely malformed url. |
| 268 | + debugging($e->getMessage()); |
| 269 | + } |
| 270 | + } |
| 271 | + |
| 272 | + return $feed; |
| 273 | + } |
| 274 | + |
| 275 | +} |
0 commit comments