From bfe1e789de206b4cf4dea6bacf5f79a13e0fd403 Mon Sep 17 00:00:00 2001 From: nicolasconnault Date: Tue, 3 Apr 2007 03:32:46 +0000 Subject: [PATCH] MDL-8774: Also an effort to refactorise the poorly designed mod/data/Preset code. --- files/index.php | 2 +- lang/en_utf8/data.php | 9 +- lang/en_utf8/error.php | 1 + mod/data/preset_class.php | 812 +++++++++++++++++++++++++++++ mod/data/preset_new.php | 172 ++++++ mod/data/simpletest/testpreset.php | 65 +++ theme/standard/styles_layout.css | 6 + 7 files changed, 1065 insertions(+), 2 deletions(-) create mode 100644 mod/data/preset_class.php create mode 100755 mod/data/preset_new.php create mode 100644 mod/data/simpletest/testpreset.php diff --git a/files/index.php b/files/index.php index bf0845caab..6b953d1d7b 100644 --- a/files/index.php +++ b/files/index.php @@ -105,7 +105,7 @@ ', '»', "$course->shortname -> $fullnav"); + $fullnav = str_replace('->', '»', format_string($course->shortname) . " -> $fullnav"); echo ''; if ($course->id == SITEID and $wdir != "/backupdata") { diff --git a/lang/en_utf8/data.php b/lang/en_utf8/data.php index bad779e32c..4696f6ad2a 100644 --- a/lang/en_utf8/data.php +++ b/lang/en_utf8/data.php @@ -63,6 +63,7 @@ $string['deleted'] = 'deleted'; $string['deletefield'] = 'Delete an existing field'; $string['deletewarning'] = 'Are you sure you want to delete this preset?'; $string['descending'] = 'Descending'; +$string['directorynotapreset'] = '$a->directory Not a preset: missing files: $a->missing_files'; $string['download'] = 'Download'; $string['edit'] = 'Edit'; $string['editcomment'] = 'Edit comment'; @@ -79,6 +80,7 @@ $string['example'] = 'Database module example'; $string['export'] = 'Export'; $string['exportaszip'] = 'Export as zip'; $string['exportedtozip'] = 'Exported to temporary zip...'; +$string['failedpresetdelete'] = 'Error deleting a preset!'; $string['fieldadded'] = 'Field added'; $string['fieldallowautolink'] = 'Allow autolink'; $string['fielddeleted'] = 'Field deleted'; @@ -98,6 +100,7 @@ $string['fieldwidth'] = 'Width'; $string['fieldwidthlistview'] = 'Width in list view'; $string['fieldwidthsingleview'] = 'Width in single view'; $string['file'] = 'File'; +$string['filesnotgenerated'] = 'Not all files were generated: $a'; $string['filtername'] = 'Database Auto-linking'; $string['footer'] = 'Footer'; $string['forcelinkname'] = 'Forced name for the link'; @@ -134,6 +137,7 @@ $string['modulename'] = 'Database'; $string['modulenameplural'] = 'Databases'; $string['more'] = 'More'; $string['moreurl'] = 'More URL'; +$string['movezipfailed'] = 'Can\'t move zip'; $string['multientry'] = 'Repeated entry'; $string['multimenu'] = 'Menu (Multi-select)'; $string['multipletags'] = 'Multiple tags found! Template not saved'; @@ -152,12 +156,14 @@ $string['nameurl'] = 'URL field'; $string['newentry'] = 'New entry'; $string['newfield'] = 'Create a new field'; $string['noaccess'] = 'You do not have access to this page'; +$string['nodefinedfields'] = 'New preset has no defined fields!'; $string['nofieldindatabase'] = 'There are no fields defined for this database.'; $string['nolisttemplate'] = 'List template is not yet defined'; $string['nomatch'] = 'No matching entries found!'; $string['nomaximum'] = 'No maximum'; $string['norecords'] = 'No entries in database'; $string['nosingletemplate'] = 'Single template is not yet defined'; +$string['notinjectivemap'] = 'Not an injective map'; $string['number'] = 'Number'; $string['numberrssarticles'] = 'RSS articles'; $string['numnotapproved'] = 'Pending'; @@ -215,6 +221,7 @@ $string['text'] = 'Text'; $string['textarea'] = 'Textarea'; $string['todatabase'] = 'to this database.'; $string['type'] = 'Field type'; +$string['undefinedprocessactionmethod'] = 'No action method defined in Data_Preset to handle action \"$a\".'; $string['updatefield'] = 'Update an existing field'; $string['uploadfile'] = 'Upload file'; $string['uploadrecords'] = 'Upload entries from a file'; @@ -222,5 +229,5 @@ $string['url'] = 'Url'; $string['usestandard'] = 'Use a preset'; $string['viewfromdate'] = 'Viewable from'; $string['viewtodate'] = 'Viewable to'; - +$string['wrongdataid'] = 'Wrong data id provided'; ?> diff --git a/lang/en_utf8/error.php b/lang/en_utf8/error.php index 6451b55f22..3e11952a76 100644 --- a/lang/en_utf8/error.php +++ b/lang/en_utf8/error.php @@ -37,6 +37,7 @@ $string['invalidcourse'] = 'Invalid course'; $string['invalidfieldname'] = '\"$a\" is not a valid field name'; $string['invalidfiletype'] = '\"$a\" is not a valid file type'; $string['invalidmd5'] = 'Invalid md5'; +$string['invalidrequest'] = 'Invalid request'; $string['invalidrole'] = 'Invalid role'; $string['invalidxmlfile'] = '\"$a\" is not a valid XML file'; $string['loginasonecourse'] = 'You can not enter this course.
You have to terminate the \"Login as\" session before entering any other course.'; diff --git a/mod/data/preset_class.php b/mod/data/preset_class.php new file mode 100644 index 0000000000..5d8884f378 --- /dev/null +++ b/mod/data/preset_class.php @@ -0,0 +1,812 @@ +shortname = $shortname; + $this->user_id = $user_id; + + if (empty($directory)) { + $this->directory = $this->get_path(); + } else { + $this->directory = $directory; + } + + if (!empty($data_id)) { + if (!$this->data = get_record('data', 'id', $data_id)) { + print_error('wrongdataid','data'); + } else { + $this->listtemplate = $this->data->listtemplate; + $this->singletemplate = $this->data->singletemplate; + $this->listtemplateheader = $this->data->listtemplateheader; + $this->listtemplatefooter = $this->data->listtemplatefooter; + $this->addtemplate = $this->data->addtemplate; + $this->rsstemplate = $this->data->rsstemplate; + $this->csstemplate = $this->data->csstemplate; + $this->jstemplate = $this->data->jstemplate; + } + } + } + + /* + * Returns the best name to show for a preset + * If the shortname has spaces in it, replace them with underscores. + * Convert the name to lower case. + */ + function best_name($shortname = null) { + if (empty($shortname)) { + $shortname = $this->shortname; + } + + /// We are looking inside the preset itself as a first choice, but also in normal data directory + $string = get_string('presetname'.$shortname, 'data', NULL, $this->directory.'/lang/'); + + if (substr($string, 0, 1) == '[') { + return strtolower(str_replace(' ', '_', $shortname)); + } else { + return $string; + } + } + + /** + * TODO figure out what's going on here with the user id. This method doesn't look quite right to me. + */ + function get_path() { + global $USER, $CFG, $COURSE; + + $context = get_context_instance(CONTEXT_COURSE, $COURSE->id); + + if ($this->user_id > 0 && ($this->user_id == $USER->id || has_capability('mod/data:viewalluserpresets', $context))) { + return $CFG->dataroot.'/data/preset/'.$this->user_id.'/'.$this->shortname; + } else if ($this->user_id == 0) { + return $CFG->dirroot.'/mod/data/preset/'.$this->shortname; + } else if ($this->user_id < 0) { + return $CFG->dataroot.'/temp/data/'.-$this->user_id.'/'.$this->shortname; + } + + return 'Does it disturb you that this code will never run?'; + } + + + /** + * A preset is a directory with a number of required files. + * This function verifies that the given directory contains + * all these files, thus validating as a preset directory. + * + * @param string $directory An optional directory to check. Will use this Preset's directory if not provided. + * @return mixed True if the directory contains all the files required to qualify as Preset object; + * an array of the missing filename is returned otherwise + */ + function has_all_required_files($directory = null) + { + if (empty($directory)) { + $directory = $this->directory; + } else { + $directory = rtrim($directory, '/\\') . '/'; + } + + $missing_files = array(); + + foreach ($this->required_files as $file) { + if(!file_exists($directory . '/' . $file)) { + $missing_files[] = $file; + } + } + + if (!empty($missing_files)) { + return $missing_files; + } + + return true; + } + + /** + * Deletes all the files in the directory mapped by this Preset object. + * + * @return boolean False if an error occured while trying to delete one of the files, true otherwise. + */ + function clean_files() + { + foreach ($this->required_files as $file) { + if (!unlink($this->directory . '/' . $file)) { + return $file; + } + } + + return true; + } + + function get_template_files() + { + $template_files = array(); + + foreach ($this->required_files as $file) { + if (preg_match('/^([a-z]+template[a-z]?)\.[a-z]{2,4}$/', $file, $matches)) { + $template_files[$matches[1]] = $file; + } + } + + return $template_files; + } + + /** + * Exports this Preset object as a series of files in the Preset's directory. + * @return string The path/name of the resulting zip file if successful. + */ + function export() { + global $CFG; + $this->directory = $CFG->dataroot.'/temp'; + // write all templates, but not the xml yet + + $template_files = $this->get_template_files(); + foreach ($template_files as $var => $file) { + $handle = fopen($this->directory . '/' . $file, 'w'); + fwrite($handle, $this->$var); + fclose($handle); + } + + /* All the display data is now done. Now assemble preset.xml */ + $fields = get_records('data_fields', 'dataid', $this->data->id); + $presetfile = fopen($this->directory.'/preset.xml', 'w'); + $presetxml = "\n\n"; + + /* Database settings first. Name not included? */ + $settingssaved = array('intro', + 'comments', + 'requiredentries', + 'requiredentriestoview', + 'maxentries', + 'rssarticles', + 'approval', + 'scale', + 'assessed', + 'defaultsort', + 'defaultsortdir', + 'editany'); + + $presetxml .= "\n"; + foreach ($settingssaved as $setting) { + $presetxml .= "<$setting>{$this->data->$setting}\n"; + } + $presetxml .= "\n\n"; + + /* Now for the fields. Grabs all settings that are non-empty */ + if (!empty($fields)) { + foreach ($fields as $field) { + $presetxml .= "\n"; + foreach ($field as $key => $value) { + if ($value != '' && $key != 'id' && $key != 'dataid') { + $presetxml .= "<$key>$value\n"; + } + } + $presetxml .= "\n\n"; + } + } + + $presetxml .= ""; + fwrite($presetfile, $presetxml); + fclose($presetfile); + + /* Check all is well */ + if (is_array($missing_files = $this->has_all_required_files())) { + $missing_files = implode(', ', $missing_files); + print_error('filesnotgenerated', 'data', null, $missing_files); + } + + // Remove export.zip + @unlink($this->directory.'/export.zip'); + + $filelist = array(); + foreach ($this->required_files as $file) { + $filelist[$file] = $this->directory . '/' . $file; + } + + // zip_files is part of moodlelib + $status = zip_files($filelist, $this->directory.'/export.zip'); + + /* made the zip... now return the filename for storage.*/ + return $this->directory.'/export.zip'; + } + + + /** + * Loads the contents of the preset folder to initialise this Preset object. + * TODO document + */ + function load_from_file($directory = null) { + global $CFG; + if (empty($directory) && empty($this->directory)) { + $this->directory = $this->get_path(); + } + + if (is_array($missing_files = $this->has_all_required_files())) { + $a = new StdClass(); + $a->missing_files = implode(', ', $missing_files); + $a->directory = $this->directory; + print_error('directorynotapreset','data', null, $a); + } + + /* Grab XML */ + $presetxml = file_get_contents($this->directory.'/preset.xml'); + $parsedxml = xmlize($presetxml); + + /* First, do settings. Put in user friendly array. */ + $settingsarray = $parsedxml['preset']['#']['settings'][0]['#']; + $settings = new StdClass(); + + foreach ($settingsarray as $setting => $value) { + $settings->$setting = $value[0]['#']; + } + + /* Now work out fields to user friendly array */ + $fieldsarray = $parsedxml['preset']['#']['field']; + $fields = array(); + foreach ($fieldsarray as $field) { + $f = new StdClass(); + foreach ($field['#'] as $param => $value) { + $f->$param = $value[0]['#']; + } + $f->dataid = $this->data->id; + $f->type = clean_param($f->type, PARAM_ALPHA); + $fields[] = $f; + } + + + /* Now add the HTML templates to the settings array so we can update d */ + $template_files = $this->get_template_files(); + + foreach ($template_files as $var => $file) { + $settings->$var = file_get_contents($this->directory . '/' . $file); + } + + $settings->instance = $this->data->id; + + /* Now we look at the current structure (if any) to work out whether we need to clear db + or save the data */ + $currentfields = array(); + $currentfields = get_records('data_fields', 'dataid', $this->data->id); + $currentfields = array_merge($currentfields); + return array($settings, $fields, $currentfields); + } + + + /** + * Import options + * TODO document + * TODO replace all output by a return value + */ + function get_import_html() { + if (!confirm_sesskey()) { + print_error("confirmsesskeybad"); + } + + $strblank = get_string('blank', 'data'); + $strnofields = get_string('nofields', 'data'); + $strcontinue = get_string('continue'); + $strwarning = get_string('mappingwarning', 'data'); + $strfieldmappings = get_string('fieldmappings', 'data'); + $strnew = get_string('new'); + $strold = get_string('old'); + + $sesskey = sesskey(); + + list($settings, $newfields, $currentfields) = $this->load_from_file(); + + $html = ''; + + $html .= '
'; + $html .= '
'; + $html .= ''; + $html .= ''; + $html .= ''; + $html .= ''; + + if (!empty($currentfields) && !empty($newfields)) { + $html .= "

$strfieldmappings "; + helpbutton('fieldmappings', '', 'data'); + $html .= '

'; + + foreach ($newfields as $nid => $newfield) { + $html .= ""; + $html .= ''; + } + $html .= '
'; + $html .= "

$strwarning

"; + } + else if (empty($newfields)) { + print_error('nodefinedfields', 'data'); + } + $html .= '
'; + return $html; + } + + + /** + * import() + * TODO document + */ + function import() { + global $CFG; + + list($settings, $newfields, $currentfields) = $this->load_from_file(); + $preservedfields = array(); + + /* Maps fields and makes new ones */ + if (!empty($newfields)) { + /* We require an injective mapping, and need to know what to protect */ + foreach ($newfields as $nid => $newfield) { + $cid = optional_param("field_$nid", -1, PARAM_INT); + if ($cid == -1) continue; + + if (array_key_exists($cid, $preservedfields)) { + print_error('notinjectivemap', 'data'); + } else { + $preservedfields[$cid] = true; + } + } + + foreach ($newfields as $nid => $newfield) { + $cid = optional_param("field_$nid", -1, PARAM_INT); + /* A mapping. Just need to change field params. Data kept. */ + if ($cid != -1 and isset($currentfelds[$cid])) { + $fieldobject = data_get_field_from_id($currentfields[$cid]->id, $this->data); + foreach ($newfield as $param => $value) { + if ($param != "id") { + $fieldobject->field->$param = $value; + } + } + unset($fieldobject->field->similarfield); + $fieldobject->update_field(); + unset($fieldobject); + } + /* Make a new field */ + else { + include_once("field/$newfield->type/field.class.php"); + + if (!isset($newfield->description)) { + $newfield->description = ''; + } + $classname = 'data_field_'.$newfield->type; + $fieldclass = new $classname($newfield, $this->data); + $fieldclass->insert_field(); + unset($fieldclass); + } + } + } + + /* Get rid of all old unused data */ + if (!empty($preservedfields)) { + foreach ($currentfields as $cid => $currentfield) { + if (!array_key_exists($cid, $preservedfields)) { + /* Data not used anymore so wipe! */ + print "Deleting field $currentfield->name
"; + $id = $currentfield->id; + // Why delete existing data records and related comments/ratings ?? + /* + if ($content = get_records('data_content', 'fieldid', $id)) { + foreach ($content as $item) { + delete_records('data_ratings', 'recordid', $item->recordid); + delete_records('data_comments', 'recordid', $item->recordid); + delete_records('data_records', 'id', $item->recordid); + } + } + */ + delete_records('data_content', 'fieldid', $id); + delete_records('data_fields', 'id', $id); + } + } + } + + data_update_instance(addslashes_object($settings)); + + if (strstr($this->directory, '/temp/')) clean_preset($this->directory); /* Removes the temporary files */ + return true; + } + + /** + * Runs the Preset action method that matches the given action string. + * @param string $action + * @return string html + */ + function process_action($action, $params) + { + echo $action; + if (in_array("action_$action", get_class_methods(get_class($this)))) { + return $this->{"action_$action"}($params); + } else { + print_error('undefinedprocessactionmethod', 'data', null, $action); + } + } + +//////////////////// +// ACTION METHODS // +//////////////////// + + function action_base($params) + { + return null; + } + + function action_confirmdelete($params) + { + global $CFG, $USER; + $html = ''; + $course = $params['course']; + $shortname = $params['shortname']; + + if (!confirm_sesskey()) { // GET request ok here + print_error('confirmsesskeybad'); + } + + $this->user_id = $params['userid']; + + if ($this->user_id > 0 and ($this->user_id == $USER->id || has_capability('mod/data:manageuserpresets', $context))) { + //ok can delete + } else { + print_error('invalidrequest'); + } + + $path = $this->get_path(); + + $strwarning = get_string('deletewarning', 'data').'
'. + data_preset_name($shortname, $path); + + $options = new object(); + $options->fullname = $this->user_id.'/'.$shortname; + $options->action = 'delete'; + $options->d = $this->data->id; + $options->sesskey = sesskey(); + + $optionsno = new object(); + $optionsno->d = $this->data->id; + notice_yesno($strwarning, 'preset.php', 'preset.php', $options, $optionsno, 'post', 'get'); + $html .= print_footer($course, null, true); + echo $html; + exit(); + } + + function action_delete($params) + { + global $CFG, $USER; + $shortname = $params['shortname']; + + if (!data_submitted() and !confirm_sesskey()) { + print_error('invalidrequest'); + } + + if ($this->user_id > 0 and ($this->user_id == $USER->id || has_capability('mod/data:manageuserpresets', $context))) { + //ok can delete + } else { + print_error('invalidrequest'); + } + + $this->shortname = $this->best_name($shortname); + + $this->path = $this->get_path(); + $this->directory = $this->path; + + if (!$this->clean_files()) { + print_error('failedpresetdelete', 'data'); + } + rmdir($this->path); + + $strdeleted = get_string('deleted', 'data'); + notify("$shortname $strdeleted", 'notifysuccess'); + } + + function action_importpreset($params) + { + $course = $params['course']; + if (!data_submitted() or !confirm_sesskey()) { + print_error('invalidrequest'); + } + + $this->shortname = $params['shortname']; + $this->data = $params['data']; + $this->user_id = $params['userid']; + $html = ''; + $html .= $this->get_import_html(); + + $html .= print_footer($course, null, true); + echo $html; + exit(); + } + + function action_importzip($params) + { + global $CFG, $USER; + $course = $params['course']; + if (!data_submitted() or !confirm_sesskey()) { + print_error('invalid_request'); + } + + if (!make_upload_directory('temp/data/'.$USER->id)) { + print_error('errorcreatingdirectory', null, null, 'temp/data/' . $USER->id); + } + + $this->file = $CFG->dataroot.'/temp/data/'.$USER->id; + $this->directory = $this->file; + $this->user_id = $USER->id; + $this->clean_files($this->file); + + if (!unzip_file($CFG->dataroot."/$USER->id/$file", $this->file, false)) { + } + + $html .= $this->get_import_html(); + $html .= print_footer($course, null, true); + echo $html; + exit(); + } + + function action_finishimport($params) + { + if (!data_submitted() or !confirm_sesskey()) { + print_error('invalidrequest'); + } + $this->shortname = $this->best_name($this->data->name); + $this->directory = $this->get_path(); + $this->import(); + + $strimportsuccess = get_string('importsuccess', 'data'); + $straddentries = get_string('addentries', 'data'); + $strtodatabase = get_string('todatabase', 'data'); + if (!get_records('data_records', 'dataid', $this->data->id)) { + notify('$strimportsuccess $straddentries $strtodatabase", 'notifysuccess'); + } else { + notify("$strimportsuccess", 'notifysuccess'); + } + } + + function action_export($params) + { + global $CFG, $USER; + $course = $params['course']; + $html = ''; + + if (!data_submitted() or !confirm_sesskey()) { + print_error('invalid_request'); + } + + $this->shortname = $params['shortname']; + $this->data = $params['data']; + + $html .= '
'; + $file = $this->export(); + $html .= get_string('exportedtozip', 'data')."
"; + $permanentfile = $CFG->dataroot.'/' . $course->id . '/moddata/data/' . $this->data->id . '/preset.zip'; + @unlink($permanentfile); + /* is this created elsewhere? sometimes its not present... */ + make_upload_directory($course->id . '/moddata/data/' . $this->data->id); + + /* now just move the zip into this folder to allow a nice download */ + if (!rename($file, $permanentfile)) { + print_error('movezipfailed', 'data'); + } + + $html .= ''.get_string('download', 'data').""; + $html .= '
'; + return $html; + } + + /** + * First stage of saving a Preset: ask for a name + */ + function action_save1($params) + { + $html = ''; + $sesskey = $params['sesskey']; + $course = $params['course']; + if (!data_submitted() or !confirm_sesskey()) { + print_error('invalid_request'); + } + + $strcontinue = get_string('continue'); + $strwarning = get_string('presetinfo', 'data'); + $strname = get_string('shortname'); + + $html .= '
'; + $html .= '

'.$strwarning.'

'; + $html .= '
'; + $html .= '
'; + $html .= ' '; + $html .= ''; + $html .= ''; + $html .= ''; + $html .= '
'; + $html .= print_footer($course, null, true); + echo $html; + exit(); + } + + /** + * Second stage of saving a preset: If the given name already exists, + * suggest to use a different name or offer to overwrite the existing preset. + */ + function action_save2($params) + { + $course = $params['course']; + $this->data = $params['data']; + + global $CFG, $USER; + if (!data_submitted() or !confirm_sesskey()) { + print_error('invalid_request'); + } + + $strcontinue = get_string('continue'); + $stroverwrite = get_string('overwrite', 'data'); + $strname = get_string('shortname'); + + $name = $this->best_name(optional_param('name', $this->data->name, PARAM_FILE)); + $this->shortname = $name; + + if (!is_array($this->has_all_required_files("$CFG->dataroot/data/preset/$USER->id/$name"))) { + notify("Preset already exists: Pick another name or overwrite ($CFG->dataroot/data/preset/$USER->id/$name)"); + + $html .= '
'; + $html .= '
'; + $html .= '
'; + $html .= ' '; + $html .= ''; + $html .= ''; + $html .= ''; + $html .= '
'; + + $html .= '
'; + $html .= '
'; + $html .= ''; + $html .= ''; + $html .= ''; + $html .= ''; + $html .= '
'; + $html .= '
'; + $html .= print_footer($course, null, true); + echo $html; + exit(); + } + } + + /** + * Third stage of saving a preset, overwrites an existing preset with the new one. + */ + function action_save3($params) + { + global $CFG, $USER; + if (!data_submitted() or !confirm_sesskey()) { + print_error('invalidrequest'); + } + + $name = $this->best_name(optional_param('name', $this->data->name, PARAM_FILE)); + $this->directory = "/data/preset/$USER->id/$name"; + $this->shortname = $name; + $this->user_id = $USER->id; + + make_upload_directory($this->directory); + $this->clean_files($CFG->dataroot.$this->directory); + + $file = $this->export(); + if (!unzip_file($file, $CFG->dataroot.$this->directory, false)) { + print_error('cannotunzipfile'); + } + notify(get_string('savesuccess', 'data'), 'notifysuccess'); + } +} + +?> diff --git a/mod/data/preset_new.php b/mod/data/preset_new.php new file mode 100755 index 0000000000..c482eda5db --- /dev/null +++ b/mod/data/preset_new.php @@ -0,0 +1,172 @@ +libdir.'/uploadlib.php'); +require_once($CFG->libdir.'/xmlize.php'); +require_once('preset_class.php'); + +$id = optional_param('id', 0, PARAM_INT); // course module id +$d = optional_param('d', 0, PARAM_INT); // database activity id +$action = optional_param('action', 'base', PARAM_ALPHANUM); // current action +$fullname = optional_param('fullname', '', PARAM_PATH); // directory the preset is in +$file = optional_param('file', '', PARAM_FILE); // uploaded file + +// find out preset owner userid and shortname +$parts = explode('/', $fullname); +$userid = empty($parts[0]) ? 0 : (int)$parts[0]; +$shortname = empty($parts[1]) ? '' : $parts[1]; +unset($parts); +unset($fullname); + +if ($id) { + if (! $cm = get_coursemodule_from_id('data', $id)) { + error('Course Module ID was incorrect'); + } + if (! $course = get_record('course', 'id', $cm->course)) { + error('Course is misconfigured'); + } + if (! $data = get_record('data', 'id', $cm->instance)) { + error('Module Incorrect'); + } +} else if ($d) { + if (! $data = get_record('data', 'id', $d)) { + error('Database ID Incorrect'); + } + if (! $course = get_record('course', 'id', $data->course)) { + error('Course is misconfigured'); + } + if (! $cm = get_coursemodule_from_instance('data', $data->id, $course->id)) { + error('Course Module ID was incorrect'); + } +} else { + error('Parameter missing'); +} + +if (!$context = get_context_instance(CONTEXT_MODULE, $cm->id)) { + error('Could not find context'); +} + +require_login($course->id, false, $cm); + +require_capability('mod/data:managetemplates', $context); + +if ($userid && ($userid != $USER->id) && !has_capability('mod/data:viewalluserpresets', $context)) { + error('You are not allowed to access presets from other users'); +} + +/* Need sesskey security check here for import instruction */ +$sesskey = sesskey(); + +/********************************************************************/ +/* Output */ +data_print_header($course, $cm, $data, 'presets'); + +$preset = new Data_Preset($shortname, $data->id, null, $userid); +echo $preset->process_action($action, compact('shortname', 'fullname', 'data', 'userid', 'file', 'course', 'sesskey')); + +$presets = data_get_available_presets($context); + +$strimport = get_string('import'); +$strfromfile = get_string('fromfile', 'data'); +$strchooseorupload = get_string('chooseorupload', 'data'); +$strusestandard = get_string('usestandard', 'data'); +$strchoose = get_string('choose'); +$strexport = get_string('export', 'data'); +$strexportaszip = get_string('exportaszip', 'data'); +$strsaveaspreset = get_string('saveaspreset', 'data'); +$strsave = get_string('save', 'data'); +$strdelete = get_string('delete'); + +echo '
'; +echo ''; +echo ''; + +echo ''; + +echo ''; + + +echo ''; + +echo ''; + + +echo ''; +echo '

'.$strexport.'

'; +helpbutton('exportzip', '', 'data'); +echo ''; +$options = new object(); +$options->action = 'export'; +$options->d = $data->id; +$options->sesskey = sesskey(); +print_single_button('preset.php', $options, $strexport, 'post'); +echo '
'; +helpbutton('savepreset', '', 'data'); +echo ''; +$options = new object(); +$options->action = 'save1'; +$options->d = $data->id; +$options->sesskey = sesskey(); +print_single_button('preset.php', $options, $strsave, 'post'); +echo '

'.$strimport.'

'; +helpbutton('importfromfile', '', 'data'); +echo ''; + +echo '
'; +echo '
'; +echo ''; +echo ''; +echo ''; +echo ''; +echo ''; +echo '
'; +echo '
'; +helpbutton('usepreset', '', 'data'); +echo ''; + +echo '
'; +echo '
'; +echo ''; +echo ''; +echo ''; + +$i = 0; +foreach ($presets as $id => $preset) { + $screenshot = ''; + if (!empty($preset->user_id)) { + $user = get_record('user', 'id', $preset->user_id); + $desc = $preset->name.' ('.fullname($user, true).')'; + } else { + $desc = $preset->name; + } + + if (!empty($preset->screenshot)) { + $screenshot = ''.get_string('screenshot').' '.$desc.' '; + } + + $fullname = $preset->user_id.'/'.$preset->shortname; + + $dellink = ''; + if ($preset->user_id > 0 and ($preset->user_id == $USER->id || has_capability('mod/data:manageuserpresets', $context))) { + $dellink = ' '. + ''.$strdelete.' '.$desc.''; + } + + echo ''.$dellink.'
'; +} +echo '
'; +echo ''; +echo '
'; +echo '
'; +echo '
'; + +print_footer($course); + + +?> diff --git a/mod/data/simpletest/testpreset.php b/mod/data/simpletest/testpreset.php new file mode 100644 index 0000000000..c1a471fd24 --- /dev/null +++ b/mod/data/simpletest/testpreset.php @@ -0,0 +1,65 @@ +libdir . '/simpletestlib.php'); +require_once('../preset_class.php'); + +class data_preset_test extends UnitTestCase { + + function setUp() { + } + + function tearDown() { + } + + function test_address_in_subnet() { + } + + /** + * Modifies $_SERVER['HTTP_USER_AGENT'] manually to check if check_browser_version + * works as expected. + */ + function test_check_browser_version() + { + } + + function test_optional_param() + { + } +} + +?> diff --git a/theme/standard/styles_layout.css b/theme/standard/styles_layout.css index 728ae2110a..d2b8570dbf 100644 --- a/theme/standard/styles_layout.css +++ b/theme/standard/styles_layout.css @@ -2677,6 +2677,12 @@ body#user-index .rolesform { .datapreferences { text-align:center; } + +table.presets { + margin-left: auto; + margin-right: auto; +} + /*** *** Modules: Forum ***/ -- 2.39.5