Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/Entities/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,17 @@ public function getPasswordHash(): ?string
return $this->password_hash;
}

/**
* Returns the previous login information for this user
*/
public function previousLogin(): ?Login
{
/** @var LoginModel $logins */
$logins = model(LoginModel::class);

return $logins->previousLogin($this);
}

/**
* Returns the last login information for this user as
*/
Expand Down
13 changes: 13 additions & 0 deletions src/Models/LoginModel.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,19 @@ public function recordLoginAttempt(
$this->checkQueryReturn($return);
}

/**
* Returns the previous login information for the user,
* useful to display to the user the last time the account
* was accessed.
*/
public function previousLogin(User $user): ?Login
{
return $this->where('success', 1)
->where('user_id', $user->id)
->orderBy('id', 'desc')
->limit(1, 1)->first();
}

/**
* Returns the last login information for the user
*/
Expand Down
39 changes: 39 additions & 0 deletions tests/Unit/UserTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,45 @@ public function testLastLogin(): void
$this->assertInstanceOf(Time::class, $last->date);
}

public function testPreviousLogin(): void
{
fake(
UserIdentityModel::class,
['user_id' => $this->user->id, 'type' => Session::ID_TYPE_EMAIL_PASSWORD, 'secret' => 'foo@example.com']
);

// No logins found.
$this->assertNull($this->user->previousLogin());

$login1 = fake(
LoginModel::class,
['id_type' => 'email', 'identifier' => $this->user->email, 'user_id' => $this->user->id]
);

// The very most login is skipped.
$this->assertNull($this->user->previousLogin());

fake(
LoginModel::class,
['id_type' => 'email', 'identifier' => $this->user->email, 'user_id' => $this->user->id]
);
fake(
LoginModel::class,
[
'id_type' => 'email',
'identifier' => $this->user->email,
'user_id' => $this->user->id,
'success' => false,
]
);

$previous = $this->user->previousLogin();

$this->assertInstanceOf(Login::class, $previous); // @phpstan-ignore-line
$this->assertSame($login1->id, $previous->id);
$this->assertInstanceOf(Time::class, $previous->date);
}

/**
* @see https://github.com/codeigniter4/shield/issues/103
*/
Expand Down