Note: ->stringfilters update not done yet.
<?php // $Id$
- require_once('../config.php');
+///////////////////////////////////////////////////////////////////////////
+// //
+// NOTICE OF COPYRIGHT //
+// //
+// Moodle - Modular Object-Oriented Dynamic Learning Environment //
+// http://moodle.org //
+// //
+// Copyright (C) 1999 onwards Martin Dougiamas http://dougiamas.com //
+// //
+// This program 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 2 of the License, or //
+// (at your option) any later version. //
+// //
+// This program 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: //
+// //
+// http://www.gnu.org/copyleft/gpl.html //
+// //
+///////////////////////////////////////////////////////////////////////////
- $action = optional_param('action', '', PARAM_ACTION);
+/**
+ * Processes actions from the admin_setting_managefilters object (defined in
+ * adminlib.php).
+ *
+ * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
+ * @package administration
+ *//** */
+
+ require_once(dirname(__FILE__) . '/../config.php');
+
+ $action = optional_param('action', '', PARAM_ACTION);
$filterpath = optional_param('filterpath', '', PARAM_PATH);
require_login();
- require_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM));
+ $systemcontext = get_context_instance(CONTEXT_SYSTEM);
+ require_capability('moodle/site:config', $systemcontext);
$returnurl = "$CFG->wwwroot/$CFG->admin/settings.php?section=managefilters";
redirect($returnurl);
}
- // get a list of installed filters
- $installedfilters = array();
- $filterlocations = array('mod','filter');
- foreach ($filterlocations as $filterlocation) {
- $plugins = get_list_of_plugins($filterlocation);
- foreach ($plugins as $plugin) {
- $pluginpath = "$CFG->dirroot/$filterlocation/$plugin/filter.php";
- if (is_readable($pluginpath)) {
- $installedfilters["$filterlocation/$plugin"] = "$filterlocation/$plugin";
- }
- }
- }
+ $filters = filter_get_global_states();
- // get all the currently selected filters
- if (!empty($CFG->textfilters)) {
- $activefilters = explode(',', $CFG->textfilters);
- } else {
- $activefilters = array();
+ // In case any new filters have been installed, but not put in the table yet.
+ $fitlernames = filter_get_all_installed();
+ $newfilters = $fitlernames;
+ foreach ($filters as $filter => $notused) {
+ unset($newfilters[$filter]);
}
- //======================
- // Process Actions
- //======================
+ if (!isset($filters[$filterpath]) && !isset($newfilters[$filterpath])) {
+ throw new moodle_exception('filternotinstalled', 'error', $returnurl, $filterpath);
+ }
switch ($action) {
- case 'hide':
- $key=array_search($filterpath, $activefilters);
- // check filterpath is valid
- if ($key===false) {
- break;
- }
- // just delete it
- unset($activefilters[$key]);
- break;
-
- case 'show':
- // check filterpath is valid
- if (!array_key_exists($filterpath, $installedfilters)) {
- print_error('filternotinstalled', 'error', $url, $filterpath);
- } elseif (array_search($filterpath,$activefilters)) {
- // filterpath is already active - doubleclick??
- } else {
- // add it to installed filters
- $activefilters[] = $filterpath;
- $activefilters = array_unique($activefilters);
+ case 'setstate':
+ if ($newstate = optional_param('newstate', '', PARAM_INTEGER)) {
+ filter_set_global_state($filterpath, $newstate);
+ unset($newfilters[$filterpath]);
}
break;
case 'down':
- $key=array_search($filterpath, $activefilters);
- // check filterpath is valid
- if ($key===false) {
- print_error("filternotactive", 'error', $url, $filterpath );
- } elseif ($key>=(count($activefilters)-1)) {
- // cannot be moved any further down - doubleclick??
- } else {
- // swap with $key+1
- $fsave = $activefilters[$key];
- $activefilters[$key] = $activefilters[$key+1];
- $activefilters[$key+1] = $fsave;
+ if (isset($filters[$filterpath])) {
+ $oldpos = $filters[$filterpath]->sortorder;
+ if ($oldpos <= count($filters)) {
+ filter_set_global_state($filterpath, $filters[$filterpath]->active, $oldpos + 1);
+ }
}
break;
case 'up':
- $key=array_search($filterpath, $activefilters);
- // check filterpath is valid
- if ($key===false) {
- print_error("filternotactive", 'error', $url, $filterpath );
- } elseif ($key<1) {
- //cannot be moved any further up - doubleclick??
- } else {
- // swap with $key-1
- $fsave = $activefilters[$key];
- $activefilters[$key] = $activefilters[$key-1];
- $activefilters[$key-1] = $fsave;
+ if (isset($filters[$filterpath])) {
+ $oldpos = $filters[$filterpath]->sortorder;
+ if ($oldpos >= 1) {
+ filter_set_global_state($filterpath, $filters[$filterpath]->active, $oldpos - 1);
+ }
}
break;
+
+ case 'delete':
+ $filtername = $fitlernames[$filterpath];
+ if (substr($filterpath, 0, 4) == 'mod/') {
+ $mod = basename($filterpath);
+ $a = new stdClass;
+ $a->filter = $filtername;
+ $a->module = get_string('modulename', $mod);
+ print_error('cannotdeletemodfilter', 'admin', admin_url('qtypes.php'), $a);
+ }
+
+ // If not yet confirmed, display a confirmation message.
+ if (!optional_param('confirm', '', PARAM_BOOL)) {
+ $title = get_string('deletefilterareyousure', 'admin', $filtername);
+ print_header($title, $title);
+ print_heading($title);
+ notice_yesno(get_string('deletefilterareyousuremessage', 'admin', $filtername),
+ admin_url('filters.php?action=delete&filterpath=' . $delete . '&confirm=1&sesskey=' . sesskey()),
+ $returnurl, NULL, NULL, 'post', 'get');
+ print_footer('empty');
+ exit;
+ }
+
+ // Do the deletion.
+ $title = get_string('deletingfilter', 'admin', $filtername);
+ print_header($title, $title);
+ print_heading($title);
+
+ // Delete all data for this plugin.
+ filter_delete_all_data($filterpath);
+
+ $a = new stdClass;
+ $a->fitler = $filtername;
+ $a->directory = $filterparth;
+ print_box(get_string('deletefilterfiles', 'admin', $a), 'generalbox', 'notice');
+ print_continue($returnurl);
+ admin_externalpage_print_footer();
+ exit;
}
- // save, reset cache and return
- set_config('textfilters', implode(',', $activefilters));
+ // Add any missing filters to the DB table.
+ foreach ($newfilters as $filter => $notused) {
+ filter_set_global_state($filter, TEXTFILTER_DISABLED);
+ }
+
+ // Reset caches and return
reset_text_filters_cache();
redirect($returnurl);
-
-?>
$string['calendarexportsalt'] = 'Calendar export salt';
$string['calendarsettings'] = 'Calendar';
$string['cannotdeletemissingqtype'] = 'You cannot delete the missing question type. It is needed by the system.';
+$string['cannotdeletemodfilter'] = 'You cannot uninstall the \'$a->filter\' because it is part of the \'$a->module\' module.';
$string['cannotdeleteqtypeinuse'] = 'You cannot delete the question type \'$a\'. There are questions of this type in the question bank.';
$string['cannotdeleteqtypeneeded'] = 'You cannot delete the question type \'$a\'. There are other question types installed that rely on it.';
$string['cfgwwwrootwarning'] = 'You have defined $CFG->wwwroot incorrectly in your config.php file. It does not match the URL you are using to access this page. Please correct it, or you will experience strange bugs like <a href=\'http://tracker.moodle.org/browse/MDL-11061\'>MDL-11061</a>.';
$string['defaultuserroleid'] = 'Default role for all users';
$string['defaultvalues'] = 'Default values';
$string['deleteerrors'] = 'Delete errors';
+$string['deletefilterareyousure'] = 'Are you sure you want to delete the filter \'$a\'';
+$string['deletefilterareyousuremessage'] = 'You are about to completely delete the filter \'$a\'. Are you sure you want to uninstall it?';
+$string['deletefilterfiles'] = 'All data associated with the filter \'$a->filter\' has been deleted from the database. To complete the deletion (and to prevent the filter from re-installing itself), you should now delete this directory from your server: $a->directory';
$string['deleteincompleteusers'] = 'Delete incomplete users after';
$string['deleteqtypeareyousure'] = 'Are you sure you want to delete the question type \'$a\'';
$string['deleteqtypeareyousuremessage'] = 'You are about to completely delete the question type \'$a\'. Are you sure you want to uninstall it?';
$string['deleteunconfirmed'] = 'Delete not fully setup users after';
$string['deleteuser'] = 'Delete user';
+$string['deletingfilter'] = 'Deleting filter \'$a\'';
$string['deletingqtype'] = 'Deleting question type \'$a\'';
$string['density'] = 'Density';
$string['denyemailaddresses'] = 'Denied email domains';
$string['anyfield'] = 'any field';
$string['anyrole'] = 'any role';
$string['anyvalue'] = 'any value';
+$string['applyto'] = 'Apply to';
$string['categoryrole'] = 'Category role';
$string['tablenosave'] = 'Changes in table above are saved automatically.';
+$string['content'] = 'Content';
+$string['contentandheadings'] = 'Content and headings';
$string['contains'] = 'contains';
$string['courserole'] = 'Course role';
$string['courserolelabel'] = '$a->label is $a->rolename in $a->coursename from $a->categoryname';
$string['datelabelisafter'] = '$a->label is after $a->after';
$string['datelabelisbefore'] = '$a->label is before $a->before';
$string['datelabelisbetween'] = '$a->label is between $a->after and $a->before';
+$string['disabled'] = 'Disabled';
$string['doesnotcontain'] = 'doesn\'t contain';
$string['endswith'] = 'ends with';
$string['firstaccess'] = 'First access';
$string['globalrolelabel'] = '$a->label is $a->value';
+$string['isactive'] = 'Active?';
$string['isanyvalue'] = 'is any value';
$string['isafter'] = 'is after';
$string['isbefore'] = 'is before';
$string['isnotequalto'] = 'isn\'t equal to';
$string['isnotdefined'] = 'isn\'t defined';
$string['newfilter'] = 'New filter';
+$string['offbutavailable'] = 'Off, but available';
+$string['on'] = 'On';
$string['profilelabel'] = '$a->label: $a->profile $a->operator $a->value';
$string['profilelabelnovalue'] = '$a->label: $a->profile $a->operator';
$string['removeall'] = 'Remove all filters';
}
public function write_setting($data) {
- // do not write any setting
+ // do not write any settings. Instead all our UI submits to admin/filters.php
+ // which makes and changes, then redirects back.
return '';
}
return false;
}
- public function output_html($data, $query='') {
+ protected function action_url($filterpath, $action) {
global $CFG;
+ return $CFG->wwwroot . '/' . $CFG->admin . '/filters.php?sesskey=' . sesskey() .
+ '&filterpath=' . urlencode($filterpath) . '&action=' . $action;
+ }
- $strname = get_string('name');
- $strhide = get_string('disable');
- $strshow = get_string('enable');
- $strhideshow = "$strhide/$strshow";
- $strsettings = get_string('settings');
- $strup = get_string('up');
- $strdown = get_string('down');
- $strupdown = "$strup/$strdown";
-
- // get a list of possible filters (and translate name if possible)
- // note filters can be in the dedicated filters area OR in their
- // associated modules
- $installedfilters = filter_get_all_installed();
- $filtersettings_new = array();
- foreach ($installedfilters as $path => $strfiltername) {
- $settingspath_new = $CFG->dirroot . '/' . $path . '/filtersettings.php';
- if (is_readable($settingspath_new)) {
- $filtersettings_new[] = $path;
- }
- }
+ protected function action_icon($url, $icon, $straction) {
+ global $CFG;
+ return '<a href="' . $url . '" title="' . $straction . '">' .
+ '<img src="' . $CFG->pixpath . '/t/' . $icon . '.gif" alt="' . $straction . '" /></a> ';
+ }
- // get all the currently selected filters
- if (!empty($CFG->textfilters)) {
- $oldactivefilters = explode(',', $CFG->textfilters);
- $oldactivefilters = array_unique($oldactivefilters);
- } else {
- $oldactivefilters = array();
- }
+ protected function get_table_row($filterinfo, $isfirstrow, $islastactive) {
+ global $CFG;
+ $row = array();
+ $filter = $filterinfo->filter;
- // take this opportunity to clean up filters
- $activefilters = array();
- foreach ($oldactivefilters as $oldactivefilter) {
- if (!empty($oldactivefilter) and array_key_exists($oldactivefilter, $installedfilters)) {
- $activefilters[] = $oldactivefilter;
+ $row[] = $this->filternames[$filter];
+
+ $row[] = popup_form($this->action_url($filter, 'setstate') . '&newstate=', $this->activechoices,
+ 'active' . basename($filter), $filterinfo->active, '', '', '', true, 'self', '', NULL, get_string('save'));
+
+ $updown = '';
+ $spacer = '<img src="' . $CFG->pixpath . '/spacer.gif" class="iconsmall" alt="" /> ';
+ if ($filterinfo->active != TEXTFILTER_DISABLED) {
+ if (!$isfirstrow) {
+ $updown .= $this->action_icon($this->action_url($filter, 'up'), 'up', $this->strup);
+ } else {
+ $updown .= $spacer;
+ }
+ if (!$islastactive) {
+ $updown .= $this->action_icon($this->action_url($filter, 'down'), 'down', $this->strdown);
+ } else {
+ $updown .= $spacer;
}
}
+ $row[] = $updown;
- // Get the list of all filters, and pull the active filters
- // to the top.
- $displayfilters = array();
- foreach ($activefilters as $activefilter) {
- $name = $installedfilters[$activefilter];
- $displayfilters[$activefilter] = $name;
+ $row[] = 'TODO Apply to col';
+
+ // settings link (if defined)
+ $settings = '';
+ if (filter_has_global_settings($filter)) {
+ $settings = '<a href="' . $CFG->wwwroot . '/' . $CFG->admin . '/settings.php?section=filtersetting' .
+ str_replace('/', '',$filter) . '">' . $this->strsettings . '</a>';
}
- foreach ($installedfilters as $key => $filter) {
- if (!array_key_exists($key, $displayfilters)) {
- $displayfilters[$key] = $filter;
- }
+ $row[] = $settings;
+
+ return $row;
+ }
+
+ public function output_html($data, $query='') {
+ global $CFG;
+
+ $this->activechoices = array(
+ TEXTFILTER_DISABLED => get_string('disabled', 'filters'),
+ TEXTFILTER_OFF => get_string('offbutavailable', 'filters'),
+ TEXTFILTER_ON => get_string('on', 'filters'),
+ );
+ $this->applytochoices = array(
+ 1 => get_string('content', 'filters'),
+ 3 => get_string('contentandheadings', 'filters'),
+ );
+ $this->strup = get_string('up');
+ $this->strdown = get_string('down');
+ $this->strsettings = get_string('settings');
+
+ $filters = filter_get_global_states();
+
+ // In case any new filters have been installed, but not put in the table yet.
+ $this->filternames = filter_get_all_installed();
+ $newfilters = $this->filternames;
+ foreach ($filters as $filter => $notused) {
+ unset($newfilters[$filter]);
}
$return = print_heading(get_string('actfilterhdr', 'filters'), '', 3, 'main', true);
$return .= print_box_start('generalbox filtersui', '', true);
$table = new object();
- $table->head = array($strname, $strhideshow, $strupdown, $strsettings);
- $table->align = array('left', 'center', 'center', 'center');
+ $table->head = array(get_string('filter'), get_string('isactive', 'filters'),
+ get_string('order'), get_string('applyto', 'filters'), $this->strsettings);
+ $table->align = array('left', 'left', 'center', 'left', 'left');
$table->width = '90%';
$table->data = array();
- $filtersurl = "$CFG->wwwroot/$CFG->admin/filters.php?sesskey=".sesskey();
- $imgurl = "$CFG->pixpath/t";
-
- // iterate through filters adding to display table
- $updowncount = 1;
- $activefilterscount = count($activefilters);
- foreach ($displayfilters as $path => $name) {
- $upath = urlencode($path);
- // get hide/show link
- if (in_array($path, $activefilters)) {
- $hideshow = "<a href=\"$filtersurl&action=hide&filterpath=$upath\">";
- $hideshow .= "<img src=\"{$CFG->pixpath}/i/hide.gif\" class=\"icon\" alt=\"$strhide\" /></a>";
- $hidden = false;
- $displayname = "<span>$name</span>";
- }
- else {
- $hideshow = "<a href=\"$filtersurl&action=show&filterpath=$upath\">";
- $hideshow .= "<img src=\"{$CFG->pixpath}/i/show.gif\" class=\"icon\" alt=\"$strshow\" /></a>";
- $hidden = true;
- $displayname = "<span class=\"dimmed_text\">$name</span>";
- }
-
- // get up/down link (only if not hidden)
- $updown = '';
- if (!$hidden) {
- if ($updowncount>1) {
- $updown .= "<a href=\"$filtersurl&action=up&filterpath=$upath\">";
- $updown .= "<img src=\"$imgurl/up.gif\" alt=\"$strup\" /></a> ";
- }
- else {
- $updown .= "<img src=\"$CFG->pixpath/spacer.gif\" class=\"icon\" alt=\"\" /> ";
- }
- if ($updowncount<$activefilterscount) {
- $updown .= "<a href=\"$filtersurl&action=down&filterpath=$upath\">";
- $updown .= "<img src=\"$imgurl/down.gif\" alt=\"$strdown\" /></a>";
- }
- else {
- $updown .= "<img src=\"$CFG->pixpath/spacer.gif\" class=\"icon\" alt=\"\" />";
- }
- ++$updowncount;
+ $lastactive = null;
+ foreach ($filters as $filter => $filterinfo) {
+ if ($filterinfo->active != TEXTFILTER_DISABLED) {
+ $lastactive = $filter;
}
+ }
- // settings link (if defined)
- $settings = '';
- if (in_array($path, $filtersettings_new)) {
- $settings = "<a href=\"settings.php?section=filtersetting".str_replace('/', '',$path)."\">$strsettings</a>";
+ // iterate through filters adding to display table
+ $firstrow = true;
+ foreach ($filters as $filter => $filterinfo) {
+ $row = $this->get_table_row($filterinfo, $firstrow, $filter == $lastactive);
+ $table->data[] = $row;
+ if ($filterinfo->active == TEXTFILTER_DISABLED) {
+ $table->rowclass[] = 'dimmed_text';
+ } else {
+ $table->rowclass[] = '';
}
-
- // write data into the table object
- $table->data[] = array($displayname, $hideshow, $updown, $settings);
+ $firstrow = false;
+ }
+ foreach ($newfilters as $filter => $filtername) {
+ $filterinfo = new stdClass;
+ $filterinfo->filter = $filter;
+ $filterinfo->active = TEXTFILTER_DISABLED;
+ $row = $this->get_table_row($filterinfo, $firstrow, $filter == $lastactive);
+ $table->data[] = $row;
+ $table->rowclass[] = 'dimmed_text';
}
+
$return .= print_table($table, true);
$return .= get_string('tablenosave', 'filters');
$return .= print_box_end(true);
return $filters;
}
+/**
+ * This function is for use by the filter administration page.
+ * @return array 'filtername' => object with fields 'filter' (=filtername), 'active' and 'sortorder'
+ */
+function filter_get_global_states() {
+ global $DB;
+ $context = get_context_instance(CONTEXT_SYSTEM);
+ return $DB->get_records('filter_active', array('contextid' => $context->id), 'sortorder', 'filter,active,sortorder');
+}
+
+/**
+ * Delete all the data in the database relating to a filter, prior to deleting it.
+ * @param string $filter The filter name, for example 'filter/tex' or 'mod/glossary'.
+ */
+function filter_delete_all_data($filter) {
+ global $DB;
+ if (substr($filter, 0, 7) == 'filter/') {
+ unset_all_config_for_plugin('filter_' . basename($filter));
+ }
+ $DB->delete_records('filter_active', array('filter' => $filter));
+ $DB->delete_records('filter_config', array('filter' => $filter));
+}
+
+/**
+ * Does this filter have a global settings page in the admin tree?
+ * (The settings page for a filter must be called, for example,
+ * filtersettingfiltertex or filtersettingmodglossay.)
+ *
+ * @param string $filter The filter name, for example 'filter/tex' or 'mod/glossary'.
+ * @return boolean Whether there should be a 'Settings' link on the config page.
+ */
+function filter_has_global_settings($filter) {
+ global $CFG;
+ $settingspath = $CFG->dirroot . '/' . $filter . '/filtersettings.php';
+ return is_readable($settingspath);
+}
+
/**
* Process phrases intelligently found within a HTML text (such as adding links)
*
// Validate.
$this->assert_global_sort_order(array('filter/2', 'filter/1', 'filter/3'));
}
+
+ public function test_filter_get_global_states() {
+ // Setup fixture.
+ filter_set_global_state('filter/1', TEXTFILTER_ON);
+ filter_set_global_state('filter/2', TEXTFILTER_OFF);
+ filter_set_global_state('filter/3', TEXTFILTER_DISABLED);
+ // Exercise SUT.
+ $filters = filter_get_global_states();
+ // Validate.
+ $this->assertEqual(array(
+ 'filter/1' => (object) array('filter' => 'filter/1', 'active' => TEXTFILTER_ON, 'sortorder' => 1),
+ 'filter/2' => (object) array('filter' => 'filter/2', 'active' => TEXTFILTER_OFF, 'sortorder' => 2),
+ 'filter/3' => (object) array('filter' => 'filter/3', 'active' => TEXTFILTER_DISABLED, 'sortorder' => 3)
+ ), $filters);
+ }
}
/**
}
}
+class filter_delete_all_data_test extends UnitTestCaseUsingDatabase {
+ private $syscontext;
+ private $childcontext;
+ private $childcontext2;
+
+ public function setUp() {
+ // Create the table we need and switch to test DB.
+ $this->create_test_tables(array('filter_active', 'filter_config', 'config', 'config_plugins'), 'lib');
+ $this->switch_to_test_db();
+ }
+
+ public function test_filter_delete_all_data_filter() {
+ $syscontext = get_context_instance(CONTEXT_SYSTEM);
+ filter_set_global_state('filter/name', TEXTFILTER_ON);
+ filter_set_global_state('filter/other', TEXTFILTER_ON);
+ filter_set_local_config('filter/name', $syscontext->id, 'settingname', 'A value');
+ filter_set_local_config('filter/other', $syscontext->id, 'settingname', 'Other value');
+ set_config('configname', 'A config value', 'filter_name');
+ set_config('configname', 'Other config value', 'filter_other');
+ filter_delete_all_data('filter/name');
+ $this->assertEqual(1, $this->testdb->count_records('filter_active'));
+ $this->assertTrue($this->testdb->record_exists('filter_active', array('filter' => 'filter/other')));
+ $this->assertEqual(1, $this->testdb->count_records('filter_config'));
+ $this->assertTrue($this->testdb->record_exists('filter_config', array('filter' => 'filter/other')));
+ $expectedconfig = new stdClass;
+ $expectedconfig->configname = 'Other config value';
+ $this->assertEqual($expectedconfig, get_config('filter_other'));
+ $this->assertFalse(get_config('filter_name'));
+ }
+}
?>