diff --git a/user/profile/index.php b/user/profile/index.php
new file mode 100644
index 0000000000000..8cd326aaa9de1
--- /dev/null
+++ b/user/profile/index.php
@@ -0,0 +1,329 @@
+dirroot.'/user/profile/lib.php');
+require_once($CFG->libdir.'/adminlib.php');
+
+$adminroot = admin_get_root();
+admin_externalpage_setup('profilefields', $adminroot);
+
+require_login();
+
+require_capability('moodle/user:update', get_context_instance(CONTEXT_SYSTEM, SITEID));
+
+
+$id = optional_param('id', 0, PARAM_INT);
+$action = optional_param('action', '', PARAM_ALPHA);
+$dir = optional_param('dir', '', PARAM_ALPHA);
+$confirm = optional_param('confirm', 0, PARAM_BOOL);
+$type = optional_param('type', '', PARAM_ALPHANUM);
+
+$datatypes = profile_list_datatypes();
+$redirect = $CFG->wwwroot.'/user/profile/index.php';
+$strchangessaved = get_string('changessaved');
+$strcancelled = get_string('cancelled');
+
+
+/// Do we have any actions to perform before printing the header
+
+switch ($action) {
+ case 'movecategory':
+ if (confirm_sesskey()) {
+ profile_move_category($id, $dir);
+ }
+ redirect($redirect);
+ exit;
+ break;
+ case 'movefield':
+ if (confirm_sesskey()) {
+ profile_move_field($id, $dir);
+ }
+ redirect($redirect);
+ exit;
+ break;
+ case 'deletecategory':
+ if ($confirm and confirm_sesskey()) {
+ $categorycount = count_records_select('user_info_category', '1');
+ $fieldcount = count_records('user_info_field', 'categoryid', $id);
+
+ /// Can only delete the last category if there are no fields in it
+ if ( ($categorycount > 1) or ($fieldcount == 0) ) {
+ profile_delete_category($id);
+ }
+ redirect($redirect);
+ exit;
+ }
+ break;
+ case 'deletefield':
+
+ if ($confirm and confirm_sesskey()) {
+ if ($field = get_record('user_info_field', 'id', $id)) {
+ require_once($CFG->dirroot.'/user/profile/field/'.$field->datatype.'/field.class.php');
+ $newfield = 'profile_field_'.$field->datatype;
+ $formfield = new $newfield($field->id);
+ $formfield->edit_remove_field();
+ }
+ redirect($redirect);
+ exit;
+ }
+
+ break;
+ case 'editfield':
+ unset($field);
+ if ($id == 0) {
+ if (!isset($datatypes[$type])) {
+ redirect($redirect);
+ exit;
+ }
+ $field->id = 0;
+ $field->datatype = $datatypes[$type];
+ $field->categoryid = 0;
+ } elseif (!($field = get_record('user_info_field', 'id', $id))) {
+ redirect($redirect);
+ exit;
+ }
+ break;
+ case 'editcategory':
+ unset($category);
+ if ($id == 0) {
+ $category->id = 0;
+ $category->name = '';
+ } elseif (!($category = get_record('user_info_category', 'id', $id))) {
+ redirect($redirect);
+ exit;
+ }
+ break;
+ default:
+}
+
+
+
+/// Print the header
+admin_externalpage_print_header($adminroot);
+
+print_heading(get_string('profilefields', 'admin'));
+
+
+/// Are we adding or editing a cateogory?
+if ( ($action == 'editcategory' )) {
+ require_once('index_category_form.php');
+ $categoryform = new category_form(null, compact('category'));
+ if ($categoryform->is_cancelled()) {
+ redirect($redirect, $strcancelled);
+ } else {
+ if ($data = $categoryform->data_submitted()) {
+ if ($data->id == 0) {
+ unset($data->id);
+ $data->sortorder = count_records_select('user_info_category', '1') + 1;
+ if (!insert_record('user_info_category', $data, false)) {
+ error('There was a problem adding the record to the database');
+ exit;
+ }
+ } else {
+ if (!update_record('user_info_category', $data)) {
+ error('There was a problem updating the record in the database');
+ exit;
+ }
+ }
+ redirect($redirect, $strchangessaved);
+ } else {
+ $categoryform->display();
+ }
+ }
+
+/// Are we adding or editing a field?
+} elseif ( $action == 'editfield' ) {
+ require_once('index_field_form.php');
+ $fieldform = new field_form(null, compact('field'));
+ if ($fieldform->is_cancelled()) {
+ redirect($redirect, $strcancelled);
+ } else {
+ if ($data = $fieldform->data_submitted()) {
+ require_once($CFG->dirroot.'/user/profile/field/'.$field->datatype.'/field.class.php');
+ $newfield = 'profile_field_'.$field->datatype;
+ $formfield = new $newfield($field->id);
+ if (!$formfield->edit_save($data)) {
+ error('There was an error updating the database');
+ } else {
+ redirect($redirect, $strchangessaved);
+ }
+
+ } else {
+ $fieldform->display();
+ }
+ }
+
+/// Deleting a category that has fields in it, print confirm screen?
+} elseif ( ($action == 'deletecategory') and !$confirm ) {
+ $fieldcount = count_records('user_info_field', 'categoryid', $id);
+ echo '
'.get_string('profileconfirmcategorydeletion', 'admin', $fieldcount).'
'.get_string('yes').' '.get_string('no').'';
+
+
+/// Deleting a field that has user data, print confirm screen
+} elseif ( ($action == 'deletefield') and !$confirm ) {
+ $datacount = count_records('user_info_data', 'fieldid', $id);
+ echo ''.get_string('profileconfirmfielddeletion', 'admin', $datacount).'
'.get_string('yes').' '.get_string('no').'';
+
+
+
+/// Print the table of categories and fields
+} else {
+
+ if ($categories = get_records_select('user_info_category', '1', 'sortorder ASC')) {
+
+ unset ($table);
+ $table->align = array('left', 'right');
+ $table->width = '95%';
+ $table->data = array();
+
+ foreach ($categories as $category) {
+
+ $table->data[] = array($category->name, profile_category_icons($category));
+
+ unset($table2);
+ $table2->align = array('left', 'right');
+ $table2->width = '100%';
+ $table2->data = array();
+
+ if ($fields = get_records_select('user_info_field', "categoryid=$category->id", 'sortorder ASC')) {
+ foreach ($fields as $field) {
+
+ $table2->data[] = array($field->shortname, profile_field_icons($field));
+
+ } /// End of $fields foreach
+ } /// End of $fields if
+
+ if (!empty($table2->data)) {
+ $table->data[] = array('',print_table($table2,true));
+ }
+
+ } /// End of $categories foreach
+
+ print_table($table);
+
+ } else {
+
+ notify(get_string('profilenocategoriesdefined', 'admin'));
+
+ } /// End of $categories if
+
+
+
+
+ echo '
';
+ echo '';
+
+ /// Create a new field link
+ if ($categories) {
+ $options = profile_list_datatypes();
+ print_string('profilecreatefield', 'admin');
+ popup_form($CFG->wwwroot.'/user/profile/index.php?id=0&action=editfield&type=', $options, 'newfieldform');
+ }
+
+/// Create a new category link
+ $options = array('action'=>'editcategory', 'id'=>'0');
+ print_single_button('index.php',$options,get_string('profilecreatecategory', 'admin'));
+
+ echo '';
+}
+
+admin_externalpage_print_footer($adminroot);
+
+
+
+/***** Some functions relevant to this script *****/
+
+/**
+ * Create a string containing the editing icons for the user profile categories
+ * @param object the category object
+ * @return string the icon string
+ */
+function profile_category_icons ($category) {
+ global $CFG, $USER;
+
+ $str->delete = get_string("delete");
+ $str->moveup = get_string("moveup");
+ $str->movedown = get_string("movedown");
+ $str->edit = get_string("edit");
+
+ $editstr = '';
+ $categorycount = count_records_select('user_info_category', '1');
+ $fieldcount = count_records('user_info_field', 'categoryid', $category->id);
+
+ /// Edit
+ $editstr .= ' ';
+
+ /// Delete
+ /// Can only delete the last category if there are no fields in it
+ if ( ($categorycount > 1) or ($fieldcount == 0) ) {
+ $editstr .= ' ';
+ } else {
+ $editstr .= ' ';
+ }
+
+ /// Move up
+ if ($category->sortorder > 1) {
+ $editstr .= ' ';
+ } else {
+ $editstr .= ' ';
+ }
+
+ /// Move down
+ if ($category->sortorder < $categorycount) {
+ $editstr .= ' ';
+ } else {
+ $editstr .= ' ';
+ }
+
+
+ return $editstr;
+}
+
+/**
+ * Create a string containing the editing icons for the user profile fields
+ * @param object the field object
+ * @return string the icon string
+ */
+function profile_field_icons ($field) {
+ global $CFG, $USER;
+
+ if (empty($str)) {
+ $str->delete = get_string("delete");
+ $str->moveup = get_string("moveup");
+ $str->movedown = get_string("movedown");
+ $str->edit = get_string("edit");
+ }
+
+ $editstr = '';
+ $fieldcount = count_records('user_info_field', 'categoryid',$field->categoryid);
+ $datacount = count_records('user_info_data', 'fieldid', $field->id);
+
+ /// Edit
+ $editstr .= ' ';
+
+ /// Delete
+ $editstr .= ' ';
+
+ /// Move up
+ if ($field->sortorder > 1) {
+ $editstr .= ' ';
+ } else {
+ $editstr .= ' ';
+ }
+
+ /// Move down
+ if ($field->sortorder < $fieldcount) {
+ $editstr .= ' ';
+ } else {
+ $editstr .= ' ';
+ }
+
+ return $editstr;
+}
+
+
+?>
diff --git a/user/profile/index_category_form.php b/user/profile/index_category_form.php
new file mode 100644
index 0000000000000..596db12a93313
--- /dev/null
+++ b/user/profile/index_category_form.php
@@ -0,0 +1,57 @@
+dirroot/lib/formslib.php");
+
+class category_form extends moodleform {
+
+ // Define the form
+ function definition () {
+ global $USER, $CFG;
+
+ $mform =& $this->_form;
+ $renderer =& $mform->defaultRenderer();
+ $category = $this->_customdata['category'];
+
+ $strrequired = get_string('required');
+
+ /// Add some extra hidden fields
+ $mform->addElement('hidden', 'id', $category->id);
+ $mform->addElement('hidden', 'action', 'editcategory');
+ $mform->addElement('hidden', 'sesskey', $USER->sesskey);
+
+ $mform->addElement('text', 'name', get_string('profilecategoryname', 'admin'), 'maxlength="255" size="30"');
+ $mform->setType('name', PARAM_MULTILANG);
+ $mform->addRule('name', $strrequired, 'required', null, 'client');
+ $mform->setDefault('name', $category->name);
+
+ $this->add_action_buttons(true);
+
+
+ } /// End of function
+
+ function definition_after_data () {
+ /// nothing yet
+ }
+
+
+/// perform some moodle validation
+ function validation ($data) {
+ global $CFG;
+
+ $data = (object)$data;
+ $err = array();
+
+ /// Check the name is unique
+ if (($category = get_record('user_info_category', 'name', $data->name)) and ($category->id <> $data->id)) {
+ $err['name'] = get_string('profilecategorynamenotunique', 'admin');
+ }
+
+ if (count($err) == 0){
+ return true;
+ } else {
+ return $err;
+ }
+ }
+}
+
+?>
diff --git a/user/profile/index_field_form.php b/user/profile/index_field_form.php
new file mode 100644
index 0000000000000..28f2f4fa74550
--- /dev/null
+++ b/user/profile/index_field_form.php
@@ -0,0 +1,66 @@
+dirroot/lib/formslib.php");
+
+class field_form extends moodleform {
+
+ // Define the form
+ function definition () {
+ global $USER, $CFG;
+
+ $mform =& $this->_form;
+ $renderer =& $mform->defaultRenderer();
+ $field = $this->_customdata['field'];
+
+ $strrequired = get_string('required');
+
+ /// Add some extra hidden fields
+ $mform->addElement('hidden', 'id', $field->id);
+ $mform->addElement('hidden', 'action', 'editfield');
+ $mform->addElement('hidden', 'type', $field->datatype);
+ $mform->addElement('hidden', 'oldcategory', $field->categoryid);
+ $mform->addElement('hidden', 'datatype', $field->datatype);
+ $mform->addElement('hidden', 'sesskey', $USER->sesskey);
+
+
+ /// Everything else is dependant on the data type
+ require_once($CFG->dirroot.'/user/profile/field/'.$field->datatype.'/field.class.php');
+ $newfield = 'profile_field_'.$field->datatype;
+ $formfield = new $newfield($field->id);
+ $formfield->edit_field($mform);
+
+ /// override the defaults with the user settings
+ $this->set_defaults($field);
+
+ $this->add_action_buttons(true);
+
+
+ } /// End of function
+
+ function definition_after_data () {
+ /// nothing yet
+ }
+
+
+/// perform some moodle validation
+ function validation ($data) {
+ global $CFG;
+
+ $data = (object)$data;
+ $field = $this->_customdata['field'];
+
+ /// Everything else is dependant on the data type
+ require_once($CFG->dirroot.'/user/profile/field/'.$field->datatype.'/field.class.php');
+ $newfield = 'profile_field_'.$field->datatype;
+ $formfield = new $newfield($field->id);
+ $err = $formfield->edit_validate($data);
+
+ if (count($err) == 0){
+ return true;
+ } else {
+ return $err;
+ }
+ }
+}
+
+?>