Add page to view and delete user sessions
This commit is contained in:
parent
102c8428c8
commit
5c59fec1cf
|
@ -41,6 +41,8 @@ $route->addGroup(
|
|||
$route->get('/certificates', 'SettingsController@ifsgCertificate');
|
||||
$route->post('/certificates', 'SettingsController@saveIfsgCertificate');
|
||||
$route->get('/oauth', 'SettingsController@oauth');
|
||||
$route->get('/sessions', 'SettingsController@sessions');
|
||||
$route->post('/sessions', 'SettingsController@sessionsDelete');
|
||||
}
|
||||
);
|
||||
|
||||
|
|
|
@ -145,6 +145,9 @@ msgstr "Bitte gib Dein geplantes Abreisedatum an, damit wir ein Gefühl für die
|
|||
msgid "settings.profile.success"
|
||||
msgstr "Einstellungen gespeichert."
|
||||
|
||||
msgid "settings.sessions.delete_success"
|
||||
msgstr "Sitzung erfolgreich gelöscht."
|
||||
|
||||
msgid "faq.delete.success"
|
||||
msgstr "FAQ Eintrag erfolgreich gelöscht."
|
||||
|
||||
|
|
|
@ -1122,6 +1122,9 @@ msgstr "Senden"
|
|||
msgid "Y-m-d H:i"
|
||||
msgstr "d.m.Y H:i"
|
||||
|
||||
msgid "Y-m-d H:i:s"
|
||||
msgstr "d.m.Y H:i:s"
|
||||
|
||||
msgid "mark as read"
|
||||
msgstr "als gelesen markieren"
|
||||
|
||||
|
@ -1974,6 +1977,9 @@ msgstr "Vorschau"
|
|||
msgid "form.delete"
|
||||
msgstr "Löschen"
|
||||
|
||||
msgid "form.delete_all"
|
||||
msgstr "Alle löschen"
|
||||
|
||||
msgid "form.updated"
|
||||
msgstr "Aktualisiert"
|
||||
|
||||
|
@ -2201,6 +2207,21 @@ msgstr "Passwort wiederholen"
|
|||
msgid "settings.password.success"
|
||||
msgstr "Passwort wurde erfolgreich geändert."
|
||||
|
||||
msgid "settings.sessions"
|
||||
msgstr "Sitzungen"
|
||||
|
||||
msgid "settings.sessions.info"
|
||||
msgstr "Hier kannst Du deine Bowser-Sitzungen sehen und löschen."
|
||||
|
||||
msgid "settings.sessions.current"
|
||||
msgstr "Aktuelle Sitzung"
|
||||
|
||||
msgid "settings.sessions.id"
|
||||
msgstr "Sitzungs-ID"
|
||||
|
||||
msgid "settings.sessions.last_activity"
|
||||
msgstr "Zuletzt verwendet"
|
||||
|
||||
msgid "settings.theme"
|
||||
msgstr "Theme"
|
||||
|
||||
|
|
|
@ -144,6 +144,9 @@ msgstr "Please enter your planned date of departure. "
|
|||
msgid "settings.profile.success"
|
||||
msgstr "Settings saved."
|
||||
|
||||
msgid "settings.sessions.delete_success"
|
||||
msgstr "Session deleted successfully."
|
||||
|
||||
msgid "faq.delete.success"
|
||||
msgstr "FAQ entry successfully deleted."
|
||||
|
||||
|
|
|
@ -70,6 +70,9 @@ msgstr "Preview"
|
|||
msgid "form.delete"
|
||||
msgstr "Delete"
|
||||
|
||||
msgid "form.delete_all"
|
||||
msgstr "Delete all"
|
||||
|
||||
msgid "form.updated"
|
||||
msgstr "Updated"
|
||||
|
||||
|
@ -299,6 +302,21 @@ msgstr "Password confirmation"
|
|||
msgid "settings.password.success"
|
||||
msgstr "Password was changed successfully."
|
||||
|
||||
msgid "settings.sessions"
|
||||
msgstr "Sessions"
|
||||
|
||||
msgid "settings.sessions.info"
|
||||
msgstr "Here you can see and delete your browser sessions."
|
||||
|
||||
msgid "settings.sessions.current"
|
||||
msgstr "Current session"
|
||||
|
||||
msgid "settings.sessions.id"
|
||||
msgstr "Session ID"
|
||||
|
||||
msgid "settings.sessions.last_activity"
|
||||
msgstr "Last activity"
|
||||
|
||||
msgid "settings.theme"
|
||||
msgstr "Theme"
|
||||
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
{% extends 'pages/settings/settings.twig' %}
|
||||
{% import 'macros/form.twig' as f %}
|
||||
{% import 'macros/base.twig' as m %}
|
||||
|
||||
{% block title %}{{ __('settings.sessions') }}{% endblock %}
|
||||
|
||||
{% block row_content %}
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
{{ m.info(__('settings.sessions.info')) }}
|
||||
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ __('settings.sessions.id') }}</th>
|
||||
<th>{{ __('settings.sessions.last_activity') }}</th>
|
||||
<th>
|
||||
{% if sessions|length > 1 %}
|
||||
<form action="" enctype="multipart/form-data" method="post">
|
||||
{{ csrf() }}
|
||||
{{ f.hidden('id', 'all') }}
|
||||
{{ f.submit(
|
||||
__('form.delete_all'),
|
||||
{'name': 'delete', 'btn_type': 'danger', 'size': 'sm', 'icon_left': 'trash'}
|
||||
) }}
|
||||
</form>
|
||||
{% endif %}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
{% for session in sessions %}
|
||||
<tr>
|
||||
<td>
|
||||
<pre>{{ session['id'] }}</pre>
|
||||
</td>
|
||||
<td>{{ session.last_activity.format(__('Y-m-d H:i:s')) }}</td>
|
||||
<td>
|
||||
{% if session.id != current_session %}
|
||||
<form action="" enctype="multipart/form-data" method="post">
|
||||
{{ csrf() }}
|
||||
{{ f.hidden('id', session.id) }}
|
||||
{{ f.submit(
|
||||
__('form.delete'),
|
||||
{'name': 'delete', 'btn_type': 'danger', 'size': 'sm', 'icon_left': 'trash'}
|
||||
) }}
|
||||
</form>
|
||||
{% else %}
|
||||
{{ __('settings.sessions.current') }}
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -279,6 +279,38 @@ class SettingsController extends BaseController
|
|||
);
|
||||
}
|
||||
|
||||
public function sessions(): Response
|
||||
{
|
||||
$sessions = $this->auth->user()->sessions->sortByDesc('last_activity');
|
||||
|
||||
return $this->response->withView(
|
||||
'pages/settings/sessions',
|
||||
[
|
||||
'settings_menu' => $this->settingsMenu(),
|
||||
'sessions' => $sessions,
|
||||
'current_session' => session()->getId(),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
public function sessionsDelete(Request $request): Response
|
||||
{
|
||||
$id = $request->postData('id');
|
||||
$query = $this->auth->user()
|
||||
->sessions()
|
||||
->getQuery()
|
||||
->where('id', '!=', session()->getId());
|
||||
|
||||
if ($id != 'all') {
|
||||
$query = $query->where('id', $id);
|
||||
}
|
||||
|
||||
$query->delete();
|
||||
$this->addNotification('settings.sessions.delete_success');
|
||||
|
||||
return $this->redirect->to('/settings/sessions');
|
||||
}
|
||||
|
||||
public function settingsMenu(): array
|
||||
{
|
||||
$menu = [
|
||||
|
@ -298,6 +330,8 @@ class SettingsController extends BaseController
|
|||
$menu[url('/settings/certificates')] = 'settings.certificates';
|
||||
}
|
||||
|
||||
$menu[url('/settings/sessions')] = 'settings.sessions';
|
||||
|
||||
if (!empty(config('oauth'))) {
|
||||
$menu[url('/settings/oauth')] = ['title' => 'settings.oauth', 'hidden' => $this->checkOauthHidden()];
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ use Engelsystem\Controllers\NotificationType;
|
|||
use Engelsystem\Controllers\SettingsController;
|
||||
use Engelsystem\Http\Exceptions\HttpNotFound;
|
||||
use Engelsystem\Http\Response;
|
||||
use Engelsystem\Models\Session as SessionModel;
|
||||
use Engelsystem\Models\User\License;
|
||||
use Engelsystem\Models\User\Settings;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
|
@ -32,6 +33,10 @@ class SettingsControllerTest extends ControllerTest
|
|||
|
||||
protected SettingsController $controller;
|
||||
|
||||
protected SessionModel $currentSession;
|
||||
protected SessionModel $secondSession;
|
||||
protected SessionModel $otherSession;
|
||||
|
||||
protected function setUpProfileTest(): array
|
||||
{
|
||||
$body = [
|
||||
|
@ -574,7 +579,95 @@ class SettingsControllerTest extends ControllerTest
|
|||
$this->controller->oauth();
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \Engelsystem\Controllers\SettingsController::sessions
|
||||
*/
|
||||
public function testSessions(): void
|
||||
{
|
||||
$this->setExpects($this->auth, 'user', null, $this->user, $this->once());
|
||||
|
||||
$this->response->expects($this->once())
|
||||
->method('withView')
|
||||
->willReturnCallback(function ($view, $data) {
|
||||
$this->assertEquals('pages/settings/sessions', $view);
|
||||
|
||||
$this->assertArrayHasKey('sessions', $data);
|
||||
$this->assertCount(3, $data['sessions']);
|
||||
|
||||
$this->assertArrayHasKey('current_session', $data);
|
||||
$this->assertEquals($this->currentSession->id, $data['current_session']);
|
||||
|
||||
return $this->response;
|
||||
});
|
||||
|
||||
$this->controller->sessions();
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \Engelsystem\Controllers\SettingsController::sessionsDelete
|
||||
*/
|
||||
public function testSessionsDelete(): void
|
||||
{
|
||||
$this->setExpects($this->auth, 'user', null, $this->user, $this->once());
|
||||
$this->setExpects($this->response, 'redirectTo', ['http://localhost/settings/sessions'], $this->response);
|
||||
|
||||
// Delete old user session
|
||||
$this->request = $this->request->withParsedBody(['id' => $this->secondSession->id]);
|
||||
$this->controller->sessionsDelete($this->request);
|
||||
|
||||
$this->assertHasNotification('settings.sessions.delete_success');
|
||||
$this->assertCount(3, SessionModel::all());
|
||||
$this->assertNull(SessionModel::find($this->secondSession->id));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \Engelsystem\Controllers\SettingsController::sessionsDelete
|
||||
*/
|
||||
public function testSessionsDeleteActiveSession(): void
|
||||
{
|
||||
$this->setExpects($this->auth, 'user', null, $this->user, $this->once());
|
||||
$this->setExpects($this->response, 'redirectTo', null, $this->response);
|
||||
|
||||
// Delete active user session
|
||||
$this->request = $this->request->withParsedBody(['id' => $this->currentSession->id]);
|
||||
$this->controller->sessionsDelete($this->request);
|
||||
|
||||
$this->assertCount(4, SessionModel::all()); // None got deleted
|
||||
$this->assertNotNull(SessionModel::find($this->currentSession->id));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \Engelsystem\Controllers\SettingsController::sessionsDelete
|
||||
*/
|
||||
public function testSessionsDeleteOtherUsersSession(): void
|
||||
{
|
||||
$this->setExpects($this->auth, 'user', null, $this->user, $this->once());
|
||||
$this->setExpects($this->response, 'redirectTo', null, $this->response);
|
||||
|
||||
// Delete another users session
|
||||
$this->request = $this->request->withParsedBody(['id' => $this->otherSession->id]);
|
||||
$this->controller->sessionsDelete($this->request);
|
||||
|
||||
$this->assertCount(4, SessionModel::all()); // None got deleted
|
||||
$this->assertNotNull(SessionModel::find($this->otherSession->id));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \Engelsystem\Controllers\SettingsController::sessionsDelete
|
||||
*/
|
||||
public function testSessionsDeleteAllSessions(): void
|
||||
{
|
||||
$this->setExpects($this->auth, 'user', null, $this->user, $this->once());
|
||||
$this->setExpects($this->response, 'redirectTo', null, $this->response);
|
||||
|
||||
// Delete all other user sessions
|
||||
$this->request = $this->request->withParsedBody(['id' => 'all']);
|
||||
$this->controller->sessionsDelete($this->request);
|
||||
|
||||
$this->assertCount(2, SessionModel::all()); // Two got deleted
|
||||
$this->assertNotNull(SessionModel::find($this->currentSession->id));
|
||||
$this->assertNull(SessionModel::find($this->secondSession->id));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \Engelsystem\Controllers\SettingsController::__construct
|
||||
|
@ -849,6 +942,13 @@ class SettingsControllerTest extends ControllerTest
|
|||
->has(License::factory())
|
||||
->create();
|
||||
|
||||
// Create 4 sessions, 3 for the active user
|
||||
$this->otherSession = SessionModel::factory()->create()->first(); // Other users sessions
|
||||
$sessions = SessionModel::factory(3)->create(['user_id' => $this->user->id]);
|
||||
$this->currentSession = $sessions->first();
|
||||
$this->secondSession = $sessions->last();
|
||||
$this->session->setId($this->currentSession->id);
|
||||
|
||||
$this->controller = $this->app->make(SettingsController::class);
|
||||
$this->controller->setValidator(new Validator());
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue