Merge branch 'MDL-70063-master-1' of git://github.com/mihailges/moodle

This commit is contained in:
Sara Arjona 2020-11-11 16:31:21 +01:00
commit c33f967019
7 changed files with 267 additions and 57 deletions

View File

@ -51,9 +51,6 @@ class block_tag_youtube extends block_base {
function specialization() {
$this->title = !empty($this->config->title) ? $this->config->title : get_string('pluginname', 'block_tag_youtube');
// Convert numeric categories (old YouTube API) to
// textual ones (new Google Data API)
$this->config->category = !empty($this->config->category) ? $this->category_map_old2new($this->config->category) : '0';
}
function instance_allow_multiple() {
@ -341,62 +338,71 @@ class block_tag_youtube extends block_base {
return $text;
}
function get_categories() {
// TODO: Right now using sticky categories from
// http://gdata.youtube.com/schemas/2007/categories.cat
// This should be performed from time to time by the block insead
// and cached somewhere, avoiding deprecated ones and observing regions
return array (
'0' => get_string('anycategory', 'block_tag_youtube'),
'Film' => get_string('filmsanimation', 'block_tag_youtube'),
'Autos' => get_string('autosvehicles', 'block_tag_youtube'),
'Music' => get_string('music', 'block_tag_youtube'),
'Animals'=> get_string('petsanimals', 'block_tag_youtube'),
'Sports' => get_string('sports', 'block_tag_youtube'),
'Travel' => get_string('travel', 'block_tag_youtube'),
'Games' => get_string('gadgetsgames', 'block_tag_youtube'),
'Comedy' => get_string('comedy', 'block_tag_youtube'),
'People' => get_string('peopleblogs', 'block_tag_youtube'),
'News' => get_string('newspolitics', 'block_tag_youtube'),
'Entertainment' => get_string('entertainment', 'block_tag_youtube'),
'Education' => get_string('education', 'block_tag_youtube'),
'Howto' => get_string('howtodiy', 'block_tag_youtube'),
'Tech' => get_string('scienceandtech', 'block_tag_youtube')
);
/**
* Method that returns an array containing all relevant video categories obtained through an API call, where the
* array index represents the category ID and the array value represents the category name.
*
* @return array The array containing the relevant video categories
* @throws moodle_exception If the API key is not set
* @throws Google_Service_Exception If an error occurs while obtaining the categories through the API call
*/
public function get_categories() {
// Get the default categories and it's translations.
$categorytranslations = $this->category_map_translation();
if ($service = $this->get_service()) {
// Call the API to fetch the youtube video categories.
// This API call requires the regionCode parameter which instructs the API to return the list of video
// categories available in the specified country. Currently 'us' is hardcoded as the returned categories
// for this region correspond to the previously used (legacy) hardcoded list of categories.
// TODO: We should improve this in the future and avoid hardcoding this value.
$response = $service->videoCategories->listVideoCategories('snippet', ['regionCode' => 'us']);
$categoryitems = $response['modelData']['items'];
// Return an array with the relevant categories.
return array_reduce($categoryitems, function($categories, $category) use ($categorytranslations) {
$categoryid = $category['id'];
$categoryname = $category['snippet']['title'];
// Videos can be associated with this category.
if ($category['snippet']['assignable']) {
// If the category name can be mapped with a translation, add it to the categories array.
if (array_key_exists($categoryname, $categorytranslations)) {
$categories[$categoryid] = $categorytranslations[$categoryname];
} else { // Otherwise, display the untranslated category name and show a debugging message.
$categories[$categoryid] = $categoryname;
debugging("The category '{$categoryname}' does not have a translatable language string.");
}
}
return $categories;
}, []);
} else {
throw new \moodle_exception('apierror', 'block_tag_youtube');
}
}
/**
* Provide conversion from old numeric categories available in youtube API
* to the new ones available in the Google API
* Method that provides mapping between the video category names and their translations.
*
* @param int $oldcat old category code
* @return mixed new category code or 0 (if no match found)
*
* TODO: Someday this should be applied on upgrade for all the existing
* block instances so we won't need the mapping any more. That would imply
* to implement restore handling to perform the conversion of old blocks.
* @return array The array that maps the video category names with their translations
*/
function category_map_old2new($oldcat) {
$oldoptions = array (
0 => '0',
1 => 'Film',
2 => 'Autos',
23 => 'Comedy',
24 => 'Entertainment',
10 => 'Music',
25 => 'News',
22 => 'People',
15 => 'Animals',
26 => 'Howto',
17 => 'Sports',
19 => 'Travel',
20 => 'Games'
);
if (array_key_exists($oldcat, $oldoptions)) {
return $oldoptions[$oldcat];
} else {
return $oldcat;
}
private function category_map_translation() {
return [
'Film & Animation' => get_string('filmsanimation', 'block_tag_youtube'),
'Autos & Vehicles' => get_string('autosvehicles', 'block_tag_youtube'),
'Music' => get_string('music', 'block_tag_youtube'),
'Pets & Animals' => get_string('petsanimals', 'block_tag_youtube'),
'Sports' => get_string('sports', 'block_tag_youtube'),
'Travel & Events' => get_string('travel', 'block_tag_youtube'),
'Gaming' => get_string('gadgetsgames', 'block_tag_youtube'),
'People & Blogs' => get_string('peopleblogs', 'block_tag_youtube'),
'Comedy' => get_string('comedy', 'block_tag_youtube'),
'Entertainment' => get_string('entertainment', 'block_tag_youtube'),
'News & Politics' => get_string('newspolitics', 'block_tag_youtube'),
'Howto & Style' => get_string('howtodiy', 'block_tag_youtube'),
'Education' => get_string('education', 'block_tag_youtube'),
'Science & Technology' => get_string('scienceandtech', 'block_tag_youtube'),
'Nonprofits & Activism' => get_string('nonprofitactivism', 'block_tag_youtube'),
];
}
/**

View File

@ -0,0 +1,130 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* This file keeps track of upgrades to the tag_youtube block
*
* @package block_tag_youtube
* @copyright 2020 Mihail Geshoski <mihail@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* Upgrade code for the Tag Youtube block.
*
* @param int $oldversion
*/
function xmldb_block_tag_youtube_upgrade($oldversion) {
global $DB, $CFG, $OUTPUT;
// Automatically generated Moodle v3.10.0 release upgrade line.
// Put any upgrade step following this.
if ($oldversion < 2021052501) {
// We need to fix every tag_youtube block instance that has used a legacy category name as a category config.
// The category config needs to store the category ID instead.
// If tag_youtube block instances exist.
if ($blockinstances = $DB->get_records('block_instances', ['blockname' => 'tag_youtube'])) {
$categories = [];
// The block tag youtube needs to be configured and have a valid API key in order to obtain the video
// category list.
if ($apikey = get_config('block_tag_youtube', 'apikey')) {
require_once($CFG->libdir . '/google/lib.php');
$client = get_google_client();
$client->setDeveloperKey($apikey);
$client->setScopes(array(Google_Service_YouTube::YOUTUBE_READONLY));
$service = new Google_Service_YouTube($client);
try {
// Get the video category list.
$response = $service->videoCategories->listVideoCategories('snippet', ['regionCode' => 'us']);
// Return an array of categories, where the key is the category name and the value is the
// category ID.
$categories = array_reduce($response['modelData']['items'], function ($categories, $category) {
$categoryid = $category['id'];
$categoryname = $category['snippet']['title'];
// If videos can be associated with this category, add it to the categories list.
if ($category['snippet']['assignable']) {
$categories[$categoryname] = $categoryid;
}
return $categories;
}, []);
} catch (Exception $e) {
$warn = "Due to the following error the youtube video categories were not obtained through the API:
'{$e->getMessage()}'. Therefore, any legacy values used as a category setting in Tag Youtube
block instances cannot be properly mapped and updated. All legacy values used as category setting
will still be updated and set by default to 'Any category'.";
echo $OUTPUT->notification($warn, 'notifyproblem');
}
} else {
$warn = "The API key is missing in the Tag Youtube block configuration. Therefore, the youtube video
categories cannot be obtained and mapped with the legacy values used as category setting. All legacy
values used as category setting will still be updated and set by default to 'Any category'.";
echo $OUTPUT->notification($warn, 'notifyproblem');
}
// Array that maps the old category names to the current category names.
$categorynamemap = [
'Film' => 'Film & Animation',
'Autos' => 'Autos & Vehicles',
'Comedy' => 'Comedy',
'Entertainment' => 'Entertainment',
'Music' => 'Music',
'News' => 'News & Politics',
'People' => 'People & Blogs',
'Animals' => 'Pets & Animals',
'Howto' => 'Howto & Style',
'Sports' => 'Sports',
'Travel' => 'Travel & Events',
'Games' => 'Gaming',
'Education' => 'Education',
'Tech' => 'Tech'
];
// If the block uses a legacy category name, update it to use the current category ID instead.
foreach ($blockinstances as $blockinstance) {
$blockconfig = unserialize(base64_decode($blockinstance->configdata));
$blockcategoryconfig = $blockconfig->category;
// The block is using a legacy category name as a category config.
if (array_key_exists($blockcategoryconfig, $categorynamemap)) {
if (!empty($categories)) { // The categories were successfully obtained through the API call.
// Get the current category name.
$currentcategoryname = $categorynamemap[$blockcategoryconfig];
// Add the category ID as a new category config for this block instance.
$blockconfig->category = $categories[$currentcategoryname];
} else { // The categories were not obtained through the API call.
// If the categories were not obtained through the API call, we are not able to map the
// current legacy category name with the category ID. Therefore, we should default the category
// config value to 0 ('Any category') to at least enable the block to function properly. The
// user can later manually select the desired category and re-save the config through the UI.
$blockconfig->category = 0;
}
$blockinstance->configdata = base64_encode(serialize($blockconfig));
$DB->update_record('block_instances', $blockinstance);
}
}
}
upgrade_block_savepoint(true, 2021052501, 'tag_youtube', false);
}
return true;
}

View File

@ -30,6 +30,8 @@
*/
class block_tag_youtube_edit_form extends block_edit_form {
protected function specific_definition($mform) {
global $OUTPUT;
$mform->addElement('header', 'configheader', get_string('blocksettings', 'block'));
$mform->addElement('text', 'config_title', get_string('configtitle', 'block_tag_youtube'));
@ -38,10 +40,26 @@ class block_tag_youtube_edit_form extends block_edit_form {
$mform->addElement('text', 'config_numberofvideos', get_string('numberofvideos', 'block_tag_youtube'), array('size' => 5));
$mform->setType('config_numberofvideos', PARAM_INT);
$categorychoices = $this->block->get_categories();
$mform->addElement('select', 'config_category', get_string('category', 'block_tag_youtube'), $categorychoices);
// Category setting.
$categorychoices = ['0' => get_string('anycategory', 'block_tag_youtube')];
$categoryerror = '';
try {
// Get all video categories through an API call and add them to the category list.
$categorychoices += $this->block->get_categories();
} catch (Exception $e) {
$categoryerror = $e->getMessage();
}
$mform->addElement('select', 'config_category', get_string('category', 'block_tag_youtube'),
$categorychoices);
$mform->setDefault('config_category', 0);
if ($categoryerror) {
$notification = $OUTPUT->notification(get_string('categoryerror', 'block_tag_youtube', $categoryerror),
'error');
$mform->addElement('static', 'config_category_error', '', $notification);
}
$mform->addElement('text', 'config_playlist', get_string('includeonlyvideosfromplaylist', 'block_tag_youtube'));
$mform->setType('config_playlist', PARAM_ALPHANUM);
}

View File

@ -32,12 +32,14 @@ $string['comedy'] = 'Comedy';
$string['configtitle'] = 'YouTube block title';
$string['education'] = 'Education';
$string['entertainment'] = 'Entertainment';
$string['categoryerror'] = 'Failed to obtain the list of categories. <br> {$a}';
$string['filmsanimation'] = 'Films & Animation';
$string['gadgetsgames'] = 'Gadgets & Games';
$string['howtodiy'] = 'How-to & DIY';
$string['includeonlyvideosfromplaylist'] = 'Include only videos from the playlist with id';
$string['music'] = 'Music';
$string['newspolitics'] = 'News & Politics';
$string['nonprofitactivism'] = 'Nonprofits & Activism';
$string['numberofvideos'] = 'Number of videos';
$string['peopleblogs'] = 'People & Blogs';
$string['petsanimals'] = 'Pets & Animals';

View File

@ -0,0 +1,48 @@
@block @block_tag_youtube
Feature: Adding and configuring YouTube block
In order to have the YouTube block used
As a admin
I need to add the YouTube block to the tags site page
Background:
Given I log in as "admin"
And I navigate to "Plugins > Blocks > Manage blocks" in site administration
And I click on "Show" "icon" in the "YouTube" "table_row"
@javascript
Scenario: Category options are not available (except default) in the block settings if the YouTube API key is not set.
Given the following config values are set as admin:
| apikey | | block_tag_youtube |
And I follow "Dashboard" in the user menu
And I press "Customise this page"
# TODO MDL-57120 site "Tags" link not accessible without navigation block.
And I add the "Navigation" block if not present
And I click on "Site pages" "list_item" in the "Navigation" "block"
And I click on "Tags" "link" in the "Navigation" "block"
And I add the "YouTube" block
When I configure the "YouTube" block
Then I should see "Category"
And I should see "Failed to obtain the list of categories."
And I should see "The YouTube API key is not set. Contact your administrator."
And the "Category" select box should contain "Any category"
And the "Category" select box should not contain "Films & Animation"
And the "Category" select box should not contain "Entertainment"
And the "Category" select box should not contain "Education"
@javascript
Scenario: Category options are not available (except default) in the block settings when invalid YouTube API key is set.
Given the following config values are set as admin:
| apikey | invalidapikeyvalue | block_tag_youtube |
And I follow "Dashboard" in the user menu
And I press "Customise this page"
And I add the "Navigation" block if not present
And I click on "Site pages" "list_item" in the "Navigation" "block"
And I click on "Tags" "link" in the "Navigation" "block"
And I add the "YouTube" block
When I configure the "YouTube" block
Then I should see "Category"
And I should see "Failed to obtain the list of categories."
And the "Category" select box should contain "Any category"
And the "Category" select box should not contain "Comedy"
And the "Category" select box should not contain "Autos & Vehicles"
And the "Category" select box should not contain "News & Politics"

View File

@ -1,5 +1,11 @@
This files describes API changes in the block tag_youtube code.
=== 3.10.1 ===
* The config category now stores the category ID, instead of a string representation of the category name.
In YouTube Data API v3, the API call to fetch the videos related to a certain category expects the category ID to be
passed to the videoCategoryId parameter, instead of the category name.
=== 3.0 ===
* Due to the final YouTube API v2.0 deprecation we needed to adapt the current

View File

@ -24,6 +24,6 @@
defined('MOODLE_INTERNAL') || die();
$plugin->version = 2021052500; // The current plugin version (Date: YYYYMMDDXX)
$plugin->version = 2021052501; // The current plugin version (Date: YYYYMMDDXX)
$plugin->requires = 2021052500; // Requires this Moodle version
$plugin->component = 'block_tag_youtube'; // Full name of the plugin (used for diagnostics)