MDL-74590 contentbank: add custom fields to content bank

This commit is contained in:
Daniel Neis Araujo 2022-04-27 18:26:30 -03:00
parent a75365f2e4
commit d42e31899c
20 changed files with 457 additions and 4 deletions

View File

@ -842,6 +842,12 @@ if ($hassiteconfig) {
$temp = new admin_settingpage('managecontentbanktypes', new lang_string('managecontentbanktypes'));
$temp->add(new admin_setting_managecontentbankcontenttypes());
$ADMIN->add('contentbanksettings', $temp);
$ADMIN->add('contentbanksettings',
new admin_externalpage('contentbank', new lang_string('contentbankcustomfields', 'contentbank'),
$CFG->wwwroot . '/contentbank/customfield.php',
'moodle/contentbank:configurecustomfields'
)
);
$plugins = core_plugin_manager::instance()->get_plugins_of_type('contenttype');
foreach ($plugins as $plugin) {
/** @var \core\plugininfo\contentbank $plugin */

View File

@ -403,4 +403,14 @@ abstract class content {
$this->get_visibility() == self::VISIBILITY_PUBLIC ||
has_capability('moodle/contentbank:viewunlistedcontent', $context);
}
/**
* Checks if there are any custom field related to this content.
*
* @return bool True if there is at least one populated field.
*/
public function has_custom_fields(): bool {
$handler = \core_contentbank\customfield\content_handler::create();
return !empty($handler->get_instance_data($this->get_id()));
}
}

View File

@ -238,10 +238,17 @@ abstract class contenttype {
* @return string HTML code to include in view.php.
*/
public function get_view_content(content $content): string {
global $PAGE;
// Trigger an event for viewing this content.
$event = contentbank_content_viewed::create_from_record($content->get_content());
$event->trigger();
if ($content->has_custom_fields()) {
$renderer = $PAGE->get_renderer('core');
$renderable = new \core_contentbank\output\customfields($content);
return $renderer->render($renderable);
}
return '';
}

View File

@ -0,0 +1,191 @@
<?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/>.
namespace core_contentbank\customfield;
use core_customfield\api;
use core_customfield\field_controller;
/**
* Content handler for content bank custom fields
*
* @package core_contentbank
* @copyright 2024 Daniel Neis Araujo <daniel@adapta.online>
* @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class content_handler extends \core_customfield\handler {
/**
* @var content_handler
*/
static protected $singleton;
/**
* @var \context
*/
protected $parentcontext;
/** @var int Field is displayed in the content bank edit page, visible to everybody */
const VISIBLETOALL = 2;
/** @var int Field is not displayed in the content bank edit page */
const NOTVISIBLE = 0;
/**
* Returns a singleton
*
* @param int $itemid
* @return \core_contentbank\customfield\content_handler
*/
public static function create(int $itemid = 0): \core_contentbank\customfield\content_handler {
if (static::$singleton === null) {
self::$singleton = new static(0);
}
return self::$singleton;
}
/**
* Run reset code after unit tests to reset the singleton usage.
*/
public static function reset_caches(): void {
if (!PHPUNIT_TEST) {
throw new \coding_exception('This feature is only intended for use in unit tests');
}
static::$singleton = null;
}
/**
* The current user can configure custom fields on this component.
*
* @return bool true if the current can configure custom fields, false otherwise
*/
public function can_configure(): bool {
return has_capability('moodle/contentbank:configurecustomfields', $this->get_configuration_context());
}
/**
* The current user can edit custom fields on the content bank.
*
* @param field_controller $field
* @param int $instanceid id of the course to test edit permission
* @return bool true if the current can edit custom fields, false otherwise
*/
public function can_edit(field_controller $field, int $instanceid = 0): bool {
$context = $this->get_instance_context($instanceid);
return (!$field->get_configdata_property('locked') ||
has_capability('moodle/contentbank:changelockedcustomfields', $context));
}
/**
* The current user can view custom fields on the given course.
*
* @param field_controller $field
* @param int $instanceid id of the course to test edit permission
* @return bool true if the current can edit custom fields, false otherwise
*/
public function can_view(field_controller $field, int $instanceid): bool {
$visibility = $field->get_configdata_property('visibility');
if ($visibility == self::NOTVISIBLE) {
return false;
} else {
return true;
}
}
/**
* Context that should be used for new categories created by this handler
*
* @return \context the context for configuration
*/
public function get_configuration_context(): \context {
return \context_system::instance();
}
/**
* URL for configuration of the fields on this handler.
*
* @return \moodle_url The URL to configure custom fields for this component
*/
public function get_configuration_url(): \moodle_url {
return new \moodle_url('/contentbank/customfield.php');
}
/**
* Returns the context for the data associated with the given instanceid.
*
* @param int $instanceid id of the record to get the context for
* @return \context the context for the given record
*/
public function get_instance_context(int $instanceid = 0): \context {
global $DB;
$contextid = $DB->get_field('contentbank_content', 'contextid', ['id' => $instanceid]);
if (!$contextid || $contextid == SITEID) {
return \context_system::instance();
} else {
return \context::instance_by_id($contextid);
}
}
/**
* Allows to add custom controls to the field configuration form that will be saved in configdata
*
* @param \MoodleQuickForm $mform
*/
public function config_form_definition(\MoodleQuickForm $mform) {
$mform->addElement('header', 'content_handler_header', get_string('customfieldsettings', 'core_course'));
$mform->setExpanded('content_handler_header', true);
// If field is locked.
$mform->addElement('selectyesno', 'configdata[locked]', get_string('customfield_islocked', 'core_course'));
$mform->addHelpButton('configdata[locked]', 'customfield_islocked', 'core_course');
// Field data visibility.
$visibilityoptions = [self::VISIBLETOALL => get_string('customfield_visibletoall', 'core_course'),
self::NOTVISIBLE => get_string('customfield_notvisible', 'core_course')];
$mform->addElement('select', 'configdata[visibility]', get_string('customfield_visibility', 'core_course'),
$visibilityoptions);
$mform->addHelpButton('configdata[visibility]', 'customfield_visibility', 'core_course');
}
/**
* Creates or updates custom field data.
*
* @param \restore_task $task
* @param array $data
*/
public function restore_instance_data_from_backup(\restore_task $task, array $data) {
$courseid = $task->get_courseid();
$context = $this->get_instance_context($courseid);
$editablefields = $this->get_editable_fields($courseid);
$records = api::get_instance_fields_data($editablefields, $courseid);
$target = $task->get_target();
$override = ($target != \backup::TARGET_CURRENT_ADDING && $target != \backup::TARGET_EXISTING_ADDING);
foreach ($records as $d) {
$field = $d->get_field();
if ($field->get('shortname') === $data['shortname'] && $field->get('type') === $data['type']) {
if (!$d->get('id') || $override) {
$d->set($d->datafield(), $data['value']);
$d->set('value', $data['value']);
$d->set('valueformat', $data['valueformat']);
$d->set('contextid', $context->id);
$d->save();
}
return;
}
}
}
}

View File

@ -91,6 +91,12 @@ class copy_content extends external_api {
$crecord->name = $params['name'];
if ($content = $contenttype->create_content($crecord)) {
$handler = \core_contentbank\customfield\content_handler::create();
$handler->instance_form_before_set_data($record);
$record->id = $content->get_id();
$handler->instance_form_save($record);
$fs = get_file_storage();
$files = $fs->get_area_files($context->id, 'contentbank', 'public', $params['contentid'], 'itemid, filepath,
filename', false);

View File

@ -56,10 +56,10 @@ abstract class edit_content extends moodleform {
* @param string $method Form method.
*/
public function __construct(string $action = null, array $customdata = null, string $method = 'post') {
parent::__construct($action, $customdata, $method);
$this->contextid = $customdata['contextid'];
$this->plugin = $customdata['plugin'];
$this->id = $customdata['id'];
$this->id = $customdata['id'] ?? 0;
parent::__construct($action, $customdata, $method);
$mform =& $this->_form;
$mform->addElement('hidden', 'contextid', $this->contextid);
@ -72,6 +72,21 @@ abstract class edit_content extends moodleform {
$this->_form->setType('id', PARAM_INT);
}
/**
* Add elements to form
*/
protected function definition() {
global $DB;
// Add custom fields to the form.
$content = $DB->get_record('contentbank_content', ['id' => $this->id]);
$handler = \core_contentbank\customfield\content_handler::create();
$handler->instance_form_definition($this->_form, $this->id);
if ($content) {
$handler->instance_form_before_set_data($content);
}
$this->set_data($content);
}
/**
* Overrides formslib's add_action_buttons() method.
*

View File

@ -0,0 +1,62 @@
<?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/>.
namespace core_contentbank\output;
use renderable;
use templatable;
use renderer_base;
use core_contentbank\content;
/**
* Content bank Custom fields renderable class.
*
* @package core_contentbank
* @copyright 2024 Daniel Neis Araujo <daniel@adapta.online>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class customfields implements renderable, templatable {
/**
* Constructor.
*
* @param \core_contentbank\content $content The content object.
*/
public function __construct(content $content) {
$this->content = $content;
}
/**
* Export the data.
*
* @param renderer_base $output
* @return stdClass
*/
public function export_for_template(renderer_base $output) {
global $DB;
$context = new \stdClass();
$context->url = $this->content->get_file_url();
$context->name = $this->content->get_name();
$handler = \core_contentbank\customfield\content_handler::create();
$customfields = $handler->get_instance_data($this->content->get_id());
$context->data = $handler->display_custom_fields_data($customfields);
return $context;
}
}

View File

@ -174,6 +174,10 @@ class viewcontent implements renderable, templatable {
$contenthtml = $this->contenttype->get_view_content($this->content);
$data->contenthtml = $contenthtml;
$handler = \core_contentbank\customfield\content_handler::create();
$customfields = $handler->get_instance_data($this->content->get_id());
$data->customfieldshtml = $handler->display_custom_fields_data($customfields);
// Check if the user can edit this content type.
if ($this->contenttype->can_edit($this->content)) {
$data->usercanedit = true;

View File

@ -116,6 +116,7 @@ class editor extends edit_content {
$mform->addElement('cancel', 'cancel', get_string('back'));
} else {
$this->h5peditor->add_editor_to_form($mform);
parent::definition();
$this->add_action_buttons();
}
}
@ -157,6 +158,10 @@ class editor extends edit_content {
// Create entry in content bank.
$contenttype = new contenttype($context);
$newcontent = $contenttype->create_content($cbrecord);
$cfdata = fullclone($data);
$cfdata->id = $newcontent->get_id();
$handler = \core_contentbank\customfield\content_handler::create();
$handler->instance_form_save($cfdata, true);
if ($file && $newcontent) {
$updatedfilerecord = new stdClass();
$updatedfilerecord->id = $file->get_id();
@ -172,6 +177,10 @@ class editor extends edit_content {
} else {
// Update content.
$this->content->update_content();
$cfdata = fullclone($data);
$cfdata->id = $this->content->get_id();
$handler = \core_contentbank\customfield\content_handler::create();
$handler->instance_form_save($cfdata, true);
}
return $contentid ?? $newcontent->get_id();

View File

@ -0,0 +1,37 @@
<?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/>.
/**
* Manage Content Bank custom fields
*
* @package core_contentbank
* @copyright 2024 Daniel Neis Araujo <daniel@adapta.online>
* @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
require_once('../config.php');
require_once($CFG->libdir.'/adminlib.php');
admin_externalpage_setup('contentbank');
$output = $PAGE->get_renderer('core_customfield');
$handler = core_contentbank\customfield\content_handler::create();
$outputpage = new \core_customfield\output\management($handler);
echo $output->header(),
$output->heading(new lang_string('contentbank')),
$output->render($outputpage),
$output->footer();

View File

@ -0,0 +1,29 @@
{{!
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/>.
}}
{{!
@template core_contentbank/customfields
This template renders the view of the document on content bank.
Example context (json):
{
}
}}
<div class="customfields-container">
{{{data}}}
</div>

View File

@ -36,7 +36,8 @@
"contenthtml" : "<iframe src=\"http://something/h5p/embed.php?url=h5pfileurl\"></iframe>",
"usercanedit" : true,
"editcontenturl" : "http://something/contentbank/edit.php?contextid=1&plugin=h5p&id=1",
"closeurl" : "http://moodle.test/h5pcb/moodle/contentbank/index.php"
"closeurl" : "http://moodle.test/h5pcb/moodle/contentbank/index.php",
"customfieldshtml" : "custom fields html"
}
}}
<div class="core_contentbank_viewcontent">
@ -44,4 +45,7 @@
<div class="mt-1 mb-1" data-region="viewcontent-content">
{{{ contenthtml }}}
</div>
<div class="ps-2 pt-3">
{{{ customfieldshtml }}}
</div>
</div>

View File

@ -0,0 +1,39 @@
@core @core_contentbank @core_h5p @contentbank_h5p @_file_upload @javascript
Feature: Content bank custom fields
In order to add/edit custom fields for content
As a user
I need to be able to access the custom fields
Background:
Given the following "blocks" exist:
| blockname | contextlevel | reference | pagetypepattern | defaultregion |
| private_files | System | 1 | my-index | side-post |
And the following "custom field categories" exist:
| name | component | area | itemid |
| Category for test | core_contentbank | content | 0 |
And the following "custom fields" exist:
| name | category | type | shortname |
| Test field | Category for test | text | testfield |
And the following "contentbank content" exist:
| contextlevel | reference | contenttype | user | contentname | filepath |
| System | | contenttype_h5p | admin | filltheblanks.h5p | /h5p/tests/fixtures/filltheblanks.h5p |
And I log in as "admin"
And I am on site homepage
And I turn editing mode on
And the following config values are set as admin:
| unaddableblocks | | theme_boost|
And I add the "Navigation" block if not present
And I configure the "Navigation" block
And I set the following fields to these values:
| Page contexts | Display throughout the entire site |
And I press "Save changes"
Scenario: Users can edit customfields
Given I click on "Site pages" "list_item" in the "Navigation" "block"
And I click on "Content bank" "link" in the "Navigation" "block"
And I follow "filltheblanks.h5p"
And I click on "Edit" "link"
And I set the following fields to these values:
| Test field | My test value |
When I click on "Save" "button"
Then I should see "Test field: My test value"

View File

@ -25,6 +25,7 @@
$string['author'] = 'Author';
$string['contentbank'] = 'Content bank';
$string['choosecontext'] = 'Choose course or category...';
$string['contentbankcustomfields'] = 'Content bank custom fields';
$string['contentbankpreferences'] = 'Content bank preferences';
$string['contentcopied'] = 'Content copied.';
$string['contentdeleted'] = 'Content deleted.';
@ -42,6 +43,7 @@ $string['contentupdated'] = 'Content updated.';
$string['contextnotallowed'] = 'You are not allowed to access the content bank in this context.';
$string['copycontent'] = 'Copy content';
$string['copyof'] = 'Copy of {$a}';
$string['custombankfields'] = 'Custom bank fields';
$string['displayunlisted'] = 'Show unlisted content';
$string['emptynamenotallowed'] = 'Empty name is not allowed';
$string['eventcontentcreated'] = 'Content created';

View File

@ -152,6 +152,8 @@ $string['confirmunassigntitle'] = 'Confirm role change';
$string['confirmunassignyes'] = 'Remove';
$string['confirmunassignno'] = 'Cancel';
$string['contentbank:access'] = 'Access the content bank';
$string['contentbank:changelockedcustomfields'] = 'Change locked custom fields for content bank';
$string['contentbank:configurecustomfields'] = 'Configure custom fields for content bank';
$string['contentbank:copyanycontent'] = 'Copy any content in the content bank';
$string['contentbank:copycontent'] = 'Copy content in the content bank';
$string['contentbank:deleteanycontent'] = 'Delete any content from the content bank';

View File

@ -2629,6 +2629,24 @@ $capabilities = array(
]
],
'moodle/contentbank:configurecustomfields' => [
'riskbitmask' => RISK_SPAM,
'captype' => 'write',
'contextlevel' => CONTEXT_COURSE,
'archetypes' => [
'manager' => CAP_ALLOW,
],
],
'moodle/contentbank:changelockedcustomfields' => [
'riskbitmask' => RISK_SPAM,
'captype' => 'write',
'contextlevel' => CONTEXT_COURSE,
'archetypes' => [
'manager' => CAP_ALLOW,
],
],
// Allow users to download course content.
'moodle/course:downloadcoursecontent' => [
'captype' => 'read',

View File

@ -2400,6 +2400,10 @@ body.h5p-embed {
}
}
#page-contentbank-edit fieldset {
margin-top: 1em;
}
.text-decoration-none {
text-decoration: none !important; /* stylelint-disable-line declaration-no-important */
}

View File

@ -25401,6 +25401,10 @@ body.h5p-embed .h5pmessages {
margin: 0 auto;
}
#page-contentbank-edit fieldset {
margin-top: 1em;
}
.text-decoration-none {
text-decoration: none !important; /* stylelint-disable-line declaration-no-important */
}

View File

@ -25401,6 +25401,10 @@ body.h5p-embed .h5pmessages {
margin: 0 auto;
}
#page-contentbank-edit fieldset {
margin-top: 1em;
}
.text-decoration-none {
text-decoration: none !important; /* stylelint-disable-line declaration-no-important */
}

View File

@ -29,7 +29,7 @@
defined('MOODLE_INTERNAL') || die();
$version = 2024081000.00; // YYYYMMDD = weekly release date of this DEV branch.
$version = 2024081000.01; // YYYYMMDD = weekly release date of this DEV branch.
// RR = release increments - 00 in DEV branches.
// .XX = incremental changes.
$release = '4.5dev+ (Build: 20240810)'; // Human-friendly version name