MDL-26675 block_rss_client: Add a new feed in the RSS block form

The patch added a couple of things:
- Add a new feed in the RSS block form
- Make the image responsive to the parent container
- Each feed now includes a channel link
This commit is contained in:
Meirza 2024-05-24 10:11:26 +07:00 committed by meirzamoodle
parent fd487cd3f2
commit b3e8993353
10 changed files with 242 additions and 48 deletions

View file

@ -61,19 +61,6 @@
protected function get_footer($feedrecords) {
$footer = null;
if ($this->config->block_rss_client_show_channel_link) {
global $CFG;
require_once($CFG->libdir.'/simplepie/moodle_simplepie.php');
$feedrecord = array_pop($feedrecords);
$feed = new moodle_simplepie($feedrecord->url);
$channellink = new moodle_url($feed->get_link());
if (!empty($channellink)) {
$footer = new block_rss_client\output\footer($channellink);
}
}
if ($this->hasfailedfeeds) {
if (has_any_capability(['block/rss_client:manageownfeeds', 'block/rss_client:manageanyfeeds'], $this->context)) {
if ($footer === null) {
@ -104,6 +91,15 @@
return $this->content;
}
$managefeedfooterlink = '';
if (has_any_capability(['block/rss_client:manageanyfeeds', 'block/rss_client:manageownfeeds'], $this->context)) {
$managefeedfooterlink = html_writer::link(
new moodle_url('/blocks/rss_client/managefeeds.php', ['courseid' => $this->page->course->id]),
get_string('managefeeds', 'block_rss_client'),
['class' => 'btn btn-primary', 'role' => 'button'],
);
}
if (!isset($this->config)) {
// The block has yet to be configured - just display configure message in
// the block if user has permission to configure it
@ -112,6 +108,8 @@
$this->content->text = get_string('feedsconfigurenewinstance2', 'block_rss_client');
}
$this->content->footer = $managefeedfooterlink;
return $this->content;
}
@ -156,6 +154,8 @@
$this->content->footer = $renderer->render_footer($footer);
}
$this->content->footer .= $managefeedfooterlink;
return $this->content;
}
@ -259,6 +259,12 @@
}
}
// Feed channel link.
if ($this->config->block_rss_client_show_channel_link) {
$channellink = $simplepiefeed->get_link();
$feed->set_channellink($channellink ? new moodle_url($channellink) : null);
}
return $feed;
}

View file

@ -44,6 +44,13 @@ class feed implements \renderable, \templatable {
*/
protected $title = null;
/**
* The feed's channel link.
*
* @var string|null
*/
protected ?string $channellink;
/**
* An array of renderable feed items
*
@ -78,11 +85,13 @@ class feed implements \renderable, \templatable {
* @param string $title The title of the RSS feed
* @param boolean $showtitle Whether to show the title
* @param boolean $showimage Whether to show the channel image
* @param string|null $channellink The channel link of the RSS feed
*/
public function __construct($title, $showtitle = true, $showimage = true) {
public function __construct($title, $showtitle = true, $showimage = true, ?string $channellink = null) {
$this->title = $title;
$this->showtitle = $showtitle;
$this->showimage = $showimage;
$this->channellink = $channellink;
}
/**
@ -97,6 +106,7 @@ class feed implements \renderable, \templatable {
'title' => $this->showtitle ? $this->title : null,
'image' => null,
'items' => array(),
'channellink' => $this->channellink ?? null,
);
if ($this->showimage && $this->image) {
@ -131,6 +141,15 @@ class feed implements \renderable, \templatable {
return $this->title;
}
/**
* Set the feed channel link.
*
* @param \moodle_url|null $channellink the URL to the channel website.
*/
public function set_channellink(?\moodle_url $channellink) {
$this->channellink = $channellink;
}
/**
* Add an RSS item
*

View file

@ -100,7 +100,6 @@ class footer implements \renderable, \templatable {
*/
public function export_for_template(\renderer_base $output) {
$data = new \stdClass();
$data->channellink = clean_param($this->channelurl, PARAM_URL);
if ($this->manageurl) {
$data->hasfailedfeeds = true;
$data->manageurl = clean_param($this->manageurl, PARAM_URL);

View file

@ -22,6 +22,10 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
require_once($CFG->libdir .'/simplepie/moodle_simplepie.php');
/**
* Form for editing RSS client block instances.
*
@ -29,24 +33,36 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class block_rss_client_edit_form extends block_edit_form {
/** @var stdClass|null The new RSS feed URL object. */
private ?stdClass $newrss = null;
protected function specific_definition($mform) {
global $CFG, $DB, $USER;
// Fields for editing block contents.
$mform->addElement('header', 'configheader', get_string('blocksettings', 'block'));
$mform->addElement('selectyesno', 'config_display_description', get_string('displaydescriptionlabel', 'block_rss_client'));
$mform->setDefault('config_display_description', 0);
$radiogroup = [
$mform->createElement('radio', 'config_method',
get_string('configmethodexisting', 'block_rss_client'), null, 'existing'),
$mform->createElement('radio', 'config_method',
get_string('configmethodnew', 'block_rss_client'), null, 'new'),
];
$mform->addGroup(
elements: $radiogroup,
name: 'config_method_group',
separator: ['   '],
appendName: false,
);
$mform->setDefault('config_method', 'existing');
$mform->addElement('text', 'config_shownumentries', get_string('shownumentrieslabel', 'block_rss_client'), array('size' => 5));
$mform->setType('config_shownumentries', PARAM_INT);
$mform->addRule('config_shownumentries', null, 'numeric', null, 'client');
if (!empty($CFG->block_rss_client_num_entries)) {
$mform->setDefault('config_shownumentries', $CFG->block_rss_client_num_entries);
} else {
$mform->setDefault('config_shownumentries', 5);
}
// Add new RSS feed.
$mform->addElement('text', 'config_feedurl', get_string('feedurl', 'block_rss_client'));
$mform->setType('config_feedurl', PARAM_URL);
$mform->hideIf('config_feedurl', 'config_method', 'ne', 'new');
// Select existing RSS feed.
$insql = '';
$params = array('userid' => $USER->id);
if (!empty($this->block->config) && !empty($this->block->config->rssid)) {
@ -68,21 +84,33 @@ class block_rss_client_edit_form extends block_edit_form {
if ($rssfeeds) {
$select = $mform->addElement('select', 'config_rssid', get_string('choosefeedlabel', 'block_rss_client'), $rssfeeds);
$select->setMultiple(true);
$mform->hideIf('config_rssid', 'config_method', 'ne', 'existing');
} else {
$mform->addElement('static', 'config_rssid_no_feeds', get_string('choosefeedlabel', 'block_rss_client'),
get_string('nofeeds', 'block_rss_client'));
$mform->hideIf('config_rssid_no_feeds', 'config_method', 'ne', 'existing');
}
if (has_any_capability(array('block/rss_client:manageanyfeeds', 'block/rss_client:manageownfeeds'), $this->block->context)) {
$mform->addElement('static', 'nofeedmessage', '',
'<a href="' . $CFG->wwwroot . '/blocks/rss_client/managefeeds.php?courseid=' . $this->page->course->id . '">' .
get_string('feedsaddedit', 'block_rss_client') . '</a>');
}
// Subheading: Display settings for RSS feed.
$startsubheading = '<div class="row"><h4 class="col-md-12 col-form-label d-flex">';
$endsubheading = '</h4></div>';
$mform->addElement('html', $startsubheading . get_string('displaysettings', 'block_rss_client') . $endsubheading);
$mform->addElement('text', 'config_title', get_string('uploadlabel'));
$mform->setType('config_title', PARAM_NOTAGS);
$mform->addElement('selectyesno', 'config_display_description', get_string('displaydescriptionlabel', 'block_rss_client'));
$mform->setDefault('config_display_description', 0);
$mform->addElement('text', 'config_shownumentries', get_string('shownumentrieslabel', 'block_rss_client'), ['size' => 5]);
$mform->setType('config_shownumentries', PARAM_INT);
$mform->addRule('config_shownumentries', null, 'numeric', null, 'client');
if (!empty($CFG->block_rss_client_num_entries)) {
$mform->setDefault('config_shownumentries', $CFG->block_rss_client_num_entries);
} else {
$mform->setDefault('config_shownumentries', 5);
}
$mform->addElement('selectyesno', 'config_block_rss_client_show_channel_link', get_string('clientshowchannellinklabel', 'block_rss_client'));
$mform->setDefault('config_block_rss_client_show_channel_link', 0);
@ -90,6 +118,91 @@ class block_rss_client_edit_form extends block_edit_form {
$mform->setDefault('config_block_rss_client_show_channel_image', 0);
}
/**
* Overriding the get_data function to insert a new RSS ID.
*/
public function get_data(): ?stdClass {
$data = parent::get_data();
// Force the 'existing` method as a default.
$data->config_method = 'existing';
// Sanitize the title to prevent XSS (Cross-Site Scripting) attacks by encoding special characters into HTML entities.
$data->config_title = htmlspecialchars($data->config_title, ENT_QUOTES, 'utf-8');
// If the new RSS is not empty then add the ID to the config_rssid.
if ($data && $this->newrss) {
$data->config_rssid[] = $this->newrss->id;
}
return $data;
}
/**
* Overriding the definition_after_data to empty the input.
*/
public function definition_after_data(): void {
parent::definition_after_data();
$mform =& $this->_form;
// If form is not submitted then empty the feed URL.
if (!$this->is_submitted()) {
$mform->getElement('config_feedurl')->setValue('');
}
}
/**
* Overriding the validation to validate the RSS URL and store it to the database.
*
* If there are no errors, insert the new feed to the database and store the object in
* the private property so it can be saved to the RSS block config.
*
* @param array $data Data from the form.
* @param array $files Files form the form.
* @return array of errors from validation.
*/
public function validation($data, $files): array {
global $USER, $DB;
$errors = parent::validation($data, $files);
if ($data['config_method'] === "new") {
// If the "New" method is selected and the feed URL is not empty, then proceed.
if ($data['config_feedurl']) {
if (!filter_var($data['config_feedurl'], FILTER_VALIDATE_URL)) {
$errors['config_feedurl'] = get_string('couldnotfindloadrssfeed', 'block_rss_client');
return $errors;
}
try {
$rss = new moodle_simplepie();
// Set timeout for longer than normal to try and grab the feed.
$rss->set_timeout(10);
$rss->set_feed_url($data['config_feedurl']);
$rss->set_autodiscovery_cache_duration(0);
$rss->set_autodiscovery_level(moodle_simplepie::LOCATOR_ALL);
$rss->init();
if ($rss->error()) {
$errors['config_feedurl'] = get_string('couldnotfindloadrssfeed', 'block_rss_client');
} else {
// Return URL without quoting.
$discoveredurl = new moodle_url($rss->subscribe_url());
$theurl = $discoveredurl->out(false);
// Save the RSS to the database.
$this->newrss = new stdClass;
$this->newrss->userid = $USER->id;
$this->newrss->title = $rss->get_title();
$this->newrss->description = $rss->get_description();
$this->newrss->url = $theurl;
$newrssid = $DB->insert_record('block_rss_client', $this->newrss);
$this->newrss->id = $newrssid;
}
} catch (Exception $e) {
$errors['config_feedurl'] = get_string('couldnotfindloadrssfeed', 'block_rss_client');
}
} else {
// If the "New" method is selected, but the feed URL is empty, then raise error.
$errors['config_feedurl'] = get_string('err_required', 'form');
}
}
return $errors;
}
/**
* Display the configuration form when block is being added to the page
*

View file

@ -27,17 +27,21 @@ $string['addheadlineblock'] = 'Add RSS headline block';
$string['addnew'] = 'Add new';
$string['addnewfeed'] = 'Add a new feed';
$string['cannotmakemodification'] = 'You are not allowed to make modifications to this RSS feed at this time.';
$string['choosefeedlabel'] = 'Select the feeds to display in this block';
$string['clientchannellink'] = 'Source site...';
$string['clientnumentries'] = 'The default number of entries to show per feed.';
$string['clientshowchannellinklabel'] = 'Should a link to the original site (channel link) be displayed? (Note that if no feed link is supplied in the news feed then no link will be shown) :';
$string['clientshowchannellinklabel'] = 'Show source link if available';
$string['clientshowimagelabel'] = 'Show channel image if available :';
$string['configblock'] = 'Configure this block';
$string['configmethodexisting'] = 'Select existing RSS feed';
$string['configmethodnew'] = 'Add new RSS feed';
$string['couldnotfindfeed'] = 'Could not find feed with id';
$string['couldnotfindloadrssfeed'] = 'Could not find or load the RSS feed.';
$string['customtitlelabel'] = 'Custom title (leave blank to use title supplied by feed):';
$string['deletefeedconfirm'] = 'Are you sure you want to delete this feed?';
$string['disabledrssfeeds'] = 'RSS feeds are disabled';
$string['displaydescriptionlabel'] = 'Display each link\'s description?';
$string['displaydescriptionlabel'] = 'Show descriptions for entries';
$string['displaysettings'] = 'Display settings for RSS feed';
$string['editafeed'] = 'Edit a feed';
$string['editfeeds'] = 'Edit, subscribe or unsubscribe from RSS/Atom news feeds';
$string['editnewsfeeds'] = 'Edit news feeds';
@ -54,11 +58,10 @@ $string['feedsaddedit'] = 'Add/edit feeds';
$string['feedsconfigurenewinstance'] = 'Click here to configure this block to display RSS feeds.';
$string['feedsconfigurenewinstance2'] = 'Click the edit icon above to configure this block to display RSS feeds.';
$string['feedupdated'] = 'News feed updated';
$string['feedurl'] = 'Feed URL';
$string['feedurl'] = 'RSS link';
$string['findmorefeeds'] = 'Find more RSS feeds';
$string['choosefeedlabel'] = 'Choose the feeds which you would like to make available in this block:';
$string['managefeeds'] = 'Manage all my feeds';
$string['nofeeds'] = 'There are no RSS feeds defined for this site.';
$string['nofeeds'] = 'There are no existing RSS feeds configured for this site. You can add one choosing \'Add new RSS feed\'.';
$string['numentries'] = 'Entries per feed';
$string['pickfeed'] = 'Pick a news feed';
$string['pluginname'] = 'Remote RSS feeds';
@ -81,7 +84,7 @@ $string['rss_client:manageownfeeds'] = 'Manage own RSS feeds';
$string['rss_client:myaddinstance'] = 'Add a new Remote RSS feeds block to Dashboard';
$string['seeallfeeds'] = 'See all feeds';
$string['sharedfeed'] = 'Shared feed';
$string['shownumentrieslabel'] = 'Max number entries to show per block.';
$string['shownumentrieslabel'] = 'Entries to display';
$string['submitters'] = 'Who will be allowed to define new RSS feeds? Defined feeds are available for any page on your site.';
$string['submitters2'] = 'Submitters';
$string['timeout'] = 'Time in minutes before an RSS feed expires in cache. Note that this time defines the minimum time before expiry; the feed will be refreshed in cache on the next cron execution after expiry. Recommended values are 30 mins or greater.';

View file

@ -55,7 +55,8 @@
"permalink": "https://www.example.com/my-cat-story.html",
"datepublished": "12 January 2016, 9:12 pm"
}
]
],
"channellink": "https://www.example.com"
},
{
"title": "News from around my kitchen",
@ -81,7 +82,8 @@
"permalink": "https://www.example.com/oven-smoke.html",
"datepublished": "13 January 2016, 8:25 pm"
}
]
],
"channellink": "https://www.example.com"
}
]
}

View file

@ -42,7 +42,7 @@
<a href="{{{link}}}">
{{/link}}
<img src="{{{url}}}" alt="{{title}}" />
<img src="{{{url}}}" alt="{{title}}" class="img-fluid">
{{#link}}
</a>

View file

@ -55,7 +55,8 @@
"permalink": "https://www.example.com/my-cat-story.html",
"datepublished": "12 January 2016, 9:12 pm"
}
]
],
"channellink": "https://www.example.com"
}
}}
{{$image}}
@ -77,3 +78,9 @@
{{/items}}
</ul>
{{/items}}
{{#channellink}}
<div class="pb-3 text-right">
<a href="{{{channellink}}}" rel="noopener noreferrer" target="_blank">{{#str}} clientchannellink, block_rss_client {{/str}}</a>
</div>
{{/channellink}}

View file

@ -30,13 +30,10 @@
Example context (json):
{
"channellink": "https://www.example.com/feeds/rss"
"hasfailedfeeds": true,
"manageurl": "http://moodle.web/blocks/rss_client/managefeeds.php?courseid=1"
}
}}
{{#channellink}}
<a href="{{{channellink}}}">{{#str}} clientchannellink, block_rss_client {{/str}}</a>
{{#hasfailedfeeds}}<br>{{/hasfailedfeeds}}
{{/channellink}}
{{#hasfailedfeeds}}
<a href="{{{manageurl}}}">{{#str}} failedfeeds, block_rss_client {{/str}}</a>
{{/hasfailedfeeds}}
<a href="{{{manageurl}}}" class="d-block mb-3">{{#str}} failedfeeds, block_rss_client {{/str}}</a>
{{/hasfailedfeeds}}

View file

@ -0,0 +1,48 @@
@block @block_rss_client
Feature: Enable RSS client block menu on the frontpage
In order to enable the RSS client block on the frontpage
As an admin
I can add RSS client block to the frontpage
Background:
Given I log in as "admin"
When I navigate to "Plugins > Blocks > Manage blocks" in site administration
Then I enable "rss_client" "block" plugin
And the following "blocks" exist:
| blockname | contextlevel | reference | pagetypepattern | defaultregion |
| rss_client | System | 1 | site-index | side-pre |
@javascript
Scenario: Configuring the RSS block on the frontpage
Given I log in as "admin"
And I am on site homepage
And I turn editing mode on
And "Remote news feed" "block" should exist
And I configure the "Remote news feed" block
And I should see "There are no existing RSS feeds configured for this site. You can add one choosing 'Add new RSS feed'."
# Test filling in an empty URL in the input.
And I click on "Add new RSS feed" "radio"
And I press "Save changes"
And I should see "You must supply a value here."
# Test filling in with a non-valid URL in the input.
And I set the field "config_feedurl" to "https://example.com/notvalid.rss"
And I press "Save changes"
And I should see "Could not find or load the RSS feed."
# Test filling in with the correct URL in the input.
And I set the field "config_feedurl" to "https://www.nasa.gov/rss/dyn/breaking_news.rss"
And I set the field "config_block_rss_client_show_channel_link" to "Yes"
And I press "Save changes"
And I should see "NASA"
And I should see "Source site..."
# Test the existence of the available feeds.
When I configure the "NASA" block
Then I should see "NASA" in the "Select the feeds to display in this block" "select"
And I click on "Cancel" "button" in the "Configure NASA block" "dialogue"
# Test the Manage all my feeds page.
And I click on "Manage all my feeds" "link"
And I should see "NASA"