MDL-10985 import from remote xml file with key login option
authorskodak <skodak>
Wed, 26 Sep 2007 09:42:28 +0000 (09:42 +0000)
committerskodak <skodak>
Wed, 26 Sep 2007 09:42:28 +0000 (09:42 +0000)
grade/import/key.php [new file with mode: 0644]
grade/import/key_form.php [new file with mode: 0644]
grade/import/keymanager.php [new file with mode: 0644]
grade/import/lib.php
grade/import/xmlurl/db/access.php [new file with mode: 0644]
grade/import/xmlurl/fetch.php [new file with mode: 0644]
grade/import/xmlurl/grade_import_form.php [new file with mode: 0644]
grade/import/xmlurl/import.php [new file with mode: 0644]
grade/import/xmlurl/index.php [new file with mode: 0755]
grade/import/xmlurl/version.php [new file with mode: 0644]
lang/en_utf8/gradeimport_xmlurl.php [new file with mode: 0644]

diff --git a/grade/import/key.php b/grade/import/key.php
new file mode 100644 (file)
index 0000000..9d31d9e
--- /dev/null
@@ -0,0 +1,104 @@
+<?php  //$Id$
+
+require_once('../../config.php');
+require_once('key_form.php');
+
+/// get url variables
+$courseid = optional_param('courseid', 0, PARAM_INT);
+$id       = optional_param('id', 0, PARAM_INT);
+$delete   = optional_param('delete', 0, PARAM_BOOL);
+$confirm  = optional_param('confirm', 0, PARAM_BOOL);
+
+if ($id) {
+    if (!$key = get_record('user_private_key', 'id', $id)) {
+        error('Group ID was incorrect');
+    }
+    if (empty($courseid)) {
+        $courseid = $key->instance;
+
+    } else if ($courseid != $key->instance) {
+        error('Course ID was incorrect');
+    }
+
+    if (!$course = get_record('course', 'id', $courseid)) {
+        error('Course ID was incorrect');
+    }
+
+} else {
+    if (!$course = get_record('course', 'id', $courseid)) {
+        error('Course ID was incorrect');
+    }
+    $key = new object();
+}
+
+$key->courseid = $course->id;
+
+require_login($course);
+$context = get_context_instance(CONTEXT_COURSE, $course->id);
+require_capability('moodle/grade:import', $context);
+
+// extra security check
+if (!empty($key->userid) and $USER->id != $key->userid) {
+    error('You are not owner of this key');
+}
+
+$returnurl = $CFG->wwwroot.'/grade/import/keymanager.php?id='.$course->id;
+
+if ($id and $delete) {
+    if (!$confirm) {
+        print_header(get_string('deleteselectedkey'), get_string('deleteselectedkey'));
+        $optionsyes = array('id'=>$id, 'delete'=>1, 'courseid'=>$courseid, 'sesskey'=>sesskey(), 'confirm'=>1);
+        $optionsno  = array('id'=>$courseid);
+        notice_yesno(get_string('deletekeyconfirm', 'userkey', $key->value), 'key.php', 'keymanager.php', $optionsyes, $optionsno, 'get', 'get');
+        print_footer();
+        die;
+
+    } else if (confirm_sesskey()){
+        delete_records('user_private_key', 'id', $id);
+        redirect('keymanager.php?id='.$course->id);
+    }
+}
+
+/// First create the form
+$editform = new key_form();
+$editform->set_data($key);
+
+if ($editform->is_cancelled()) {
+    redirect($returnurl);
+
+} elseif ($data = $editform->get_data()) {
+
+    if ($data->id) {
+        $record = new object();
+        $record->id            = $data->id;
+        $record->iprestriction = $data->iprestriction;
+        $record->validuntil    = $data->validuntil;
+        update_record('user_private_key', $record);
+    } else {
+        create_user_key('grade/import', $USER->id, $course->id, $data->iprestriction, $data->validuntil);
+    }
+
+    redirect($returnurl);
+}
+
+$strkeys   = get_string('userkeys', 'userkey');
+$strgrades = get_string('grades');
+
+if ($id) {
+    $strheading = get_string('edituserkey', 'userkey');
+} else {
+    $strheading = get_string('createuserkey', 'userkey');
+}
+
+
+$navlinks = array(array('name'=>$strgrades, 'link'=>$CFG->wwwroot.'/grade/index.php?id='.$courseid, 'type'=>'misc'),
+                  array('name'=>$strkeys, 'link'=>$CFG->wwwroot.'/grade/import/keymanager.php?id='.$courseid, 'type'=>'misc'),
+                  array('name'=>$strheading, 'link'=>'', 'type'=>'misc'));
+$navigation = build_navigation($navlinks);
+
+/// Print header
+print_header_simple($strkeys, ': '.$strkeys, $navigation, '', '', true, '', navmenu($course));
+
+$editform->display();
+print_footer($course);
+?>
diff --git a/grade/import/key_form.php b/grade/import/key_form.php
new file mode 100644 (file)
index 0000000..ff0a6de
--- /dev/null
@@ -0,0 +1,31 @@
+<?php //$Id$
+
+require_once($CFG->dirroot.'/lib/formslib.php');
+
+class key_form extends moodleform {
+
+    // Define the form
+    function definition () {
+        global $USER, $CFG, $COURSE;
+
+        $mform =& $this->_form;
+
+        $mform->addElement('static', 'value', get_string('keyvalue', 'userkey'));
+        $mform->addElement('text', 'iprestriction', get_string('keyiprestriction', 'userkey'), array('size'=>80));
+        $mform->addElement('date_time_selector', 'validuntil', get_string('keyvaliduntil', 'userkey'), array('optional'=>true));
+
+        $mform->setHelpButton('iprestriction', array(false, get_string('keyiprestriction', 'userkey'),
+                false, true, false, get_string("keyiprestrictionhelp", 'userkey')));
+        $mform->setHelpButton('validuntil', array(false, get_string('keyvaliduntil', 'userkey'), false, true, false, get_string("keyvaliduntilhelp", 'userkey')));
+
+        $mform->addElement('hidden','id');
+        $mform->setType('id', PARAM_INT);
+
+        $mform->addElement('hidden','courseid');
+        $mform->setType('courseid', PARAM_INT);
+
+        $this->add_action_buttons();
+    }
+}
+
+?>
diff --git a/grade/import/keymanager.php b/grade/import/keymanager.php
new file mode 100644 (file)
index 0000000..db9cec7
--- /dev/null
@@ -0,0 +1,78 @@
+<?php  //$Id$
+
+///////////////////////////////////////////////////////////////////////////
+//                                                                       //
+// NOTICE OF COPYRIGHT                                                   //
+//                                                                       //
+// Moodle - Modular Object-Oriented Dynamic Learning Environment         //
+//          http://moodle.com                                            //
+//                                                                       //
+// Copyright (C) 1999 onwards  Martin Dougiamas  http://moodle.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                         //
+//                                                                       //
+///////////////////////////////////////////////////////////////////////////
+
+require_once '../../config.php';
+require_once $CFG->dirroot.'/grade/lib.php';
+
+$id     = required_param('id', PARAM_INT); // course id
+
+if (!$course = get_record('course', 'id', $id)) {
+    print_error('nocourseid');
+}
+
+require_login($course);
+$context = get_context_instance(CONTEXT_COURSE, $id);
+
+require_capability('moodle/grade:import', $context);
+
+$strgrades = get_string('grades', 'grades');
+$navigation = grade_build_nav(__FILE__, null, array('courseid' => $course->id));
+
+print_header($course->shortname.': '.get_string('grades'), $course->fullname, $navigation);
+print_grade_plugin_selector($id, '', '');
+
+$stredit         = get_string('edit');
+$strdelete       = get_string('delete');
+
+$data = array();
+if ($keys = get_records_select('user_private_key', "script='grade/import' AND instance={$course->id} AND userid={$USER->id}")) {
+    foreach($keys as $key) {
+        $line = array();
+        $line[0] = format_string($key->value);
+        $line[1] = $key->iprestriction;
+        $line[2] = empty($key->validuntil) ? get_string('always') : userdate($key->validuntil);
+
+        $buttons  = "<a title=\"$stredit\" href=\"key.php?id=$key->id\"><img".
+                    " src=\"$CFG->pixpath/t/edit.gif\" class=\"iconsmall\" alt=\"$stredit\" /></a> ";
+        $buttons .= "<a title=\"$strdelete\" href=\"key.php?id=$key->id&amp;delete=1\"><img".
+                    " src=\"$CFG->pixpath/t/delete.gif\" class=\"iconsmall\" alt=\"$strdelete\" /></a> ";
+
+        $line[3] = $buttons;
+        $data[] = $line;
+    }
+}
+$table->head  = array(get_string('keyvalue', 'userkey'), get_string('keyiprestriction', 'userkey'), get_string('keyvaliduntil', 'userkey'), $stredit);
+$table->size  = array('50%', '30%', '10%', '10%');
+$table->align = array('left', 'left', 'left', 'center');
+$table->width = '90%';
+$table->data  = $data;
+print_table($table);
+
+echo '<div class="buttons">';
+print_single_button('key.php', array('courseid'=>$course->id), get_string('newuserkey', 'userkey'));
+echo '</div>';
+
+print_footer();
+?>
index d0ab6cc..fb6c355 100755 (executable)
@@ -7,8 +7,10 @@
  * up to this point is fine and we can go ahead and commit
  * @param int courseid - id of the course
  * @param string importcode - import batch identifier
+ * @param feedback print feedback and continue button
+ * @return bool success
  */
-function grade_import_commit($courseid, $importcode) {
+function grade_import_commit($courseid, $importcode, $feedback=true) {
     global $CFG;
 
     include_once($CFG->libdir.'/gradelib.php');
@@ -117,10 +119,14 @@ function grade_import_commit($courseid, $importcode) {
         }
     }
 
-    notify(get_string('importsuccess', 'grades'));
-    print_continue($CFG->wwwroot.'/course/view.php?id='.$courseid);
+    if ($feedback) {
+        notify(get_string('importsuccess', 'grades'), 'notifysuccess');
+        print_continue($CFG->wwwroot.'/grade/index.php?id='.$courseid);
+    }
     // clean up
     import_cleanup($importcode);
+
+    return true;
 }
 
 /**
diff --git a/grade/import/xmlurl/db/access.php b/grade/import/xmlurl/db/access.php
new file mode 100644 (file)
index 0000000..2cd8336
--- /dev/null
@@ -0,0 +1,16 @@
+<?php  // $Id$
+
+$gradeimport_xmlurl_capabilities = array(
+
+    'gradeimport/xmlurl:view' => array(
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_COURSE,
+        'legacy' => array(
+            'admin' => CAP_ALLOW
+        )
+    )
+);
+
+?>
+
+
diff --git a/grade/import/xmlurl/fetch.php b/grade/import/xmlurl/fetch.php
new file mode 100644 (file)
index 0000000..37a69bc
--- /dev/null
@@ -0,0 +1,17 @@
+<?php  //$Id$
+
+$nomoodlecookie = true; // session not used here
+require '../../../config.php';
+
+$id = required_param('id', PARAM_INT); // course id
+
+require_user_key_login('grade/import', $id); // we want different keys for each course
+
+if (empty($CFG->gradepublishing)) {
+    error('Grade publishing disabled');
+}
+
+// use the same page parameters as import.php and append &key=sdhakjsahdksahdkjsahksadjksahdkjsadhksa
+require 'import.php';
+
+?>
\ No newline at end of file
diff --git a/grade/import/xmlurl/grade_import_form.php b/grade/import/xmlurl/grade_import_form.php
new file mode 100644 (file)
index 0000000..9662bcb
--- /dev/null
@@ -0,0 +1,62 @@
+<?php // $Id$
+require_once $CFG->libdir.'/formslib.php';
+
+class grade_import_form extends moodleform {
+    function definition () {
+        global $COURSE, $USER, $CFG;
+
+        $mform =& $this->_form;
+
+        $strrequired = get_string('required');
+
+        // course id needs to be passed for auth purposes
+        $mform->addElement('hidden', 'id', optional_param('id'));
+        $mform->setType('id', PARAM_INT);
+        $mform->addElement('header', 'general', get_string('importfile', 'grades'));
+        // file upload
+        $mform->addElement('text', 'url', get_string('importfile', 'grades'), 'size="80"');
+        $mform->addRule('url', $strrequired, 'required', null, 'client');
+
+        if (!empty($CFG->gradepublishing)) {
+            $mform->addElement('header', 'publishing', get_string('publishing', 'grades'));
+            $options = array(get_string('nopublish', 'grades'), get_string('createnewkey', 'userkey'));
+            if ($keys = get_records_select('user_private_key', "script='grade/import' AND instance={$COURSE->id} AND userid={$USER->id}")) {
+                foreach ($keys as $key) {
+                    $options[$key->value] = $key->value; // TODO: add more details - ip restriction, valid until ??
+                }
+            }
+            $mform->addElement('select', 'key', get_string('userkey', 'userkey'), $options);
+            $mform->setHelpButton('key', array(false, get_string('userkey', 'userkey'),
+                    false, true, false, get_string("userkeyhelp", 'grades')));
+            $mform->addElement('static', 'keymanagerlink', get_string('keymanager', 'userkey'),
+                    '<a href="'.$CFG->wwwroot.'/grade/import/keymanager.php?id='.$COURSE->id.'">'.get_string('keymanager', 'userkey').'</a>');
+
+            $mform->addElement('text', 'iprestriction', get_string('keyiprestriction', 'userkey'), array('size'=>80));
+            $mform->setHelpButton('iprestriction', array(false, get_string('keyiprestriction', 'userkey'),
+                    false, true, false, get_string("keyiprestrictionhelp", 'userkey')));
+
+            $mform->addElement('date_time_selector', 'validuntil', get_string('keyvaliduntil', 'userkey'), array('optional'=>true));
+            $mform->setHelpButton('validuntil', array(false, get_string('keyvaliduntil', 'userkey'),
+                    false, true, false, get_string("keyvaliduntilhelp", 'userkey')));
+            $mform->disabledIf('iprestriction', 'key', get_string('createnewkey', 'userkey'));
+            $mform->disabledIf('validuntil', 'key', get_string('createnewkey', 'userkey'));
+        }
+
+        $this->add_action_buttons(false, get_string('uploadgrades', 'grades'));
+    }
+
+    function validation($data) {
+        $err = array();
+
+        if ($data['url'] != clean_param($data['url'], PARAM_URL)) {
+            $err['url'] = get_string('error');
+        }
+
+        if (count($err) == 0){
+            return true;
+        } else {
+            return $err;
+        }
+    }
+}
+?>
diff --git a/grade/import/xmlurl/import.php b/grade/import/xmlurl/import.php
new file mode 100644 (file)
index 0000000..2f65afa
--- /dev/null
@@ -0,0 +1,178 @@
+<?php  //$Id$
+
+///////////////////////////////////////////////////////////////////////////
+//                                                                       //
+// NOTICE OF COPYRIGHT                                                   //
+//                                                                       //
+// Moodle - Modular Object-Oriented Dynamic Learning Environment         //
+//          http://moodle.com                                            //
+//                                                                       //
+// Copyright (C) 1999 onwards  Martin Dougiamas  http://moodle.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                         //
+//                                                                       //
+///////////////////////////////////////////////////////////////////////////
+
+require_once '../../../config.php';
+require_once $CFG->libdir.'/filelib.php';
+require_once($CFG->libdir.'/xmlize.php');
+require_once($CFG->libdir.'/gradelib.php');
+require_once $CFG->dirroot.'/grade/lib.php';
+require_once $CFG->dirroot.'/grade/import/lib.php';
+
+$url = required_param('url', PARAM_URL); // only real urls here
+$id  = required_param('id', PARAM_INT); // course id
+
+if (!$course = get_record('course', 'id', $id)) {
+    print_error('nocourseid');
+}
+
+require_login($course);
+$context = get_context_instance(CONTEXT_COURSE, $id);
+
+require_capability('moodle/grade:import', $context);
+require_capability('gradeimport/xmlurl:view', $context);
+
+
+// Large files are likely to take their time and memory. Let PHP know
+// that we'll take longer, and that the process should be recycled soon
+// to free up memory.
+@set_time_limit(0);
+@raise_memory_limit("192M");
+if (function_exists('apache_child_terminate')) {
+    @apache_child_terminate();
+}
+
+$text = download_file_content($url);
+if ($text === false) {
+    error('Can not read file');
+}
+
+$status = true;
+$error = '';
+
+$importcode = time();
+$newgrades = array();
+
+$content = xmlize($text);
+
+if ($results = $content['results']['#']['result']) {
+
+    foreach ($results as $i => $result) {
+        if (!$grade_items = grade_item::fetch_all(array('idnumber'=>$result['#']['assignment'][0]['#'], 'courseid'=>$course->id))) {
+            // gradeitem does not exist
+            // no data in temp table so far, abort
+            $status = false;
+            $error  = 'incorrect grade item idnumber'; //TODO: localize
+            break;
+        } else if (count($grade_items) != 1) {
+            $status = false;
+            $error  = 'duplicate grade item idnumber'; //TODO: localize
+            break;
+        } else {
+            $grade_item = reset($grade_items);
+        }
+
+        // grade item locked, abort
+        if ($grade_item->locked) {
+            $status = false;
+            $error  = get_string('gradeitemlocked', 'grades');
+            break;
+        }
+
+        // check if grade_grade is locked and if so, abort
+        if ($grade_grade = new grade_grade(array('itemid'=>$grade_item->id, 'userid'=>$result['#']['student'][0]['#']))) {
+            if ($grade_grade->locked) {
+                // individual grade locked, abort
+                $status = false;
+                $error  = get_string('gradegradeslocked', 'grades');
+                break;
+            }
+        }
+
+        if (isset($result['#']['score'][0]['#'])) {
+            $newgrade = new object();
+            $newgrade->itemid = $grade_item->id;
+            $newgrade->grade  = $result['#']['score'][0]['#'];
+            $newgrade->userid = $result['#']['student'][0]['#'];
+            $newgrades[] = $newgrade;
+        }
+    }
+
+    // loop through info collected so far
+    if ($status && !empty($newgrades)) {
+        foreach ($newgrades as $newgrade) {
+
+            // check if user exist
+            if (!$user = get_record('user', 'id', $newgrade->userid)) {
+                // no user found, abort
+                $status = false;
+                $error = get_string('baduserid', 'grades');
+                break;
+            }
+
+            // check grade value is a numeric grade
+            if (!is_numeric($newgrade->grade)) {
+                $status = false;
+                $error = get_string('badgrade', 'grades');
+                break;
+            }
+
+            // insert this grade into a temp table
+            $newgrade->import_code = $importcode;
+            if (!insert_record('grade_import_values', $newgrade)) {
+                $status = false;
+                // could not insert into temp table
+                $error = get_string('importfailed', 'grades');
+                break;
+            }
+        }
+    }
+} else {
+    // no results section found in xml,
+    // assuming bad format, abort import
+    $status = false;
+    $error = get_string('badxmlformat', 'grade');
+}
+
+if ($status) {
+    /// comit the code if we are up this far
+
+    if (defined('USER_KEY_LOGIN')) {
+        if (grade_import_commit($id, $importcode, false)) {
+            echo 'ok';
+            die;
+        } else {
+            error('Grade import error'); //TODO: localize
+        }
+
+    } else {
+        $strgrades = get_string('grades', 'grades');
+        $actionstr = get_string('xmlurl', 'grades');
+        $navigation = grade_build_nav(__FILE__, $actionstr, array('courseid' => $course->id));
+
+        print_header($course->shortname.': '.get_string('grades'), $course->fullname, $navigation);
+        print_grade_plugin_selector($id, 'import', 'xmlurl');
+
+        grade_import_commit($id, $importcode);
+
+        print_footer();
+        die;
+    }
+
+} else {
+    import_cleanup($importcode);
+    error($error);
+}
+
+?>
\ No newline at end of file
diff --git a/grade/import/xmlurl/index.php b/grade/import/xmlurl/index.php
new file mode 100755 (executable)
index 0000000..7018c61
--- /dev/null
@@ -0,0 +1,78 @@
+<?php  //$Id$
+
+///////////////////////////////////////////////////////////////////////////
+//                                                                       //
+// NOTICE OF COPYRIGHT                                                   //
+//                                                                       //
+// Moodle - Modular Object-Oriented Dynamic Learning Environment         //
+//          http://moodle.com                                            //
+//                                                                       //
+// Copyright (C) 1999 onwards  Martin Dougiamas  http://moodle.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                         //
+//                                                                       //
+///////////////////////////////////////////////////////////////////////////
+
+require_once '../../../config.php';
+require_once $CFG->dirroot.'/grade/lib.php';
+require_once 'grade_import_form.php';
+require_once '../lib.php';
+
+$id = required_param('id', PARAM_INT); // course id
+
+if (!$course = get_record('course', 'id', $id)) {
+    print_error('nocourseid');
+}
+
+require_login($course);
+$context = get_context_instance(CONTEXT_COURSE, $id);
+require_capability('moodle/grade:import', $context);
+require_capability('gradeimport/xml_getch:view', $context);
+
+// print header
+$strgrades = get_string('grades', 'grades');
+$actionstr = get_string('modulename', 'gradeimport_xmlurl');
+$navigation = grade_build_nav(__FILE__, $actionstr, array('courseid' => $course->id));
+
+$mform = new grade_import_form();
+
+if ($data = $mform->get_data()) {
+
+    if (empty($data->key)) {
+        redirect('import.php?id='.$id.'&url='.urlencode($data->url));
+
+    } else {
+        if ($data->key == 1) {
+            $data->key = create_user_key('grade/import', $USER->id, $course->id, $data->iprestriction, $data->validuntil);
+        }
+
+        print_header($course->shortname.': '.get_string('grades'), $course->fullname, $navigation);
+        print_grade_plugin_selector($id, 'import', 'xmlurl');
+
+        echo '<div class="gradeexportlink">';
+        $link = $CFG->wwwroot.'/grade/import/xmlurl/fetch.php?id='.$id.'&amp;url='.urlencode($data->url).'&amp;key='.$data->key;
+        echo get_string('import', 'grades').': <a href="'.$link.'">'.$link.'</a>';
+        echo '</div>';
+        print_footer();
+        die;
+    }
+}
+
+print_header($course->shortname.': '.get_string('grades'), $course->fullname, $navigation);
+print_grade_plugin_selector($id, 'import', 'xmlurl');
+
+$mform->display();
+
+print_footer();
+
+?>
diff --git a/grade/import/xmlurl/version.php b/grade/import/xmlurl/version.php
new file mode 100644 (file)
index 0000000..9da3825
--- /dev/null
@@ -0,0 +1,6 @@
+<?PHP // $Id$
+
+$plugin->version  = 2007092501;
+$plugin->requires = 2007092002;
+
+?>
diff --git a/lang/en_utf8/gradeimport_xmlurl.php b/lang/en_utf8/gradeimport_xmlurl.php
new file mode 100644 (file)
index 0000000..c957a91
--- /dev/null
@@ -0,0 +1,6 @@
+<?PHP // $Id$
+
+$string['modulename'] = 'XML file (URL)';
+$string['xmlurl:view'] = 'Import grades from XML (URL)';
+
+?>