editlib.php 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482
  1. <?php
  2. // This file is part of Moodle - http://moodle.org/
  3. //
  4. // Moodle is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // Moodle is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU General Public License
  15. // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
  16. /**
  17. * This file contains function used when editing a users profile and preferences.
  18. *
  19. * @copyright 1999 Martin Dougiamas http://dougiamas.com
  20. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  21. * @package core_user
  22. */
  23. /**
  24. * Cancels the requirement for a user to update their email address.
  25. *
  26. * @param int $userid
  27. */
  28. function cancel_email_update($userid) {
  29. unset_user_preference('newemail', $userid);
  30. unset_user_preference('newemailkey', $userid);
  31. unset_user_preference('newemailattemptsleft', $userid);
  32. }
  33. /**
  34. * Performs the common access checks and page setup for all
  35. * user preference pages.
  36. *
  37. * @param int $userid The user id to edit taken from the page params.
  38. * @param int $courseid The optional course id if we came from a course context.
  39. * @return array containing the user and course records.
  40. */
  41. function useredit_setup_preference_page($userid, $courseid) {
  42. global $PAGE, $SESSION, $DB, $CFG, $OUTPUT, $USER;
  43. // Guest can not edit.
  44. if (isguestuser()) {
  45. print_error('guestnoeditprofile');
  46. }
  47. if (!$course = $DB->get_record('course', array('id' => $courseid))) {
  48. print_error('invalidcourseid');
  49. }
  50. if ($course->id != SITEID) {
  51. require_login($course);
  52. } else if (!isloggedin()) {
  53. if (empty($SESSION->wantsurl)) {
  54. $SESSION->wantsurl = $CFG->httpswwwroot.'/user/preferences.php';
  55. }
  56. redirect(get_login_url());
  57. } else {
  58. $PAGE->set_context(context_system::instance());
  59. }
  60. // The user profile we are editing.
  61. if (!$user = $DB->get_record('user', array('id' => $userid))) {
  62. print_error('invaliduserid');
  63. }
  64. // Guest can not be edited.
  65. if (isguestuser($user)) {
  66. print_error('guestnoeditprofile');
  67. }
  68. // Remote users cannot be edited.
  69. if (is_mnet_remote_user($user)) {
  70. if (user_not_fully_set_up($user)) {
  71. $hostwwwroot = $DB->get_field('mnet_host', 'wwwroot', array('id' => $user->mnethostid));
  72. print_error('usernotfullysetup', 'mnet', '', $hostwwwroot);
  73. }
  74. redirect($CFG->wwwroot . "/user/view.php?course={$course->id}");
  75. }
  76. $systemcontext = context_system::instance();
  77. $personalcontext = context_user::instance($user->id);
  78. // Check access control.
  79. if ($user->id == $USER->id) {
  80. // Editing own profile - require_login() MUST NOT be used here, it would result in infinite loop!
  81. if (!has_capability('moodle/user:editownprofile', $systemcontext)) {
  82. print_error('cannotedityourprofile');
  83. }
  84. } else {
  85. // Teachers, parents, etc.
  86. require_capability('moodle/user:editprofile', $personalcontext);
  87. // No editing of primary admin!
  88. if (is_siteadmin($user) and !is_siteadmin($USER)) { // Only admins may edit other admins.
  89. print_error('useradmineditadmin');
  90. }
  91. }
  92. if ($user->deleted) {
  93. echo $OUTPUT->header();
  94. echo $OUTPUT->heading(get_string('userdeleted'));
  95. echo $OUTPUT->footer();
  96. die;
  97. }
  98. $PAGE->set_pagelayout('admin');
  99. $PAGE->set_context($personalcontext);
  100. if ($USER->id != $user->id) {
  101. $PAGE->navigation->extend_for_user($user);
  102. } else {
  103. if ($node = $PAGE->navigation->find('myprofile', navigation_node::TYPE_ROOTNODE)) {
  104. $node->force_open();
  105. }
  106. }
  107. return array($user, $course);
  108. }
  109. /**
  110. * Loads the given users preferences into the given user object.
  111. *
  112. * @param stdClass $user The user object, modified by reference.
  113. * @param bool $reload
  114. */
  115. function useredit_load_preferences(&$user, $reload=true) {
  116. global $USER;
  117. if (!empty($user->id)) {
  118. if ($reload and $USER->id == $user->id) {
  119. // Reload preferences in case it was changed in other session.
  120. unset($USER->preference);
  121. }
  122. if ($preferences = get_user_preferences(null, null, $user->id)) {
  123. foreach ($preferences as $name => $value) {
  124. $user->{'preference_'.$name} = $value;
  125. }
  126. }
  127. }
  128. }
  129. /**
  130. * Updates the user preferences for teh given user.
  131. *
  132. * @param stdClass|array $usernew
  133. */
  134. function useredit_update_user_preference($usernew) {
  135. $ua = (array)$usernew;
  136. foreach ($ua as $key => $value) {
  137. if (strpos($key, 'preference_') === 0) {
  138. $name = substr($key, strlen('preference_'));
  139. set_user_preference($name, $value, $usernew->id);
  140. }
  141. }
  142. }
  143. /**
  144. * Updates the provided users profile picture based upon the expected fields returned from the edit or edit_advanced forms.
  145. *
  146. * @deprecated since Moodle 3.2 MDL-51789 - please use core_user::update_picture() instead.
  147. * @todo MDL-54858 This will be deleted in Moodle 3.6.
  148. * @see core_user::update_picture()
  149. *
  150. * @global moodle_database $DB
  151. * @param stdClass $usernew An object that contains some information about the user being updated
  152. * @param moodleform $userform The form that was submitted to edit the form (unused)
  153. * @param array $filemanageroptions
  154. * @return bool True if the user was updated, false if it stayed the same.
  155. */
  156. function useredit_update_picture(stdClass $usernew, moodleform $userform, $filemanageroptions = array()) {
  157. debugging('useredit_update_picture() is deprecated. Please use core_user::update_picture() instead.', DEBUG_DEVELOPER);
  158. return core_user::update_picture($usernew, $filemanageroptions);
  159. }
  160. /**
  161. * Updates the user email bounce + send counts when the user is edited.
  162. *
  163. * @param stdClass $user The current user object.
  164. * @param stdClass $usernew The updated user object.
  165. */
  166. function useredit_update_bounces($user, $usernew) {
  167. if (!isset($usernew->email)) {
  168. // Locked field.
  169. return;
  170. }
  171. if (!isset($user->email) || $user->email !== $usernew->email) {
  172. set_bounce_count($usernew, true);
  173. set_send_count($usernew, true);
  174. }
  175. }
  176. /**
  177. * Updates the forums a user is tracking when the user is edited.
  178. *
  179. * @param stdClass $user The original user object.
  180. * @param stdClass $usernew The updated user object.
  181. */
  182. function useredit_update_trackforums($user, $usernew) {
  183. global $CFG;
  184. if (!isset($usernew->trackforums)) {
  185. // Locked field.
  186. return;
  187. }
  188. if ((!isset($user->trackforums) || ($usernew->trackforums != $user->trackforums)) and !$usernew->trackforums) {
  189. require_once($CFG->dirroot.'/mod/forum/lib.php');
  190. forum_tp_delete_read_records($usernew->id);
  191. }
  192. }
  193. /**
  194. * Updates a users interests.
  195. *
  196. * @param stdClass $user
  197. * @param array $interests
  198. */
  199. function useredit_update_interests($user, $interests) {
  200. core_tag_tag::set_item_tags('core', 'user', $user->id,
  201. context_user::instance($user->id), $interests);
  202. }
  203. /**
  204. * Powerful function that is used by edit and editadvanced to add common form elements/rules/etc.
  205. *
  206. * @param moodleform $mform
  207. * @param array $editoroptions
  208. * @param array $filemanageroptions
  209. * @param stdClass $user
  210. */
  211. function useredit_shared_definition(&$mform, $editoroptions, $filemanageroptions, $user) {
  212. global $CFG, $USER, $DB;
  213. if ($user->id > 0) {
  214. useredit_load_preferences($user, false);
  215. }
  216. $strrequired = get_string('required');
  217. $stringman = get_string_manager();
  218. // Add the necessary names.
  219. foreach (useredit_get_required_name_fields() as $fullname) {
  220. $mform->addElement('text', $fullname, get_string($fullname), 'maxlength="100" size="30"');
  221. if ($stringman->string_exists('missing'.$fullname, 'core')) {
  222. $strmissingfield = get_string('missing'.$fullname, 'core');
  223. } else {
  224. $strmissingfield = $strrequired;
  225. }
  226. $mform->addRule($fullname, $strmissingfield, 'required', null, 'client');
  227. $mform->setType($fullname, PARAM_NOTAGS);
  228. }
  229. $enabledusernamefields = useredit_get_enabled_name_fields();
  230. // Add the enabled additional name fields.
  231. foreach ($enabledusernamefields as $addname) {
  232. $mform->addElement('text', $addname, get_string($addname), 'maxlength="100" size="30"');
  233. $mform->setType($addname, PARAM_NOTAGS);
  234. }
  235. // Do not show email field if change confirmation is pending.
  236. if ($user->id > 0 and !empty($CFG->emailchangeconfirmation) and !empty($user->preference_newemail)) {
  237. $notice = get_string('emailchangepending', 'auth', $user);
  238. $notice .= '<br /><a href="edit.php?cancelemailchange=1&amp;id='.$user->id.'">'
  239. . get_string('emailchangecancel', 'auth') . '</a>';
  240. $mform->addElement('static', 'emailpending', get_string('email'), $notice);
  241. } else {
  242. $mform->addElement('text', 'email', get_string('email'), 'maxlength="100" size="30"');
  243. $mform->addRule('email', $strrequired, 'required', null, 'client');
  244. $mform->setType('email', PARAM_RAW_TRIMMED);
  245. }
  246. $choices = array();
  247. $choices['0'] = get_string('emaildisplayno');
  248. $choices['1'] = get_string('emaildisplayyes');
  249. $choices['2'] = get_string('emaildisplaycourse');
  250. $mform->addElement('select', 'maildisplay', get_string('emaildisplay'), $choices);
  251. $mform->setDefault('maildisplay', core_user::get_property_default('maildisplay'));
  252. $mform->addElement('text', 'city', get_string('city'), 'maxlength="120" size="21"');
  253. $mform->setType('city', PARAM_TEXT);
  254. if (!empty($CFG->defaultcity)) {
  255. $mform->setDefault('city', $CFG->defaultcity);
  256. }
  257. $choices = get_string_manager()->get_list_of_countries();
  258. $choices = array('' => get_string('selectacountry') . '...') + $choices;
  259. $mform->addElement('select', 'country', get_string('selectacountry'), $choices);
  260. if (!empty($CFG->country)) {
  261. $mform->setDefault('country', core_user::get_property_default('country'));
  262. }
  263. if (isset($CFG->forcetimezone) and $CFG->forcetimezone != 99) {
  264. $choices = core_date::get_list_of_timezones($CFG->forcetimezone);
  265. $mform->addElement('static', 'forcedtimezone', get_string('timezone'), $choices[$CFG->forcetimezone]);
  266. $mform->addElement('hidden', 'timezone');
  267. $mform->setType('timezone', core_user::get_property_type('timezone'));
  268. } else {
  269. $choices = core_date::get_list_of_timezones($user->timezone, true);
  270. $mform->addElement('select', 'timezone', get_string('timezone'), $choices);
  271. }
  272. // Multi-Calendar Support - see MDL-18375.
  273. $calendartypes = \core_calendar\type_factory::get_list_of_calendar_types();
  274. // We do not want to show this option unless there is more than one calendar type to display.
  275. if (count($calendartypes) > 1) {
  276. $mform->addElement('select', 'calendartype', get_string('preferredcalendar', 'calendar'), $calendartypes);
  277. $mform->setDefault('calendartype', $CFG->calendartype);
  278. }
  279. if (!empty($CFG->allowuserthemes)) {
  280. $choices = array();
  281. $choices[''] = get_string('default');
  282. $themes = get_list_of_themes();
  283. foreach ($themes as $key => $theme) {
  284. if (empty($theme->hidefromselector)) {
  285. $choices[$key] = get_string('pluginname', 'theme_'.$theme->name);
  286. }
  287. }
  288. $mform->addElement('select', 'theme', get_string('preferredtheme'), $choices);
  289. }
  290. $mform->addElement('editor', 'description_editor', get_string('userdescription'), null, $editoroptions);
  291. $mform->setType('description_editor', PARAM_CLEANHTML);
  292. $mform->addHelpButton('description_editor', 'userdescription');
  293. if (empty($USER->newadminuser)) {
  294. $mform->addElement('header', 'moodle_picture', get_string('pictureofuser'));
  295. $mform->setExpanded('moodle_picture', true);
  296. if (!empty($CFG->enablegravatar)) {
  297. $mform->addElement('html', html_writer::tag('p', get_string('gravatarenabled')));
  298. }
  299. $mform->addElement('static', 'currentpicture', get_string('currentpicture'));
  300. $mform->addElement('checkbox', 'deletepicture', get_string('delete'));
  301. $mform->setDefault('deletepicture', 0);
  302. $mform->addElement('filemanager', 'imagefile', get_string('newpicture'), '', $filemanageroptions);
  303. $mform->addHelpButton('imagefile', 'newpicture');
  304. $mform->addElement('text', 'imagealt', get_string('imagealt'), 'maxlength="100" size="30"');
  305. $mform->setType('imagealt', PARAM_TEXT);
  306. }
  307. // Display user name fields that are not currenlty enabled here if there are any.
  308. $disabledusernamefields = useredit_get_disabled_name_fields($enabledusernamefields);
  309. if (count($disabledusernamefields) > 0) {
  310. $mform->addElement('header', 'moodle_additional_names', get_string('additionalnames'));
  311. foreach ($disabledusernamefields as $allname) {
  312. $mform->addElement('text', $allname, get_string($allname), 'maxlength="100" size="30"');
  313. $mform->setType($allname, PARAM_NOTAGS);
  314. }
  315. }
  316. if (core_tag_tag::is_enabled('core', 'user') and empty($USER->newadminuser)) {
  317. $mform->addElement('header', 'moodle_interests', get_string('interests'));
  318. $mform->addElement('tags', 'interests', get_string('interestslist'),
  319. array('itemtype' => 'user', 'component' => 'core'));
  320. $mform->addHelpButton('interests', 'interestslist');
  321. }
  322. // Moodle optional fields.
  323. $mform->addElement('header', 'moodle_optional', get_string('optional', 'form'));
  324. $mform->addElement('text', 'url', get_string('webpage'), 'maxlength="255" size="50"');
  325. $mform->setType('url', core_user::get_property_type('url'));
  326. $mform->addElement('text', 'icq', get_string('icqnumber'), 'maxlength="15" size="25"');
  327. $mform->setType('icq', core_user::get_property_type('icq'));
  328. $mform->addElement('text', 'skype', get_string('skypeid'), 'maxlength="50" size="25"');
  329. $mform->setType('skype', core_user::get_property_type('skype'));
  330. $mform->addElement('text', 'aim', get_string('aimid'), 'maxlength="50" size="25"');
  331. $mform->setType('aim', core_user::get_property_type('aim'));
  332. $mform->addElement('text', 'yahoo', get_string('yahooid'), 'maxlength="50" size="25"');
  333. $mform->setType('yahoo', core_user::get_property_type('yahoo'));
  334. $mform->addElement('text', 'msn', get_string('msnid'), 'maxlength="50" size="25"');
  335. $mform->setType('msn', core_user::get_property_type('msn'));
  336. $mform->addElement('text', 'idnumber', get_string('idnumber'), 'maxlength="255" size="25"');
  337. $mform->setType('idnumber', core_user::get_property_type('idnumber'));
  338. $mform->addElement('text', 'institution', get_string('institution'), 'maxlength="255" size="25"');
  339. $mform->setType('institution', core_user::get_property_type('institution'));
  340. $mform->addElement('text', 'department', get_string('department'), 'maxlength="255" size="25"');
  341. $mform->setType('department', core_user::get_property_type('department'));
  342. $mform->addElement('text', 'phone1', get_string('phone1'), 'maxlength="20" size="25"');
  343. $mform->setType('phone1', core_user::get_property_type('phone1'));
  344. $mform->addElement('text', 'phone2', get_string('phone2'), 'maxlength="20" size="25"');
  345. $mform->setType('phone2', core_user::get_property_type('phone2'));
  346. $mform->addElement('text', 'address', get_string('address'), 'maxlength="255" size="25"');
  347. $mform->setType('address', core_user::get_property_type('address'));
  348. }
  349. /**
  350. * Return required user name fields for forms.
  351. *
  352. * @return array required user name fields in order according to settings.
  353. */
  354. function useredit_get_required_name_fields() {
  355. global $CFG;
  356. // Get the name display format.
  357. $nameformat = $CFG->fullnamedisplay;
  358. // Names that are required fields on user forms.
  359. $necessarynames = array('firstname', 'lastname');
  360. $languageformat = get_string('fullnamedisplay');
  361. // Check that the language string and the $nameformat contain the necessary names.
  362. foreach ($necessarynames as $necessaryname) {
  363. $pattern = "/$necessaryname\b/";
  364. if (!preg_match($pattern, $languageformat)) {
  365. // If the language string has been altered then fall back on the below order.
  366. $languageformat = 'firstname lastname';
  367. }
  368. if (!preg_match($pattern, $nameformat)) {
  369. // If the nameformat doesn't contain the necessary name fields then use the languageformat.
  370. $nameformat = $languageformat;
  371. }
  372. }
  373. // Order all of the name fields in the postion they are written in the fullnamedisplay setting.
  374. $necessarynames = order_in_string($necessarynames, $nameformat);
  375. return $necessarynames;
  376. }
  377. /**
  378. * Gets enabled (from fullnameformate setting) user name fields in appropriate order.
  379. *
  380. * @return array Enabled user name fields.
  381. */
  382. function useredit_get_enabled_name_fields() {
  383. global $CFG;
  384. // Get all of the other name fields which are not ranked as necessary.
  385. $additionalusernamefields = array_diff(get_all_user_name_fields(), array('firstname', 'lastname'));
  386. // Find out which additional name fields are actually being used from the fullnamedisplay setting.
  387. $enabledadditionalusernames = array();
  388. foreach ($additionalusernamefields as $enabledname) {
  389. if (strpos($CFG->fullnamedisplay, $enabledname) !== false) {
  390. $enabledadditionalusernames[] = $enabledname;
  391. }
  392. }
  393. // Order all of the name fields in the postion they are written in the fullnamedisplay setting.
  394. $enabledadditionalusernames = order_in_string($enabledadditionalusernames, $CFG->fullnamedisplay);
  395. return $enabledadditionalusernames;
  396. }
  397. /**
  398. * Gets user name fields not enabled from the setting fullnamedisplay.
  399. *
  400. * @param array $enabledadditionalusernames Current enabled additional user name fields.
  401. * @return array Disabled user name fields.
  402. */
  403. function useredit_get_disabled_name_fields($enabledadditionalusernames = null) {
  404. // If we don't have enabled additional user name information then go and fetch it (try to avoid).
  405. if (!isset($enabledadditionalusernames)) {
  406. $enabledadditionalusernames = useredit_get_enabled_name_fields();
  407. }
  408. // These are the additional fields that are not currently enabled.
  409. $nonusednamefields = array_diff(get_all_user_name_fields(),
  410. array_merge(array('firstname', 'lastname'), $enabledadditionalusernames));
  411. return $nonusednamefields;
  412. }