From bb78e249cdb882b2cd336fedafab74e31c52cf5b Mon Sep 17 00:00:00 2001 From: Rajesh Taneja Date: Mon, 19 Aug 2013 17:03:39 +0800 Subject: [PATCH] MDL-39961 Events: Replace Legacy events - User This change includes: * Added user_updated event, replacing old event * Added user_created event, replacing old event * Added user_deleted event, replacing old event * Added user_loggedout event, replacing old event * Added user_enrolment_created event, replacing old event * Added user_enrolment_deleted event, replacing old event * Added user_enrolment_updated event, replacing old event --- admin/tool/uploaduser/index.php | 13 +- admin/user.php | 13 +- auth/db/auth.php | 4 +- auth/email/auth.php | 8 +- auth/ldap/auth.php | 53 ++++---- auth/mnet/auth.php | 4 +- badges/classes/observer.php | 34 ++++- badges/tests/badgeslib_test.php | 19 +++ enrol/manual/locallib.php | 12 +- enrol/meta/classes/observer.php | 102 ++++++++++++++ enrol/meta/db/events.php | 38 +++--- enrol/meta/locallib.php | 66 ---------- enrol/meta/tests/plugin_test.php | 108 +++++++++++++++ enrol/tests/enrollib_test.php | 37 ++++++ lang/en/enrol.php | 3 + lang/en/moodle.php | 4 + lib/badgeslib.php | 34 ----- lib/behat/classes/util.php | 6 +- lib/classes/event/user_created.php | 99 ++++++++++++++ lib/classes/event/user_deleted.php | 105 +++++++++++++++ lib/classes/event/user_enrolment_created.php | 109 +++++++++++++++ lib/classes/event/user_enrolment_deleted.php | 110 ++++++++++++++++ lib/classes/event/user_enrolment_updated.php | 109 +++++++++++++++ lib/classes/event/user_loggedout.php | 100 ++++++++++++++ lib/classes/event/user_updated.php | 99 ++++++++++++++ lib/db/events.php | 12 +- lib/enrollib.php | 64 +++++---- lib/moodlelib.php | 67 ++++++---- lib/tests/moodlelib_test.php | 47 ++++++- mod/forum/classes/observer.php | 52 ++++++++ mod/forum/db/events.php | 12 +- mod/forum/lib.php | 22 ---- mod/forum/tests/lib_test.php | 33 +++++ user/edit.php | 16 +-- user/editadvanced.php | 25 +--- user/emailupdate.php | 8 +- user/lib.php | 79 ++++++----- user/tests/userlib_test.php | 132 +++++++++++++++++++ 38 files changed, 1519 insertions(+), 339 deletions(-) create mode 100644 enrol/meta/classes/observer.php create mode 100644 lib/classes/event/user_created.php create mode 100644 lib/classes/event/user_deleted.php create mode 100644 lib/classes/event/user_enrolment_created.php create mode 100644 lib/classes/event/user_enrolment_deleted.php create mode 100644 lib/classes/event/user_enrolment_updated.php create mode 100644 lib/classes/event/user_loggedout.php create mode 100644 lib/classes/event/user_updated.php create mode 100644 mod/forum/classes/observer.php create mode 100644 user/tests/userlib_test.php diff --git a/admin/tool/uploaduser/index.php b/admin/tool/uploaduser/index.php index c052d1cfcbc..7949d94eada 100644 --- a/admin/tool/uploaduser/index.php +++ b/admin/tool/uploaduser/index.php @@ -27,6 +27,7 @@ require('../../../config.php'); require_once($CFG->libdir.'/adminlib.php'); require_once($CFG->libdir.'/csvlib.class.php'); require_once($CFG->dirroot.'/user/profile/lib.php'); +require_once($CFG->dirroot.'/user/lib.php'); require_once($CFG->dirroot.'/group/lib.php'); require_once($CFG->dirroot.'/cohort/lib.php'); require_once('locallib.php'); @@ -654,9 +655,8 @@ if ($formdata = $mform2->is_cancelled()) { } if ($doupdate or $existinguser->password !== $oldpw) { - // we want only users that were really updated - - $DB->update_record('user', $existinguser); + // We want only users that were really updated. + user_update_user($existinguser, false); $upt->track('status', $struserupdated); $usersupdated++; @@ -668,8 +668,6 @@ if ($formdata = $mform2->is_cancelled()) { profile_save_data($existinguser); } - events_trigger('user_updated', $existinguser); - if ($bulk == UU_BULK_UPDATED or $bulk == UU_BULK_ALL) { if (!in_array($user->id, $SESSION->bulk_users)) { $SESSION->bulk_users[] = $user->id; @@ -789,8 +787,7 @@ if ($formdata = $mform2->is_cancelled()) { $upt->track('password', '-', 'normal', false); } - // create user - insert_record ignores any extra properties - $user->id = $DB->insert_record('user', $user); + $user->id = user_create_user($user, false); $upt->track('username', html_writer::link(new moodle_url('/user/profile.php', array('id'=>$user->id)), s($user->username)), 'normal', false); // pre-process custom profile menu fields data from csv file @@ -812,8 +809,6 @@ if ($formdata = $mform2->is_cancelled()) { // make sure user context exists context_user::instance($user->id); - events_trigger('user_created', $user); - if ($bulk == UU_BULK_NEW or $bulk == UU_BULK_ALL) { if (!in_array($user->id, $SESSION->bulk_users)) { $SESSION->bulk_users[] = $user->id; diff --git a/admin/user.php b/admin/user.php index 0f6660345ee..699babbeea8 100644 --- a/admin/user.php +++ b/admin/user.php @@ -4,6 +4,7 @@ require_once($CFG->libdir.'/adminlib.php'); require_once($CFG->libdir.'/authlib.php'); require_once($CFG->dirroot.'/user/filters/lib.php'); + require_once($CFG->dirroot.'/user/lib.php'); $delete = optional_param('delete', 0, PARAM_INT); $confirm = optional_param('confirm', '', PARAM_ALPHANUM); //md5 confirmation hash @@ -123,12 +124,9 @@ if ($user = $DB->get_record('user', array('id'=>$suspend, 'mnethostid'=>$CFG->mnet_localhost_id, 'deleted'=>0))) { if (!is_siteadmin($user) and $USER->id != $user->id and $user->suspended != 1) { $user->suspended = 1; - $user->timemodified = time(); - $DB->set_field('user', 'suspended', $user->suspended, array('id'=>$user->id)); - $DB->set_field('user', 'timemodified', $user->timemodified, array('id'=>$user->id)); - // force logout + // Force logout. session_kill_user($user->id); - events_trigger('user_updated', $user); + user_update_user($user, false); } } redirect($returnurl); @@ -139,10 +137,7 @@ if ($user = $DB->get_record('user', array('id'=>$unsuspend, 'mnethostid'=>$CFG->mnet_localhost_id, 'deleted'=>0))) { if ($user->suspended != 0) { $user->suspended = 0; - $user->timemodified = time(); - $DB->set_field('user', 'suspended', $user->suspended, array('id'=>$user->id)); - $DB->set_field('user', 'timemodified', $user->timemodified, array('id'=>$user->id)); - events_trigger('user_updated', $user); + user_update_user($user, false); } } redirect($returnurl); diff --git a/auth/db/auth.php b/auth/db/auth.php index de5061da32a..a01fc6e9801 100644 --- a/auth/db/auth.php +++ b/auth/db/auth.php @@ -284,6 +284,7 @@ class auth_plugin_db extends auth_plugin_base { $remove_users = $DB->get_records_sql($sql, $params); if (!empty($remove_users)) { + require_once($CFG->dirroot.'/user/lib.php'); $trace->output(get_string('auth_dbuserstoremove','auth_db', count($remove_users))); foreach ($remove_users as $user) { @@ -294,8 +295,7 @@ class auth_plugin_db extends auth_plugin_base { $updateuser = new stdClass(); $updateuser->id = $user->id; $updateuser->suspended = 1; - $updateuser->timemodified = time(); - $DB->update_record('user', $updateuser); + user_update_user($updateuser, false); $trace->output(get_string('auth_dbsuspenduser', 'auth_db', array('name'=>$user->username, 'id'=>$user->id)), 1); } } diff --git a/auth/email/auth.php b/auth/email/auth.php index e4590048a4d..a670cfc36a5 100644 --- a/auth/email/auth.php +++ b/auth/email/auth.php @@ -87,17 +87,15 @@ class auth_plugin_email extends auth_plugin_base { function user_signup($user, $notify=true) { global $CFG, $DB; require_once($CFG->dirroot.'/user/profile/lib.php'); + require_once($CFG->dirroot.'/user/lib.php'); $user->password = hash_internal_user_password($user->password); - $user->id = $DB->insert_record('user', $user); + $user->id = user_create_user($user, false); - /// Save any custom profile field information + // Save any custom profile field information. profile_save_data($user); - $user = $DB->get_record('user', array('id'=>$user->id)); - events_trigger('user_created', $user); - if (! send_confirmation_email($user)) { print_error('auth_emailnoemail','auth_email'); } diff --git a/auth/ldap/auth.php b/auth/ldap/auth.php index 866a83884a8..1bad153ff03 100644 --- a/auth/ldap/auth.php +++ b/auth/ldap/auth.php @@ -78,6 +78,7 @@ if (!defined('LDAP_OPT_DIAGNOSTIC_MESSAGE')) { require_once($CFG->libdir.'/authlib.php'); require_once($CFG->libdir.'/ldaplib.php'); +require_once($CFG->dirroot.'/user/lib.php'); /** * LDAP authentication plugin. @@ -550,7 +551,7 @@ class auth_plugin_ldap extends auth_plugin_base { print_error('auth_ldap_create_error', 'auth_ldap'); } - $user->id = $DB->insert_record('user', $user); + $user->id = user_create_user($user, false); // Save any custom profile field information profile_save_data($user); @@ -562,7 +563,6 @@ class auth_plugin_ldap extends auth_plugin_base { update_internal_user_password($user, $plainslashedpassword); $user = $DB->get_record('user', array('id'=>$user->id)); - events_trigger('user_created', $user); if (! send_confirmation_email($user)) { print_error('noemail', 'auth_ldap'); @@ -612,12 +612,12 @@ class auth_plugin_ldap extends auth_plugin_base { if (!$this->user_activate($username)) { return AUTH_CONFIRM_FAIL; } - $DB->set_field('user', 'confirmed', 1, array('id'=>$user->id)); + $user->confirmed = 1; if ($user->firstaccess == 0) { - $DB->set_field('user', 'firstaccess', time(), array('id'=>$user->id)); + $user->firstaccess = time(); } - $euser = $DB->get_record('user', array('id' => $user->id)); - events_trigger('user_updated', $euser); + require_once($CFG->dirroot.'/user/lib.php'); + user_update_user($user, false); return AUTH_CONFIRM_OK; } } else { @@ -806,10 +806,8 @@ class auth_plugin_ldap extends auth_plugin_base { $updateuser = new stdClass(); $updateuser->id = $user->id; $updateuser->suspended = 1; - $DB->update_record('user', $updateuser); + user_update_user($updateuser, false); echo "\t"; print_string('auth_dbsuspenduser', 'auth_db', array('name'=>$user->username, 'id'=>$user->id)); echo "\n"; - $euser = $DB->get_record('user', array('id' => $user->id)); - events_trigger('user_updated', $euser); session_kill_user($user->id); } } else { @@ -835,10 +833,8 @@ class auth_plugin_ldap extends auth_plugin_base { $updateuser->id = $user->id; $updateuser->auth = $this->authtype; $updateuser->suspended = 0; - $DB->update_record('user', $updateuser); + user_update_user($updateuser, false); echo "\t"; print_string('auth_dbreviveduser', 'auth_db', array('name'=>$user->username, 'id'=>$user->id)); echo "\n"; - $euser = $DB->get_record('user', array('id' => $user->id)); - events_trigger('user_updated', $euser); } } else { print_string('nouserentriestorevive', 'auth_ldap'); @@ -950,10 +946,10 @@ class auth_plugin_ldap extends auth_plugin_base { $user->lang = $CFG->lang; } - $id = $DB->insert_record('user', $user); + $id = user_create_user($user, false); echo "\t"; print_string('auth_dbinsertuser', 'auth_db', array('name'=>$user->username, 'id'=>$id)); echo "\n"; $euser = $DB->get_record('user', array('id' => $id)); - events_trigger('user_created', $euser); + if (!empty($this->config->forcechangepassword)) { set_user_preference('auth_forcepasswordchange', 1, $id); } @@ -1011,22 +1007,25 @@ class auth_plugin_ldap extends auth_plugin_base { $updatekeys = array_keys($newinfo); } - foreach ($updatekeys as $key) { - if (isset($newinfo[$key])) { - $value = $newinfo[$key]; - } else { - $value = ''; - } + if (!empty($updatekeys)) { + $newuser = new stdClass(); + $newuser->id = $userid; - if (!empty($this->config->{'field_updatelocal_' . $key})) { - if ($user->{$key} != $value) { // only update if it's changed - $DB->set_field('user', $key, $value, array('id'=>$userid)); + foreach ($updatekeys as $key) { + if (isset($newinfo[$key])) { + $value = $newinfo[$key]; + } else { + $value = ''; + } + + if (!empty($this->config->{'field_updatelocal_' . $key})) { + // Only update if it's changed. + if ($user->{$key} != $value) { + $newuser->$key = $value; + } } } - } - if (!empty($updatekeys)) { - $euser = $DB->get_record('user', array('id' => $userid)); - events_trigger('user_updated', $euser); + user_update_user($newuser, false); } } else { return false; diff --git a/auth/mnet/auth.php b/auth/mnet/auth.php index c1861fac43e..2f626bd2dbd 100644 --- a/auth/mnet/auth.php +++ b/auth/mnet/auth.php @@ -216,6 +216,7 @@ class auth_plugin_mnet extends auth_plugin_base { global $CFG, $DB; require_once $CFG->dirroot . '/mnet/xmlrpc/client.php'; require_once $CFG->libdir . '/gdlib.php'; + require_once($CFG->dirroot.'/user/lib.php'); // verify the remote host is configured locally before attempting RPC call if (! $remotehost = $DB->get_record('mnet_host', array('wwwroot' => $remotepeer->wwwroot, 'deleted' => 0))) { @@ -361,8 +362,7 @@ class auth_plugin_mnet extends auth_plugin_base { if (empty($localuser->firstaccess)) { // Now firstaccess, grab it here $localuser->firstaccess = time(); } - - $DB->update_record('user', $localuser); + user_update_user($localuser, false); if (!$firsttime) { // repeat customer! let the IDP know about enrolments diff --git a/badges/classes/observer.php b/badges/classes/observer.php index 6d7b05468ee..39c2c4ceb03 100644 --- a/badges/classes/observer.php +++ b/badges/classes/observer.php @@ -72,7 +72,7 @@ class core_badges_observer { /** * Triggered when 'course_completed' event is triggered. * - * @param \core\event\course_completed $event + * @param \core\event\course_completed $event */ public static function course_criteria_review(\core\event\course_completed $event) { global $DB, $CFG; @@ -105,4 +105,36 @@ class core_badges_observer { } } } + + /** + * Triggered when 'user_updated' event happens. + * + * @param \core\event\user_updated $event event generated when user profile is updated. + */ + public static function profile_criteria_review(\core\event\user_updated $event) { + global $DB, $CFG; + + if (!empty($CFG->enablebadges)) { + require_once($CFG->dirroot.'/lib/badgeslib.php'); + $userid = $event->objectid; + + if ($rs = $DB->get_records('badge_criteria', array('criteriatype' => BADGE_CRITERIA_TYPE_PROFILE))) { + foreach ($rs as $r) { + $badge = new badge($r->badgeid); + if (!$badge->is_active() || $badge->is_issued($userid)) { + continue; + } + + if ($badge->criteria[BADGE_CRITERIA_TYPE_PROFILE]->review($userid)) { + $badge->criteria[BADGE_CRITERIA_TYPE_PROFILE]->mark_complete($userid); + + if ($badge->criteria[BADGE_CRITERIA_TYPE_OVERALL]->review($userid)) { + $badge->criteria[BADGE_CRITERIA_TYPE_OVERALL]->mark_complete($userid); + $badge->issue($userid); + } + } + } + } + } + } } diff --git a/badges/tests/badgeslib_test.php b/badges/tests/badgeslib_test.php index fa7b7cb1888..a3b28782d8c 100644 --- a/badges/tests/badgeslib_test.php +++ b/badges/tests/badgeslib_test.php @@ -260,4 +260,23 @@ class core_badgeslib_testcase extends advanced_testcase { $this->assertDebuggingCalled('Error baking badge image!'); $this->assertTrue($badge->is_issued($this->user->id)); } + + /** + * Test badges observer when user_updated event is fired. + */ + public function test_badges_observer_profile_criteria_review() { + $badge = new badge($this->coursebadge); + $this->assertFalse($badge->is_issued($this->user->id)); + + $criteria_overall = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_OVERALL, 'badgeid' => $badge->id)); + $criteria_overall->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ANY)); + $criteria_overall1 = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_PROFILE, 'badgeid' => $badge->id)); + $criteria_overall1->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ALL, 'field_address' => 'address')); + + $this->user->address = 'Test address'; + user_update_user($this->user, false); + // Check if badge is awarded. + $this->assertDebuggingCalled('Error baking badge image!'); + $this->assertTrue($badge->is_issued($this->user->id)); + } } diff --git a/enrol/manual/locallib.php b/enrol/manual/locallib.php index 5c3e3459361..a4f7a00807b 100644 --- a/enrol/manual/locallib.php +++ b/enrol/manual/locallib.php @@ -257,7 +257,17 @@ class enrol_manual_editselectedusers_operation extends enrol_bulk_enrolment_oper foreach ($user->enrolments as $enrolment) { $enrolment->courseid = $enrolment->enrolmentinstance->courseid; $enrolment->enrol = 'manual'; - events_trigger('user_enrol_modified', $enrolment); + // Trigger event. + $event = \core\event\user_enrolment_updated::create( + array( + 'objectid' => $enrolment->id, + 'courseid' => $enrolment->courseid, + 'context' => context_course::instance($enrolment->courseid), + 'relateduserid' => $user->id, + 'other' => array('enrol' => 'manual') + ) + ); + $event->trigger(); } } return true; diff --git a/enrol/meta/classes/observer.php b/enrol/meta/classes/observer.php new file mode 100644 index 00000000000..625d23296fb --- /dev/null +++ b/enrol/meta/classes/observer.php @@ -0,0 +1,102 @@ +. + +/** + * Event observer for meta enrolment plugin. + * + * @package enrol_meta + * @copyright 2013 Rajesh Taneja + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +require_once($CFG->dirroot.'/enrol/meta/locallib.php'); + +/** + * Event observer for enrol_meta. + * + * @package enrol_meta + * @copyright 2013 Rajesh Taneja + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class enrol_meta_observer extends enrol_meta_handler { + + /** + * Triggered via user_enrolment_created event. + * + * @param \core\event\user_enrolment_created $event + * @return bool true on success. + */ + public static function user_enrolment_created(\core\event\user_enrolment_created $event) { + if (!enrol_is_enabled('meta')) { + // No more enrolments for disabled plugins. + return true; + } + + if ($event->other['enrol'] === 'meta') { + // Prevent circular dependencies - we can not sync meta enrolments recursively. + return true; + } + + self::sync_course_instances($event->courseid, $event->relateduserid); + return true; + } + + /** + * Triggered via user_enrolment_deleted event. + * + * @param \core\event\user_enrolment_deleted $event + * @return bool true on success. + */ + public static function user_enrolment_deleted(\core\event\user_enrolment_deleted $event) { + if (!enrol_is_enabled('meta')) { + // This is slow, let enrol_meta_sync() deal with disabled plugin. + return true; + } + + if ($event->other['enrol'] === 'meta') { + // Prevent circular dependencies - we can not sync meta enrolments recursively. + return true; + } + + self::sync_course_instances($event->courseid, $event->relateduserid); + + return true; + } + + /** + * Triggered via user_enrolment_updated event. + * + * @param \core\event\user_enrolment_updated $event + * @return bool true on success + */ + public static function user_enrolment_updated(\core\event\user_enrolment_updated $event) { + if (!enrol_is_enabled('meta')) { + // No modifications if plugin disabled. + return true; + } + + if ($event->other['enrol'] === 'meta') { + // Prevent circular dependencies - we can not sync meta enrolments recursively. + return true; + } + + self::sync_course_instances($event->courseid, $event->relateduserid); + + return true; + } +} diff --git a/enrol/meta/db/events.php b/enrol/meta/db/events.php index c1a2d70ecdd..08c962584e6 100644 --- a/enrol/meta/db/events.php +++ b/enrol/meta/db/events.php @@ -41,27 +41,6 @@ $handlers = array ( 'internal' => 1, ), - 'user_enrolled' => array ( - 'handlerfile' => '/enrol/meta/locallib.php', - 'handlerfunction' => array('enrol_meta_handler', 'user_enrolled'), - 'schedule' => 'instant', - 'internal' => 1, - ), - - 'user_unenrolled' => array ( - 'handlerfile' => '/enrol/meta/locallib.php', - 'handlerfunction' => array('enrol_meta_handler', 'user_unenrolled'), - 'schedule' => 'instant', - 'internal' => 1, - ), - - 'user_enrol_modified' => array ( - 'handlerfile' => '/enrol/meta/locallib.php', - 'handlerfunction' => array('enrol_meta_handler', 'user_enrol_modified'), - 'schedule' => 'instant', - 'internal' => 1, - ), - 'course_deleted' => array ( 'handlerfile' => '/enrol/meta/locallib.php', 'handlerfunction' => array('enrol_meta_handler', 'course_deleted'), @@ -69,3 +48,20 @@ $handlers = array ( 'internal' => 1, ), ); + +// List of observers. +$observers = array( + + array( + 'eventname' => '\core\event\user_enrolment_created', + 'callback' => 'enrol_meta_observer::user_enrolment_created', + ), + array( + 'eventname' => '\core\event\user_enrolment_deleted', + 'callback' => 'enrol_meta_observer::user_enrolment_deleted', + ), + array( + 'eventname' => '\core\event\user_enrolment_updated', + 'callback' => 'enrol_meta_observer::user_enrolment_updated', + ), +); diff --git a/enrol/meta/locallib.php b/enrol/meta/locallib.php index 3a3c26bda1f..c20bfafe54e 100644 --- a/enrol/meta/locallib.php +++ b/enrol/meta/locallib.php @@ -293,72 +293,6 @@ class enrol_meta_handler { return true; } - /** - * Triggered via user enrolled event. - * @static - * @param stdClass $ue - * @return bool success - */ - public static function user_enrolled($ue) { - if (!enrol_is_enabled('meta')) { - // no more enrolments for disabled plugins - return true; - } - - if ($ue->enrol === 'meta') { - // prevent circular dependencies - we can not sync meta enrolments recursively - return true; - } - - self::sync_course_instances($ue->courseid, $ue->userid); - - return true; - } - - /** - * Triggered via user unenrolled event. - * @static - * @param stdClass $ue - * @return bool success - */ - public static function user_unenrolled($ue) { - if (!enrol_is_enabled('meta')) { - // This is slow, let enrol_meta_sync() deal with disabled plugin. - return true; - } - - if ($ue->enrol === 'meta') { - // prevent circular dependencies - we can not sync meta enrolments recursively - return true; - } - - self::sync_course_instances($ue->courseid, $ue->userid); - - return true; - } - - /** - * Triggered via user enrolment modification event. - * @static - * @param stdClass $ue - * @return bool success - */ - public static function user_enrol_modified($ue) { - if (!enrol_is_enabled('meta')) { - // no modifications if plugin disabled - return true; - } - - if ($ue->enrol === 'meta') { - // prevent circular dependencies - we can not sync meta enrolments recursively - return true; - } - - self::sync_course_instances($ue->courseid, $ue->userid); - - return true; - } - /** * Triggered via course_deleted event. * @static diff --git a/enrol/meta/tests/plugin_test.php b/enrol/meta/tests/plugin_test.php index fdfec33e961..05cb522847b 100644 --- a/enrol/meta/tests/plugin_test.php +++ b/enrol/meta/tests/plugin_test.php @@ -439,4 +439,112 @@ class enrol_meta_plugin_testcase extends advanced_testcase { delete_course($course4, false); } + + /** + * Test user_enrolment_created event. + */ + public function test_user_enrolment_created_observer() { + global $DB; + + $this->resetAfterTest(); + + $metaplugin = enrol_get_plugin('meta'); + $user1 = $this->getDataGenerator()->create_user(); + $course1 = $this->getDataGenerator()->create_course(); + $course2 = $this->getDataGenerator()->create_course(); + $student = $DB->get_record('role', array('shortname' => 'student')); + + $e1 = $metaplugin->add_instance($course2, array('customint1' => $course1->id)); + $enrol1 = $DB->get_record('enrol', array('id' => $e1)); + + // Enrol user and capture event. + $sink = $this->redirectEvents(); + + $metaplugin->enrol_user($enrol1, $user1->id, $student->id); + $events = $sink->get_events(); + $sink->close(); + $event = array_shift($events); + + // Test Event. + $dbuserenrolled = $DB->get_record('user_enrolments', array('userid' => $user1->id)); + $this->assertInstanceOf('\core\event\user_enrolment_created', $event); + $this->assertEquals($dbuserenrolled->id, $event->objectid); + $this->assertEquals('user_enrolled', $event->get_legacy_eventname()); + $expectedlegacyeventdata = $dbuserenrolled; + $expectedlegacyeventdata->enrol = 'meta'; + $expectedlegacyeventdata->courseid = $course2->id; + $this->assertEventLegacyData($expectedlegacyeventdata, $event); + } + + /** + * Test user_enrolment_deleted observer. + */ + public function test_user_enrolment_deleted_observer() { + global $DB; + + $this->resetAfterTest(true); + + $metalplugin = enrol_get_plugin('meta'); + $user1 = $this->getDataGenerator()->create_user(); + $course1 = $this->getDataGenerator()->create_course(); + $course2 = $this->getDataGenerator()->create_course(); + $student = $DB->get_record('role', array('shortname'=>'student')); + + $e1 = $metalplugin->add_instance($course2, array('customint1' => $course1->id)); + $enrol1 = $DB->get_record('enrol', array('id' => $e1)); + + // Enrol user. + $metalplugin->enrol_user($enrol1, $user1->id, $student->id); + $this->assertEquals(1, $DB->count_records('user_enrolments')); + + // Unenrol user and capture event. + $sink = $this->redirectEvents(); + $metalplugin->unenrol_user($enrol1, $user1->id); + $events = $sink->get_events(); + $sink->close(); + $event = array_pop($events); + + $this->assertEquals(0, $DB->count_records('user_enrolments')); + $this->assertInstanceOf('\core\event\user_enrolment_deleted', $event); + $this->assertEquals('user_unenrolled', $event->get_legacy_eventname()); + } + + /** + * Test user_enrolment_updated event. + */ + public function test_user_enrolment_updated_observer() { + global $DB; + + $this->resetAfterTest(true); + + $metalplugin = enrol_get_plugin('meta'); + $user1 = $this->getDataGenerator()->create_user(); + $course1 = $this->getDataGenerator()->create_course(); + $course2 = $this->getDataGenerator()->create_course(); + $student = $DB->get_record('role', array('shortname'=>'student')); + + $e1 = $metalplugin->add_instance($course2, array('customint1' => $course1->id)); + $enrol1 = $DB->get_record('enrol', array('id' => $e1)); + + // Enrol user. + $metalplugin->enrol_user($enrol1, $user1->id, $student->id); + $this->assertEquals(1, $DB->count_records('user_enrolments')); + + // Updated enrolment for user and capture event. + $sink = $this->redirectEvents(); + $metalplugin->update_user_enrol($enrol1, $user1->id, ENROL_USER_SUSPENDED, null, time()); + $events = $sink->get_events(); + $sink->close(); + $event = array_shift($events); + + // Test Event. + $dbuserenrolled = $DB->get_record('user_enrolments', array('userid' => $user1->id)); + $this->assertInstanceOf('\core\event\user_enrolment_updated', $event); + $this->assertEquals($dbuserenrolled->id, $event->objectid); + $this->assertEquals('user_enrol_modified', $event->get_legacy_eventname()); + $expectedlegacyeventdata = $dbuserenrolled; + $expectedlegacyeventdata->enrol = 'meta'; + $expectedlegacyeventdata->courseid = $course2->id; + $this->assertEventLegacyData($expectedlegacyeventdata, $event); + } } diff --git a/enrol/tests/enrollib_test.php b/enrol/tests/enrollib_test.php index cba40a8c338..bbdc3bcb35a 100644 --- a/enrol/tests/enrollib_test.php +++ b/enrol/tests/enrollib_test.php @@ -279,4 +279,41 @@ class core_enrollib_testcase extends advanced_testcase { // It should be course 1. $this->assertEquals($sharedcourse->id, $course1->id); } + + /** + * Test user enrolment created event. + */ + public function test_user_enrolment_created_event() { + global $DB; + + $this->resetAfterTest(); + + $studentrole = $DB->get_record('role', array('shortname'=>'student')); + $this->assertNotEmpty($studentrole); + + $admin = get_admin(); + + $course1 = $this->getDataGenerator()->create_course(); + + $maninstance1 = $DB->get_record('enrol', array('courseid'=>$course1->id, 'enrol'=>'manual'), '*', MUST_EXIST); + + $manual = enrol_get_plugin('manual'); + $this->assertNotEmpty($manual); + + // Enrol user and capture event. + $sink = $this->redirectEvents(); + $manual->enrol_user($maninstance1, $admin->id, $studentrole->id); + $events = $sink->get_events(); + $sink->close(); + $event = array_shift($events); + + $dbuserenrolled = $DB->get_record('user_enrolments', array('userid' => $admin->id)); + $this->assertInstanceOf('\core\event\user_enrolment_created', $event); + $this->assertEquals($dbuserenrolled->id, $event->objectid); + $this->assertEquals('user_enrolled', $event->get_legacy_eventname()); + $expectedlegacyeventdata = $dbuserenrolled; + $expectedlegacyeventdata->enrol = $manual->get_name(); + $expectedlegacyeventdata->courseid = $course1->id; + $this->assertEventLegacyData($expectedlegacyeventdata, $event); + } } diff --git a/lang/en/enrol.php b/lang/en/enrol.php index 2beaab14481..50c6573e122 100644 --- a/lang/en/enrol.php +++ b/lang/en/enrol.php @@ -69,6 +69,9 @@ $string['errorenrolcohort'] = 'Error creating cohort sync enrolment instance in $string['errorenrolcohortusers'] = 'Error enrolling cohort members in this course.'; $string['errorthresholdlow'] = 'Notification threshold must be at least 1 day.'; $string['errorwithbulkoperation'] = 'There was an error while processing your bulk enrolment change.'; +$string['eventuserenrolmentcreated'] = 'User enrolled in course'; +$string['eventuserenrolmentdeleted'] = 'User unenrolled from course'; +$string['eventuserenrolmentupdated'] = 'User unenrolment updated'; $string['expirynotify'] = 'Notify before enrolment expires'; $string['expirynotify_help'] = 'This setting determines whether enrolment expiry notification messages are sent.'; $string['expirynotifyall'] = 'Enroller and enrolled user'; diff --git a/lang/en/moodle.php b/lang/en/moodle.php index 10c69f55b90..ac711e304f5 100644 --- a/lang/en/moodle.php +++ b/lang/en/moodle.php @@ -667,6 +667,10 @@ $string['eventcoursedeleted'] = 'Course deleted'; $string['eventcourserestored'] = 'Course restored'; $string['eventcourseupdated'] = 'Course updated'; $string['eventcoursesectionupdated'] = ' Course section updated'; +$string['eventusercreated'] = 'User created'; +$string['eventuserdeleted'] = 'User deleted'; +$string['eventuserloggedout'] = 'User logged out'; +$string['eventuserupdated'] = 'User updated'; $string['everybody'] = 'Everybody'; $string['executeat'] = 'Execute at'; $string['existing'] = 'Existing'; diff --git a/lib/badgeslib.php b/lib/badgeslib.php index 4a4b3fb8ab4..061ecd327bc 100644 --- a/lib/badgeslib.php +++ b/lib/badgeslib.php @@ -931,40 +931,6 @@ function badges_add_course_navigation(navigation_node $coursenode, stdClass $cou } } -/** - * Triggered when 'user_updated' event happens. - * - * @param object $eventdata Holds all information about a user. - * @return boolean - */ -function badges_award_handle_profile_criteria_review(stdClass $eventdata) { - global $DB, $CFG; - - if (!empty($CFG->enablebadges)) { - $userid = $eventdata->id; - - if ($rs = $DB->get_records('badge_criteria', array('criteriatype' => BADGE_CRITERIA_TYPE_PROFILE))) { - foreach ($rs as $r) { - $badge = new badge($r->badgeid); - if (!$badge->is_active() || $badge->is_issued($userid)) { - continue; - } - - if ($badge->criteria[BADGE_CRITERIA_TYPE_PROFILE]->review($userid)) { - $badge->criteria[BADGE_CRITERIA_TYPE_PROFILE]->mark_complete($userid); - - if ($badge->criteria[BADGE_CRITERIA_TYPE_OVERALL]->review($userid)) { - $badge->criteria[BADGE_CRITERIA_TYPE_OVERALL]->mark_complete($userid); - $badge->issue($userid); - } - } - } - } - } - - return true; -} - /** * Triggered when badge is manually awarded. * diff --git a/lib/behat/classes/util.php b/lib/behat/classes/util.php index 2ac98ddb8e6..64727ebd7e1 100644 --- a/lib/behat/classes/util.php +++ b/lib/behat/classes/util.php @@ -58,8 +58,8 @@ class behat_util extends testing_util { * @return void */ public static function install_site() { - global $DB; - + global $DB, $CFG; + require_once($CFG->dirroot.'/user/lib.php'); if (!defined('BEHAT_UTIL')) { throw new coding_exception('This method can be only used by Behat CLI tool'); } @@ -82,7 +82,7 @@ class behat_util extends testing_util { $user->lastname = 'User'; $user->city = 'Perth'; $user->country = 'AU'; - $DB->update_record('user', $user); + user_update_user($user, false); // Disable email message processor. $DB->set_field('message_processors', 'enabled', '0', array('name' => 'email')); diff --git a/lib/classes/event/user_created.php b/lib/classes/event/user_created.php new file mode 100644 index 00000000000..892efd536a4 --- /dev/null +++ b/lib/classes/event/user_created.php @@ -0,0 +1,99 @@ +. + +/** + * User created event. + * + * @package core + * @copyright 2013 Rajesh Taneja + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +namespace core\event; + +defined('MOODLE_INTERNAL') || die(); + +/** + * Event when new user profile is created. + * + * @package core + * @copyright 2013 Rajesh Taneja + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class user_created extends base { + + /** + * Initialise required event data properties. + */ + protected function init() { + $this->data['objecttable'] = 'user'; + $this->data['crud'] = 'c'; + $this->data['level'] = self::LEVEL_OTHER; + } + + /** + * Returns localised event name. + * + * @return string + */ + public static function get_name() { + return get_string('eventusercreated'); + } + + /** + * Returns non-localised event description with id's for admin use only. + * + * @return string + */ + public function get_description() { + return 'Profile created for user '.$this->objectid; + } + + /** + * Returns relevant URL. + * + * @return \moodle_url + */ + public function get_url() { + return new \moodle_url('/user/view.php', array('id' => $this->objectid)); + } + + /** + * Return name of the legacy event, which is replaced by this event. + * + * @return string legacy event name + */ + public static function get_legacy_eventname() { + return 'user_created'; + } + + /** + * Return user_created legacy event data. + * + * @return \stdClass user data. + */ + protected function get_legacy_eventdata() { + return $this->get_record_snapshot('user', $this->objectid); + } + + /** + * Returns array of parameters to be passed to legacy add_to_log() function. + * + * @return array + */ + protected function get_legacy_logdata() { + return array(SITEID, 'user', 'add', '/view.php?id='.$this->objectid, fullname($this->get_legacy_eventdata())); + } +} diff --git a/lib/classes/event/user_deleted.php b/lib/classes/event/user_deleted.php new file mode 100644 index 00000000000..545d691a9ea --- /dev/null +++ b/lib/classes/event/user_deleted.php @@ -0,0 +1,105 @@ +. + +/** + * User deleted event. + * + * @package core + * @copyright 2013 Rajesh Taneja + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +namespace core\event; + +defined('MOODLE_INTERNAL') || die(); + +/** + * Event when user profile is deleted. + * + * @package core + * @copyright 2013 Rajesh Taneja + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class user_deleted extends base { + + /** + * Initialise required event data properties. + */ + protected function init() { + $this->data['objecttable'] = 'user'; + $this->data['crud'] = 'd'; + $this->data['level'] = self::LEVEL_OTHER; + } + + /** + * Returns localised event name. + * + * @return string + */ + public static function get_name() { + return get_string('eventuserdeleted'); + } + + /** + * Returns non-localised event description with id's for admin use only. + * + * @return string + */ + public function get_description() { + $user = (object)$this->other['user']; + return 'User profile deleted for user '.$user->firstname.' '.$user->lastname.' id ('.$user->id.')'; + } + + /** + * Return name of the legacy event, which is replaced by this event. + * + * @return string legacy event name + */ + public static function get_legacy_eventname() { + return 'user_deleted'; + } + + /** + * Return user_deleted legacy event data. + * + * @return \stdClass user data. + */ + protected function get_legacy_eventdata() { + return (object)$this->other['user']; + } + + /** + * Returns array of parameters to be passed to legacy add_to_log() function. + * + * @return array + */ + protected function get_legacy_logdata() { + $user = (object)$this->other['user']; + return array(SITEID, 'user', 'delete', "view.php?id=$user->id", $user->firstname.' '.$user->lastname); + } + + /** + * Custom validation. + * + * @throws \coding_exception + * @return void + */ + protected function validate_data() { + parent::validate_data(); + if (!isset($this->other['user'])) { + throw new \coding_exception('user must be set in $other.'); + } + } +} diff --git a/lib/classes/event/user_enrolment_created.php b/lib/classes/event/user_enrolment_created.php new file mode 100644 index 00000000000..d45ca6dc108 --- /dev/null +++ b/lib/classes/event/user_enrolment_created.php @@ -0,0 +1,109 @@ +. + +/** + * User enrolment created event. + * + * @package core + * @copyright 2013 Rajesh Taneja + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +namespace core\event; + +defined('MOODLE_INTERNAL') || die(); + +/** + * Event when user is enrolled in a course. + * + * @package core + * @copyright 2013 Rajesh Taneja + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class user_enrolment_created extends base { + + /** + * Initialise required event data properties. + */ + protected function init() { + $this->data['objecttable'] = 'user_enrolments'; + $this->data['crud'] = 'c'; + $this->data['level'] = self::LEVEL_TEACHING; + } + + /** + * Returns localised event name. + * + * @return string + */ + public static function get_name() { + return get_string('eventuserenrolmentcreated', 'core_enrol'); + } + + /** + * Returns non-localised event description with id's for admin use only. + * + * @return string + */ + public function get_description() { + return 'User '.$this->relateduserid. ' is enrolled in course '.$this->courseid.' by user '.$this->userid; + } + + /** + * Returns relevant URL. + * + * @return \moodle_url + */ + public function get_url() { + return new \moodle_url('/enrol/users.php', array('id' => $this->courseid)); + } + + /** + * Return name of the legacy event, which is replaced by this event. + * + * @return string legacy event name + */ + public static function get_legacy_eventname() { + return 'user_enrolled'; + } + + /** + * Return user_enrolled legacy event data. + * + * @return \stdClass + */ + protected function get_legacy_eventdata() { + $legacyeventdata = $this->get_record_snapshot('user_enrolments', $this->objectid); + $legacyeventdata->enrol = $this->other['enrol']; + $legacyeventdata->courseid = $this->courseid; + return $legacyeventdata; + } + + /** + * Custom validation. + * + * @throws \coding_exception + * @return void + */ + protected function validate_data() { + parent::validate_data(); + if (!isset($this->other['enrol'])) { + throw new \coding_exception('Enrolment plugin name must be set in $other.'); + } + if (!isset($this->relateduserid)) { + throw new \coding_exception('Related user id must be set.'); + } + } +} diff --git a/lib/classes/event/user_enrolment_deleted.php b/lib/classes/event/user_enrolment_deleted.php new file mode 100644 index 00000000000..82e523f44a7 --- /dev/null +++ b/lib/classes/event/user_enrolment_deleted.php @@ -0,0 +1,110 @@ +. + +/** + * User enrolment deleted event. + * + * @package core + * @copyright 2013 Rajesh Taneja + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +namespace core\event; + +defined('MOODLE_INTERNAL') || die(); + +/** + * Event when user is unenrolled from a course. + * + * @package core + * @copyright 2013 Rajesh Taneja + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class user_enrolment_deleted extends base { + + /** + * Initialise required event data properties. + */ + protected function init() { + $this->data['objecttable'] = 'user_enrolments'; + $this->data['crud'] = 'd'; + $this->data['level'] = self::LEVEL_TEACHING; + } + + /** + * Returns localised event name. + * + * @return string + */ + public static function get_name() { + return get_string('eventuserenrolmentdeleted', 'core_enrol'); + } + + /** + * Returns non-localised event description with id's for admin use only. + * + * @return string + */ + public function get_description() { + return 'User '.$this->relateduserid. ' is enrolled in course '.$this->courseid.' by user '.$this->userid; + } + + /** + * Returns relevant URL. + * + * @return \moodle_url + */ + public function get_url() { + return new \moodle_url('/enrol/users.php', array('id' => $this->courseid)); + } + + /** + * Return name of the legacy event, which is replaced by this event. + * + * @return string legacy event name + */ + public static function get_legacy_eventname() { + return 'user_unenrolled'; + } + + /** + * Return user_unenrolled legacy event data. + * + * @return \stdClass + */ + protected function get_legacy_eventdata() { + return (object)$this->other['userenrolment']; + } + + + /** + * Custom validation. + * + * @throws \coding_exception + * @return void + */ + protected function validate_data() { + parent::validate_data(); + if (!isset($this->other['userenrolment'])) { + throw new \coding_exception('User enrolment must be set in $other.'); + } + if (!isset($this->other['enrol'])) { + throw new \coding_exception('Enrolment plugin name must be set in $other.'); + } + if (!isset($this->relateduserid)) { + throw new \coding_exception('Related user id must be set.'); + } + } +} diff --git a/lib/classes/event/user_enrolment_updated.php b/lib/classes/event/user_enrolment_updated.php new file mode 100644 index 00000000000..786f5190346 --- /dev/null +++ b/lib/classes/event/user_enrolment_updated.php @@ -0,0 +1,109 @@ +. + +/** + * User enrolment updated event. + * + * @package core + * @copyright 2013 Rajesh Taneja + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +namespace core\event; + +defined('MOODLE_INTERNAL') || die(); + +/** + * Event when user enrolment is updated. + * + * @package core + * @copyright 2013 Rajesh Taneja + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class user_enrolment_updated extends base { + + /** + * Initialise required event data properties. + */ + protected function init() { + $this->data['objecttable'] = 'user_enrolments'; + $this->data['crud'] = 'u'; + $this->data['level'] = self::LEVEL_TEACHING; + } + + /** + * Returns localised event name. + * + * @return string + */ + public static function get_name() { + return get_string('eventuserenrolmentupdated', 'core_enrol'); + } + + /** + * Returns non-localised event description with id's for admin use only. + * + * @return string + */ + public function get_description() { + return 'User '.$this->relateduserid. ' has updated enrolment for user '.$this->userid.' in course '.$this->courseid; + } + + /** + * Returns relevant URL. + * + * @return \moodle_url + */ + public function get_url() { + return new \moodle_url('/enrol/users.php', array('id' => $this->courseid)); + } + + /** + * Return name of the legacy event, which is replaced by this event. + * + * @return string legacy event name + */ + public static function get_legacy_eventname() { + return 'user_enrol_modified'; + } + + /** + * Return user_enrol_modified legacy event data. + * + * @return \stdClass + */ + protected function get_legacy_eventdata() { + $legacyeventdata = $this->get_record_snapshot('user_enrolments', $this->objectid); + $legacyeventdata->enrol = $this->other['enrol']; + $legacyeventdata->courseid = $this->courseid; + return $legacyeventdata; + } + + /** + * Custom validation. + * + * @throws \coding_exception + * @return void + */ + protected function validate_data() { + parent::validate_data(); + if (!isset($this->other['enrol'])) { + throw new \coding_exception('Enrolment plugin name must be set in $other.'); + } + if (!isset($this->relateduserid)) { + throw new \coding_exception('Related user id must be set.'); + } + } +} diff --git a/lib/classes/event/user_loggedout.php b/lib/classes/event/user_loggedout.php new file mode 100644 index 00000000000..f881b471884 --- /dev/null +++ b/lib/classes/event/user_loggedout.php @@ -0,0 +1,100 @@ +. + +/** + * User logout event. + * + * @package core + * @copyright 2013 Rajesh Taneja + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +namespace core\event; + +defined('MOODLE_INTERNAL') || die(); + +/** + * Event when user logout. + * + * @package core + * @copyright 2013 Rajesh Taneja + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class user_loggedout extends base { + + /** + * Initialise required event data properties. + */ + protected function init() { + $this->data['objecttable'] = 'user'; + $this->data['crud'] = 'r'; + $this->data['level'] = self::LEVEL_OTHER; + } + + /** + * Returns localised event name. + * + * @return string + */ + public static function get_name() { + return get_string('eventuserloggedout'); + } + + /** + * Returns non-localised event description with id's for admin use only. + * + * @return string + */ + public function get_description() { + return 'User '.$this->objectid.' logged out.'; + } + + /** + * Returns relevant URL. + * + * @return \moodle_url + */ + public function get_url() { + return new \moodle_url('/user/view.php', array('id' => $this->objectid)); + } + + /** + * Return name of the legacy event, which is replaced by this event. + * + * @return string legacy event name + */ + public static function get_legacy_eventname() { + return 'user_logout'; + } + + /** + * Return user_logout legacy event data. + * + * @return \stdClass user data. + */ + protected function get_legacy_eventdata() { + return $this->get_record_snapshot('user', $this->objectid); + } + + /** + * Returns array of parameters to be passed to legacy add_to_log() function. + * + * @return array + */ + protected function get_legacy_logdata() { + return array(SITEID, 'user', 'logout', 'view.php?id='.$this->objectid.'&course='.SITEID, $this->objectid, 0, + $this->objectid); + } +} diff --git a/lib/classes/event/user_updated.php b/lib/classes/event/user_updated.php new file mode 100644 index 00000000000..005ee407936 --- /dev/null +++ b/lib/classes/event/user_updated.php @@ -0,0 +1,99 @@ +. + +/** + * User updated event. + * + * @package core + * @copyright 2013 Rajesh Taneja + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +namespace core\event; + +defined('MOODLE_INTERNAL') || die(); + +/** + * Event when user profile is updated. + * + * @package core + * @copyright 2013 Rajesh Taneja + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class user_updated extends base { + + /** + * Initialise required event data properties. + */ + protected function init() { + $this->data['objecttable'] = 'user'; + $this->data['crud'] = 'u'; + $this->data['level'] = self::LEVEL_OTHER; + } + + /** + * Returns localised event name. + * + * @return string + */ + public static function get_name() { + return get_string('eventuserupdated'); + } + + /** + * Returns non-localised event description with id's for admin use only. + * + * @return string + */ + public function get_description() { + return 'User profile updated for userid '.$this->objectid; + } + + /** + * Returns relevant URL. + * + * @return \moodle_url + */ + public function get_url() { + return new \moodle_url('/user/view.php', array('id' => $this->objectid)); + } + + /** + * Return name of the legacy event, which is replaced by this event. + * + * @return string legacy event name + */ + public static function get_legacy_eventname() { + return 'user_updated'; + } + + /** + * Return user_updated legacy event data. + * + * @return \stdClass user data. + */ + protected function get_legacy_eventdata () { + return $this->get_record_snapshot('user', $this->objectid); + } + + /** + * Returns array of parameters to be passed to legacy add_to_log() function. + * + * @return array + */ + protected function get_legacy_logdata() { + return array(SITEID, 'user', 'update', 'view.php?id='.$this->objectid, ''); + } +} diff --git a/lib/db/events.php b/lib/db/events.php index b3ba54ac8ed..99e5f32f20e 100644 --- a/lib/db/events.php +++ b/lib/db/events.php @@ -36,14 +36,6 @@ defined('MOODLE_INTERNAL') || die(); /* List of legacy event handlers */ $handlers = array( - - 'user_updated' => array ( - 'handlerfile' => '/lib/badgeslib.php', - 'handlerfunction' => 'badges_award_handle_profile_criteria_review', - 'schedule' => 'instant', - 'internal' => 1, - ), - /* * portfolio queued event - for non interactive file transfers * NOTE: this is a HACK, please do not add any more things like this here @@ -70,6 +62,10 @@ $observers = array( array( 'eventname' => '\core\event\course_completed', 'callback' => 'core_badges_observer::course_criteria_review', + ), + array( + 'eventname' => '\core\event\user_updated', + 'callback' => 'core_badges_observer::profile_criteria_review', ) ); diff --git a/lib/enrollib.php b/lib/enrollib.php index a9741f9824f..1793749ed07 100644 --- a/lib/enrollib.php +++ b/lib/enrollib.php @@ -1276,16 +1276,7 @@ abstract class enrol_plugin { if ($ue = $DB->get_record('user_enrolments', array('enrolid'=>$instance->id, 'userid'=>$userid))) { //only update if timestart or timeend or status are different. if ($ue->timestart != $timestart or $ue->timeend != $timeend or (!is_null($status) and $ue->status != $status)) { - $ue->timestart = $timestart; - $ue->timeend = $timeend; - if (!is_null($status)) { - $ue->status = $status; - } - $ue->modifierid = $USER->id; - $ue->timemodified = time(); - $DB->update_record('user_enrolments', $ue); - - $updated = true; + $this->update_user_enrol($instance, $userid, $status, $timestart, $timeend); } } else { $ue = new stdClass(); @@ -1303,16 +1294,17 @@ abstract class enrol_plugin { } if ($inserted) { - // add extra info and trigger event - $ue->courseid = $courseid; - $ue->enrol = $name; - events_trigger('user_enrolled', $ue); - } else if ($updated) { - $ue->courseid = $courseid; - $ue->enrol = $name; - events_trigger('user_enrol_modified', $ue); - // resets current enrolment caches - $context->mark_dirty(); + // Trigger event. + $event = \core\event\user_enrolment_created::create( + array( + 'objectid' => $ue->id, + 'courseid' => $courseid, + 'context' => $context, + 'relateduserid' => $ue->userid, + 'other' => array('enrol' => $name) + ) + ); + $event->trigger(); } if ($roleid) { @@ -1389,10 +1381,17 @@ abstract class enrol_plugin { $DB->update_record('user_enrolments', $ue); context_course::instance($instance->courseid)->mark_dirty(); // reset enrol caches - // trigger event - $ue->courseid = $instance->courseid; - $ue->enrol = $instance->name; - events_trigger('user_enrol_modified', $ue); + // Trigger event. + $event = \core\event\user_enrolment_updated::create( + array( + 'objectid' => $ue->id, + 'courseid' => $instance->courseid, + 'context' => context_course::instance($instance->courseid), + 'relateduserid' => $ue->userid, + 'other' => array('enrol' => $name) + ) + ); + $event->trigger(); } /** @@ -1440,8 +1439,6 @@ abstract class enrol_plugin { WHERE ue.userid = :userid AND e.courseid = :courseid"; if ($DB->record_exists_sql($sql, array('userid'=>$userid, 'courseid'=>$courseid))) { $ue->lastenrol = false; - events_trigger('user_unenrolled', $ue); - // user still has some enrolments, no big cleanup yet } else { // the big cleanup IS necessary! @@ -1458,9 +1455,20 @@ abstract class enrol_plugin { $DB->delete_records('user_lastaccess', array('userid'=>$userid, 'courseid'=>$courseid)); $ue->lastenrol = true; // means user not enrolled any more - events_trigger('user_unenrolled', $ue); } - + // Trigger event. + $event = \core\event\user_enrolment_deleted::create( + array( + 'courseid' => $courseid, + 'context' => $context, + 'relateduserid' => $ue->userid, + 'other' => array( + 'userenrolment' => (array)$ue, + 'enrol' => $name + ) + ) + ); + $event->trigger(); // reset all enrol caches $context->mark_dirty(); diff --git a/lib/moodlelib.php b/lib/moodlelib.php index abd2e3ebd70..a0fae10295d 100644 --- a/lib/moodlelib.php +++ b/lib/moodlelib.php @@ -3215,11 +3215,7 @@ function require_login($courseorid = null, $autologinguest = true, $cm = null, $ function require_logout() { global $USER; - $params = $USER; - if (isloggedin()) { - add_to_log(SITEID, "user", "logout", "view.php?id=$USER->id&course=".SITEID, $USER->id, 0, $USER->id); - $authsequence = get_enabled_auth_plugins(); // Auths, in sequence. foreach ($authsequence as $authname) { $authplugin = get_auth_plugin($authname); @@ -3227,9 +3223,16 @@ function require_logout() { } } - events_trigger('user_logout', $params); + $event = \core\event\user_loggedout::create( + array( + 'objectid' => $USER->id, + 'context' => context_user::instance($USER->id) + ) + ); + $event->trigger(); + session_get_instance()->terminate_current(); - unset($params); + unset($GLOBALS['USER']); } /** @@ -3442,7 +3445,9 @@ function get_user_key($script, $userid, $instance=null, $iprestriction=null, $va * @return bool Always returns true */ function update_user_login_times() { - global $USER, $DB; + global $USER, $DB, $CFG; + + require_once($CFG->dirroot.'/user/lib.php'); if (isguestuser()) { // Do not update guest access times/ips for performance. @@ -3468,7 +3473,7 @@ function update_user_login_times() { $USER->lastaccess = $user->lastaccess = $now; $USER->lastip = $user->lastip = getremoteaddr(); - $DB->update_record('user', $user); + user_update_user($user, false); return true; } @@ -3967,7 +3972,9 @@ function get_user_fieldnames() { */ function create_user_record($username, $password, $auth = 'manual') { global $CFG, $DB; - require_once($CFG->dirroot."/user/profile/lib.php"); + require_once($CFG->dirroot.'/user/profile/lib.php'); + require_once($CFG->dirroot.'/user/lib.php'); + // Just in case check text case. $username = trim(core_text::strtolower($username)); @@ -4008,7 +4015,7 @@ function create_user_record($username, $password, $auth = 'manual') { $newuser->timemodified = $newuser->timecreated; $newuser->mnethostid = $CFG->mnet_localhost_id; - $newuser->id = $DB->insert_record('user', $newuser); + $newuser->id = user_create_user($newuser, false); // Save user profile data. profile_save_data($newuser); @@ -4020,10 +4027,6 @@ function create_user_record($username, $password, $auth = 'manual') { // Set the password. update_internal_user_password($user, $password); - // Fetch full user record for the event, the complete user data contains too much info - // and we want to be consistent with other places that trigger this event. - events_trigger('user_created', $DB->get_record('user', array('id' => $user->id))); - return $user; } @@ -4036,6 +4039,7 @@ function create_user_record($username, $password, $auth = 'manual') { function update_user_record($username) { global $DB, $CFG; require_once($CFG->dirroot."/user/profile/lib.php"); + require_once($CFG->dirroot.'/user/lib.php'); // Just in case check text case. $username = trim(core_text::strtolower($username)); @@ -4078,14 +4082,10 @@ function update_user_record($username) { if ($newuser) { $newuser['id'] = $oldinfo->id; $newuser['timemodified'] = time(); - $DB->update_record('user', $newuser); + user_update_user((object) $newuser, false); // Save user profile data. profile_save_data((object) $newuser); - - // Fetch full user record for the event, the complete user data contains too much info - // and we want to be consistent with other places that trigger this event. - events_trigger('user_updated', $DB->get_record('user', array('id' => $oldinfo->id))); } } @@ -4143,6 +4143,7 @@ function delete_user(stdClass $user) { require_once($CFG->libdir.'/gradelib.php'); require_once($CFG->dirroot.'/message/lib.php'); require_once($CFG->dirroot.'/tag/lib.php'); + require_once($CFG->dirroot.'/user/lib.php'); // Make sure nobody sends bogus record type as parameter. if (!property_exists($user, 'id') or !property_exists($user, 'username')) { @@ -4169,6 +4170,9 @@ function delete_user(stdClass $user) { return false; } + // Keep a copy of user context, we need it for event. + $usercontext = context_user::instance($user->id); + // Delete all grades - backup is kept in grade_grades_history table. grade_user_delete($user->id); @@ -4218,9 +4222,6 @@ function delete_user(stdClass $user) { // Force logout - may fail if file based sessions used, sorry. session_kill_user($user->id); - // Now do a final accesslib cleanup - removes all role assignments in user context and context itself. - context_helper::delete_instance(CONTEXT_USER, $user->id); - // Workaround for bulk deletes of users with the same email address. $delname = "$user->email.".time(); while ($DB->record_exists('user', array('username' => $delname))) { // No need to use mnethostid here. @@ -4237,9 +4238,22 @@ function delete_user(stdClass $user) { $updateuser->picture = 0; $updateuser->timemodified = time(); - $DB->update_record('user', $updateuser); - // Add this action to log. - add_to_log(SITEID, 'user', 'delete', "view.php?id=$user->id", $user->firstname.' '.$user->lastname); + user_update_user($updateuser, false); + + // Now do a final accesslib cleanup - removes all role assignments in user context and context itself. + context_helper::delete_instance(CONTEXT_USER, $user->id); + + // Any plugin that needs to cleanup should register this event. + // Trigger event. + $event = \core\event\user_deleted::create( + array( + 'objectid' => $user->id, + 'context' => $usercontext, + 'other' => array('user' => (array)clone $user) + ) + ); + $event->add_record_snapshot('user', $updateuser); + $event->trigger(); // We will update the user's timemodified, as it will be passed to the user_deleted event, which // should know about this updated property persisted to the user's table. @@ -4249,9 +4263,6 @@ function delete_user(stdClass $user) { $authplugin = get_auth_plugin($user->auth); $authplugin->user_delete($user); - // Any plugin that needs to cleanup should register this event. - events_trigger('user_deleted', $user); - return true; } diff --git a/lib/tests/moodlelib_test.php b/lib/tests/moodlelib_test.php index 50b1be92d8c..2a70acc1c17 100644 --- a/lib/tests/moodlelib_test.php +++ b/lib/tests/moodlelib_test.php @@ -1851,7 +1851,14 @@ class core_moodlelib_testcase extends advanced_testcase { $user = $this->getDataGenerator()->create_user(array('idnumber'=>'abc')); $user2 = $this->getDataGenerator()->create_user(array('idnumber'=>'xyz')); + // Delete user and capture event. + $sink = $this->redirectEvents(); $result = delete_user($user); + $events = $sink->get_events(); + $sink->close(); + $event = array_pop($events); + + // Test user is deleted in DB. $this->assertTrue($result); $deluser = $DB->get_record('user', array('id'=>$user->id), '*', MUST_EXIST); $this->assertEquals(1, $deluser->deleted); @@ -1862,8 +1869,15 @@ class core_moodlelib_testcase extends advanced_testcase { $this->assertEquals(1, $DB->count_records('user', array('deleted'=>1))); - // Try invalid params. + // Test Event. + $this->assertInstanceOf('\core\event\user_deleted', $event); + $this->assertSame($user->id, $event->objectid); + $this->assertSame('user_deleted', $event->get_legacy_eventname()); + $this->assertEventLegacyData($user, $event); + $expectedlogdata = array(SITEID, 'user', 'delete', "view.php?id=$user->id", $user->firstname.' '.$user->lastname); + $this->assertEventLegacyLogData($expectedlogdata, $event); + // Try invalid params. $record = new stdClass(); $record->grrr = 1; try { @@ -2407,4 +2421,35 @@ class core_moodlelib_testcase extends advanced_testcase { $expectedarray = array('19' => 'second', '38' => 'first', '44' => 'firsthalf'); $this->assertEquals($expectedarray, order_in_string($valuearray, $formatstring)); } + + /** + * Test require_logout. + */ + public function test_require_logout() { + $this->resetAfterTest(); + $user = $this->getDataGenerator()->create_user(); + $this->setUser($user); + $course = $this->getDataGenerator()->create_course(); + + $this->assertTrue(isloggedin()); + + // Logout user and capture event. + $sink = $this->redirectEvents(); + require_logout(); + $events = $sink->get_events(); + $sink->close(); + $event = array_pop($events); + + // Check if user is logged out. + $this->assertFalse(isloggedin()); + + // Test Event. + $this->assertInstanceOf('\core\event\user_loggedout', $event); + $this->assertSame($user->id, $event->objectid); + $this->assertSame('user_logout', $event->get_legacy_eventname()); + $this->assertEventLegacyData($user, $event); + $expectedlogdata = array(SITEID, 'user', 'logout', 'view.php?id='.$event->objectid.'&course='.SITEID, $event->objectid, 0, + $event->objectid); + $this->assertEventLegacyLogData($expectedlogdata, $event); + } } diff --git a/mod/forum/classes/observer.php b/mod/forum/classes/observer.php new file mode 100644 index 00000000000..a41efffc7e9 --- /dev/null +++ b/mod/forum/classes/observer.php @@ -0,0 +1,52 @@ +. + +/** + * Event observers used in forum. + * + * @package mod_forum + * @copyright 2013 Rajesh Taneja + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +/** + * Event observer for mod_forum. + */ +class mod_forum_observer { + /** + * Triggered via user_enrolment_deleted event. + * + * @param \core\event\user_enrolment_deleted $event + */ + public static function user_enrolment_deleted(\core\event\user_enrolment_deleted $event) { + global $DB; + + // NOTE: this has to be as fast as possible. + // Get user enrolment info from event. + $cp = (object)$event->other['userenrolment']; + if ($cp->lastenrol) { + $params = array('userid' => $cp->userid, 'courseid' => $cp->courseid); + $forumselect = "IN (SELECT f.id FROM {forum} f WHERE f.course = :courseid)"; + + $DB->delete_records_select('forum_digests', 'userid = :userid AND forum '.$forumselect, $params); + $DB->delete_records_select('forum_subscriptions', 'userid = :userid AND forum '.$forumselect, $params); + $DB->delete_records_select('forum_track_prefs', 'userid = :userid AND forumid '.$forumselect, $params); + $DB->delete_records_select('forum_read', 'userid = :userid AND forumid '.$forumselect, $params); + } + } +} diff --git a/mod/forum/db/events.php b/mod/forum/db/events.php index ded6583575d..5421b5aa0aa 100644 --- a/mod/forum/db/events.php +++ b/mod/forum/db/events.php @@ -31,11 +31,13 @@ $handlers = array ( 'schedule' => 'instant', 'internal' => 1, ), +); - 'user_unenrolled' => array ( - 'handlerfile' => '/mod/forum/lib.php', - 'handlerfunction' => 'forum_user_unenrolled', - 'schedule' => 'instant', - 'internal' => 1, +// List of observers. +$observers = array( + + array( + 'eventname' => '\core\event\user_enrolment_deleted', + 'callback' => 'mod_forum_observer::user_enrolment_deleted', ), ); diff --git a/mod/forum/lib.php b/mod/forum/lib.php index 917bb8ab03c..be0a2eae793 100644 --- a/mod/forum/lib.php +++ b/mod/forum/lib.php @@ -6289,28 +6289,6 @@ function forum_user_role_assigned($cp) { } } -/** - * This function gets run whenever user is unenrolled from course - * - * @param stdClass $cp - * @return void - */ -function forum_user_unenrolled($cp) { - global $DB; - - // NOTE: this has to be as fast as possible! - - if ($cp->lastenrol) { - $params = array('userid'=>$cp->userid, 'courseid'=>$cp->courseid); - $forumselect = "IN (SELECT f.id FROM {forum} f WHERE f.course = :courseid)"; - - $DB->delete_records_select('forum_digests', "userid = :userid AND forum $forumselect", $params); - $DB->delete_records_select('forum_subscriptions', "userid = :userid AND forum $forumselect", $params); - $DB->delete_records_select('forum_track_prefs', "userid = :userid AND forumid $forumselect", $params); - $DB->delete_records_select('forum_read', "userid = :userid AND forumid $forumselect", $params); - } -} - // Functions to do with read tracking. /** diff --git a/mod/forum/tests/lib_test.php b/mod/forum/tests/lib_test.php index 90de8753058..d5bfb7a8f07 100644 --- a/mod/forum/tests/lib_test.php +++ b/mod/forum/tests/lib_test.php @@ -168,4 +168,37 @@ class mod_forum_lib_testcase extends advanced_testcase { $this->assertContains($course->shortname, array($course1->shortname, $course2->shortname)); } } + + /** + * Test user_enrolment_deleted observer. + */ + public function test_user_enrolment_deleted_observer() { + global $DB; + + $this->resetAfterTest(); + + $metaplugin = enrol_get_plugin('meta'); + $user1 = $this->getDataGenerator()->create_user(); + $course1 = $this->getDataGenerator()->create_course(); + $course2 = $this->getDataGenerator()->create_course(); + $student = $DB->get_record('role', array('shortname'=>'student')); + + $e1 = $metaplugin->add_instance($course2, array('customint1' => $course1->id)); + $enrol1 = $DB->get_record('enrol', array('id' => $e1)); + + // Enrol user. + $metaplugin->enrol_user($enrol1, $user1->id, $student->id); + $this->assertEquals(1, $DB->count_records('user_enrolments')); + + // Unenrol user and capture event. + $sink = $this->redirectEvents(); + $metaplugin->unenrol_user($enrol1, $user1->id); + $events = $sink->get_events(); + $sink->close(); + $event = array_pop($events); + + $this->assertEquals(0, $DB->count_records('user_enrolments')); + $this->assertInstanceOf('\core\event\user_enrolment_deleted', $event); + $this->assertEquals('user_unenrolled', $event->get_legacy_eventname()); + } } diff --git a/user/edit.php b/user/edit.php index 49758e2df54..821ba4df5c1 100644 --- a/user/edit.php +++ b/user/edit.php @@ -28,6 +28,7 @@ require_once($CFG->libdir.'/gdlib.php'); require_once($CFG->dirroot.'/user/edit_form.php'); require_once($CFG->dirroot.'/user/editlib.php'); require_once($CFG->dirroot.'/user/profile/lib.php'); +require_once($CFG->dirroot.'/user/lib.php'); //HTTPS is required in this page when $CFG->loginhttps enabled $PAGE->https_required(); @@ -177,8 +178,6 @@ $email_changed = false; if ($usernew = $userform->get_data()) { - add_to_log($course->id, 'user', 'update', "view.php?id=$user->id&course=$course->id", ''); - $email_changed_html = ''; if ($CFG->emailchangeconfirmation) { @@ -206,15 +205,15 @@ if ($usernew = $userform->get_data()) { $usernew = file_postupdate_standard_editor($usernew, 'description', $editoroptions, $personalcontext, 'user', 'profile', 0); } - $DB->update_record('user', $usernew); - - // pass a true $userold here - if (! $authplugin->user_update($user, $usernew)) { - // auth update failed, rollback for moodle - $DB->update_record('user', $user); + // Pass a true old $user here. + if (!$authplugin->user_update($user, $usernew)) { + // Auth update failed. print_error('cannotupdateprofile'); } + // Update user with new profile data. + user_update_user($usernew, false); + //update preferences useredit_update_user_preference($usernew); @@ -259,7 +258,6 @@ if ($usernew = $userform->get_data()) { // reload from db $usernew = $DB->get_record('user', array('id'=>$user->id)); - events_trigger('user_updated', $usernew); if ($USER->id == $user->id) { // Override old $USER session variable if needed diff --git a/user/editadvanced.php b/user/editadvanced.php index 94099377894..9728bbdcc81 100644 --- a/user/editadvanced.php +++ b/user/editadvanced.php @@ -29,6 +29,7 @@ require_once($CFG->libdir.'/adminlib.php'); require_once($CFG->dirroot.'/user/editadvanced_form.php'); require_once($CFG->dirroot.'/user/editlib.php'); require_once($CFG->dirroot.'/user/profile/lib.php'); +require_once($CFG->dirroot.'/user/lib.php'); //HTTPS is required in this page when $CFG->loginhttps enabled $PAGE->https_required(); @@ -177,20 +178,15 @@ if ($usernew = $userform->get_data()) { } else { $usernew->password = hash_internal_user_password($usernew->newpassword); } - $usernew->id = $DB->insert_record('user', $usernew); - $usercreated = true; - add_to_log($course->id, 'user', 'add', "view.php?id=$usernew->id&course=$course->id", ''); - + $usernew->id = user_create_user($usernew, false); } else { $usernew = file_postupdate_standard_editor($usernew, 'description', $editoroptions, $usercontext, 'user', 'profile', 0); - $DB->update_record('user', $usernew); - // pass a true $userold here - if (! $authplugin->user_update($user, $userform->get_data())) { - // auth update failed, rollback for moodle - $DB->update_record('user', $user); + // Pass a true old $user here. + if (!$authplugin->user_update($user, $usernew)) { + // Auth update failed. print_error('cannotupdateuseronexauth', '', '', $user->auth); } - add_to_log($course->id, 'user', 'update', "view.php?id=$user->id&course=$course->id", ''); + user_update_user($usernew, false); //set new password if specified if (!empty($usernew->newpassword)) { @@ -206,8 +202,6 @@ if ($usernew = $userform->get_data()) { if (isset($usernew->suspended) and $usernew->suspended and !$user->suspended) { session_kill_user($user->id); } - - $usercreated = false; } $usercontext = context_user::instance($usernew->id); @@ -237,13 +231,6 @@ if ($usernew = $userform->get_data()) { // reload from db $usernew = $DB->get_record('user', array('id'=>$usernew->id)); - // trigger events - if ($usercreated) { - events_trigger('user_created', $usernew); - } else { - events_trigger('user_updated', $usernew); - } - if ($createpassword) { setnew_password_and_mail($usernew); unset_user_preference('create_password', $usernew); diff --git a/user/emailupdate.php b/user/emailupdate.php index 0aee6c87584..256af0f5993 100644 --- a/user/emailupdate.php +++ b/user/emailupdate.php @@ -26,6 +26,7 @@ require_once('../config.php'); require_once($CFG->libdir.'/adminlib.php'); require_once($CFG->dirroot.'/user/editlib.php'); +require_once($CFG->dirroot.'/user/lib.php'); $key = required_param('key', PARAM_ALPHANUM); $id = required_param('id', PARAM_INT); @@ -60,17 +61,16 @@ if (empty($preferences['newemailattemptsleft'])) { cancel_email_update($user->id); $user->email = $preferences['newemail']; - // Detect duplicate before saving + // Detect duplicate before saving. if ($DB->get_record('user', array('email' => $user->email))) { $stremailnowexists = get_string('emailnowexists', 'auth'); echo $OUTPUT->box($stremailnowexists, 'center'); echo $OUTPUT->continue_button("$CFG->wwwroot/user/view.php?id=$user->id"); } else { - // update user email - $DB->set_field('user', 'email', $user->email, array('id' => $user->id)); + // Update user email. $authplugin = get_auth_plugin($user->auth); $authplugin->user_update($olduser, $user); - events_trigger('user_updated', $user); + user_update_user($user, false); $a->email = $user->email; $stremailupdatesuccess = get_string('emailupdatesuccess', 'auth', $a); echo $OUTPUT->box($stremailupdatesuccess, 'center'); diff --git a/user/lib.php b/user/lib.php index 737a98a359b..7ab6c0d2ab5 100644 --- a/user/lib.php +++ b/user/lib.php @@ -28,18 +28,19 @@ /** * Creates a user * - * @param object $user user to create + * @param stdClass $user user to create + * @param bool $updatepassword if true, authentication plugin will update password. * @return int id of the newly created user */ -function user_create_user($user) { +function user_create_user($user, $updatepassword = true) { global $DB; - // set the timecreate field to the current time + // Set the timecreate field to the current time. if (!is_object($user)) { $user = (object)$user; } - //check username + // Check username. if ($user->username !== core_text::strtolower($user->username)) { throw new moodle_exception('usernamelowercase'); } else { @@ -48,10 +49,10 @@ function user_create_user($user) { } } - // save the password in a temp value for later - if (isset($user->password)) { + // Save the password in a temp value for later. + if ($updatepassword && isset($user->password)) { - //check password toward the password policy + // Check password toward the password policy. if (!check_password_policy($user->password, $errmsg)) { throw new moodle_exception($errmsg); } @@ -63,36 +64,39 @@ function user_create_user($user) { $user->timecreated = time(); $user->timemodified = $user->timecreated; - // insert the user into the database + // Insert the user into the database. $newuserid = $DB->insert_record('user', $user); - // trigger user_created event on the full database user row - $newuser = $DB->get_record('user', array('id' => $newuserid)); + // Create USER context for this user. + $usercontext = context_user::instance($newuserid); - // create USER context for this user - context_user::instance($newuserid); - - // update user password if necessary + // Update user password if necessary. if (isset($userpassword)) { + // Get full database user row, in case auth is default. + $newuser = $DB->get_record('user', array('id' => $newuserid)); $authplugin = get_auth_plugin($newuser->auth); $authplugin->user_update_password($newuser, $userpassword); } - events_trigger('user_created', $newuser); - - add_to_log(SITEID, 'user', get_string('create'), '/view.php?id='.$newuser->id, - fullname($newuser)); + // Trigger event. + $event = \core\event\user_created::create( + array( + 'objectid' => $newuserid, + 'context' => $usercontext + ) + ); + $event->trigger(); return $newuserid; - } /** * Update a user with a user object (will compare against the ID) * - * @param object $user the user to update + * @param stdClass $user the user to update + * @param bool $updatepassword if true, authentication plugin will update password. */ -function user_update_user($user) { +function user_update_user($user, $updatepassword = true) { global $DB; // set the timecreate field to the current time @@ -111,8 +115,8 @@ function user_update_user($user) { } } - // unset password here, for updating later - if (isset($user->password)) { + // Unset password here, for updating later, if password update is required. + if ($updatepassword && isset($user->password)) { //check password toward the password policy if (!check_password_policy($user->password, $errmsg)) { @@ -126,22 +130,27 @@ function user_update_user($user) { $user->timemodified = time(); $DB->update_record('user', $user); - // trigger user_updated event on the full database user row - $updateduser = $DB->get_record('user', array('id' => $user->id)); + if ($updatepassword) { + // Get full user record. + $updateduser = $DB->get_record('user', array('id' => $user->id)); - // if password was set, then update its hash - if (isset($passwd)) { - $authplugin = get_auth_plugin($updateduser->auth); - if ($authplugin->can_change_password()) { - $authplugin->user_update_password($updateduser, $passwd); + // if password was set, then update its hash + if (isset($passwd)) { + $authplugin = get_auth_plugin($updateduser->auth); + if ($authplugin->can_change_password()) { + $authplugin->user_update_password($updateduser, $passwd); + } } } - events_trigger('user_updated', $updateduser); - - add_to_log(SITEID, 'user', get_string('update'), '/view.php?id='.$updateduser->id, - fullname($updateduser)); - + // Trigger event. + $event = \core\event\user_updated::create( + array( + 'objectid' => $user->id, + 'context' => context_user::instance($user->id) + ) + ); + $event->trigger(); } /** diff --git a/user/tests/userlib_test.php b/user/tests/userlib_test.php new file mode 100644 index 00000000000..9959d0fe49d --- /dev/null +++ b/user/tests/userlib_test.php @@ -0,0 +1,132 @@ +. + +/** + * Unit tests for user/lib.php. + * + * @package core_user + * @category phpunit + * @copyright 2013 Rajesh Taneja + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +global $CFG; +require_once($CFG->dirroot.'/user/lib.php'); + +/** + * Unit tests for user lib api. + * + * @package core_user + * @category phpunit + * @copyright 2013 Rajesh Taneja + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class core_userliblib_testcase extends advanced_testcase { + /** + * Test user_update_user. + */ + public function test_user_update_user() { + global $DB; + + $this->resetAfterTest(); + + // Create user and modify user profile. + $user = $this->getDataGenerator()->create_user(); + $user->firstname = 'Test'; + $user->password = 'M00dLe@T'; + + // Update user and capture event. + $sink = $this->redirectEvents(); + user_update_user($user); + $events = $sink->get_events(); + $sink->close(); + $event = array_pop($events); + + // Test updated value. + $dbuser = $DB->get_record('user', array('id' => $user->id)); + $this->assertSame($user->firstname, $dbuser->firstname); + $this->assertNotSame('M00dLe@T', $dbuser->password); + + // Test event. + $this->assertInstanceOf('\core\event\user_updated', $event); + $this->assertSame($user->id, $event->objectid); + $this->assertSame('user_updated', $event->get_legacy_eventname()); + $this->assertEventLegacyData($dbuser, $event); + $this->assertEquals(context_user::instance($user->id), $event->get_context()); + $expectedlogdata = array(SITEID, 'user', 'update', 'view.php?id='.$user->id, ''); + $this->assertEventLegacyLogData($expectedlogdata, $event); + + // Update user with no password update. + $password = $user->password = hash_internal_user_password('M00dLe@T'); + user_update_user($user, false); + $dbuser = $DB->get_record('user', array('id' => $user->id)); + $this->assertSame($password, $dbuser->password); + } + + /** + * Test create_users. + */ + public function test_create_users() { + global $DB; + + $this->resetAfterTest(); + + $user = array( + 'username' => 'usernametest1', + 'password' => 'Moodle2012!', + 'idnumber' => 'idnumbertest1', + 'firstname' => 'First Name User Test 1', + 'lastname' => 'Last Name User Test 1', + 'middlename' => 'Middle Name User Test 1', + 'lastnamephonetic' => '最後のお名前のテスト一号', + 'firstnamephonetic' => 'お名前のテスト一号', + 'alternatename' => 'Alternate Name User Test 1', + 'email' => 'usertest1@email.com', + 'description' => 'This is a description for user 1', + 'city' => 'Perth', + 'country' => 'au' + ); + + // Create user and capture event. + $sink = $this->redirectEvents(); + $user['id'] = user_create_user($user); + $events = $sink->get_events(); + $sink->close(); + $event = array_pop($events); + + // Test user info in DB. + $dbuser = $DB->get_record('user', array('id' => $user['id'])); + $this->assertEquals($dbuser->username, $user['username']); + $this->assertEquals($dbuser->idnumber, $user['idnumber']); + $this->assertEquals($dbuser->firstname, $user['firstname']); + $this->assertEquals($dbuser->lastname, $user['lastname']); + $this->assertEquals($dbuser->email, $user['email']); + $this->assertEquals($dbuser->description, $user['description']); + $this->assertEquals($dbuser->city, $user['city']); + $this->assertEquals($dbuser->country, $user['country']); + + // Test event. + $this->assertInstanceOf('\core\event\user_created', $event); + $this->assertEquals($user['id'], $event->objectid); + $this->assertEquals('user_created', $event->get_legacy_eventname()); + $this->assertEquals(context_user::instance($user['id']), $event->get_context()); + $this->assertEventLegacyData($dbuser, $event); + $expectedlogdata = array(SITEID, 'user', 'add', '/view.php?id='.$event->objectid, fullname($dbuser)); + $this->assertEventLegacyLogData($expectedlogdata, $event); + } +}