Skip to content

Commit

Permalink
feat(core): added first login event for when user logs in the first time
Browse files Browse the repository at this point in the history
  • Loading branch information
jdalsem committed Jun 2, 2021
1 parent f269b13 commit 19a2d38
Show file tree
Hide file tree
Showing 6 changed files with 160 additions and 0 deletions.
3 changes: 3 additions & 0 deletions docs/guides/events-list.rst
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,9 @@ User events
**login:after, user**
Triggered after the user logs in.

**login:first, user**
Triggered after a successful login. Only if there is no previous login.

**logout:before, user**
Triggered during logout. Returning false should prevent the user from logging out.

Expand Down
7 changes: 7 additions & 0 deletions engine/lib/sessions.php
Original file line number Diff line number Diff line change
Expand Up @@ -276,10 +276,17 @@ function login(\ElggUser $user, $persistent = false) {
// User's privilege has been elevated, so change the session id (prevents session fixation)
$session->migrate();

// check before updating last login to determine first login
$first_login = empty($user->last_login);

$user->setLastLogin();
reset_login_failure_count($user->guid);

elgg_trigger_after_event('login', 'user', $user);

if ($first_login) {
elgg_trigger_event('login:first', 'user', $user);
}

return true;
}
Expand Down
1 change: 1 addition & 0 deletions engine/tests/classes/Elgg/BaseTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ abstract class BaseTestCase extends TestCase implements Seedable, Testable {
use Testing;
use PluginTesting;
use HookTesting;
use EventTesting;
use MessageTesting;

static $_instance;
Expand Down
20 changes: 20 additions & 0 deletions engine/tests/classes/Elgg/EventTesting.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

namespace Elgg;

trait EventTesting {

/**
* @return TestableEvent
*/
public function registerTestingEvent($name, $type, $handler, $priority = 500) {

$event = new TestableEvent();
$event->name = $name;
$event->type = $type;
$event->handler = $handler;
$event->priority = $priority;

return $event->register($this);
}
}
103 changes: 103 additions & 0 deletions engine/tests/classes/Elgg/TestableEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
<?php

namespace Elgg;

class TestableEvent {

/**
* @var string
*/
public $name;

/**
* @var string
*/
public $type;

/**
* @var callable
*/
public $handler;

/**
* @var mixed
*/
public $object;

/**
* @var int
*/
public $priority = 500;

/**
* @var BaseTestCase
*/
protected $test_case;

/**
* @var int
*/
protected $calls = 0;

/**
* Register a new testing event handler
*
* @param BaseTestCase $test_case Test case
*
* @return TestableEvent
*/
public function register(BaseTestCase $test_case) {
$this->test_case = $test_case;

elgg_register_event_handler($this->name, $this->type, [$this, 'handler'], $this->priority);

return $this;
}

/**
* Unregister handler
* @return void
*/
public function unregister() {
elgg_unregister_event_handler($this->name, $this->type, [$this, 'handler']);
}

/**
* Handler event call
*
* @param Event $event Event
*
* @return mixed
*/
public function handler(\Elgg\Event $event) {
$this->calls++;

$this->object = $event->getObject();

list(, $return, $event) = _elgg_services()->handlers->call($this->handler, $event, [
$this->name,
$this->type,
$this->object,
]);

return $return;
}

/**
* Assert that event was called expected number of times
*
* @param int $expected Expectation
*/
public function assertNumberOfCalls($expected) {
$this->test_case->assertEquals($expected, $this->calls);
}

/**
* Assert that object passed to event has a specific value
*
* @param mixed $object Object
*/
public function assertObject($object) {
$this->test_case->assertEquals($this->object, $object);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,32 @@ public function testCanPreventLoginWithHook() {

_elgg_services()->events->unregisterHandler('before:login', 'user', $handler);
}

public function testLoginEvents() {
$user = $this->user = $this->createUser();

$login_before_event = $this->registerTestingEvent('login:before', 'user', function(\Elgg\Event $event) {});
$login_after_event = $this->registerTestingEvent('login:after', 'user', function(\Elgg\Event $event) {});
$first_login_event = $this->registerTestingEvent('login:first', 'user', function(\Elgg\Event $event) {});

$this->assertTrue(login($user));
$login_before_event->assertNumberOfCalls(1);
$login_after_event->assertNumberOfCalls(1);
$first_login_event->assertNumberOfCalls(1);

$login_before_event->assertObject($user);
$login_after_event->assertObject($user);
$first_login_event->assertObject($user);

$this->assertTrue(logout($user));
$this->assertTrue(login($user));

$login_before_event->assertNumberOfCalls(2);
$login_after_event->assertNumberOfCalls(2);
$first_login_event->assertNumberOfCalls(1);

$this->assertTrue(logout($user));
}

public function testCanPersistLogin() {

Expand Down

0 comments on commit 19a2d38

Please sign in to comment.