{include file='header' __disableAds=true __sidebarLeftHasMenu=true}
-{* @TODO *}
+<section class="section">
+ <h2 class="sectionTitle">{lang}wcf.user.security.activeSessions{/lang}</h2>
+
+ <ul class="containerList">
+ {foreach from=$activeSessions item=session}
+ <li class="box64 sessionItem">
+ <div>
+ <span class="icon icon64 fa-{$session->getDeviceIcon()}"></span>
+ </div>
+
+ <div class="accountSecurityContainer">
+ <div class="containerHeadline accountSecurityInformation">
+ <h3>{$session->getBrowser()}</h3>
+ <small>
+ {$session->getIpAddress()}<br />
+ {if $session->isCurrentSession()}
+ {lang}wcf.user.security.currentSession{/lang}
+ {else}
+ {lang}wcf.user.security.sessionLastActive{/lang}
+ {/if}
+ </small>
+ </div>
+
+ {if !$session->isCurrentSession()}
+ <div class="accountSecurityButtons">
+ <button class="small sessionDeleteButton" data-session-id="{$session->getSessionID()}">{lang}wcf.user.security.deleteSession{/lang}</button>
+ </div>
+ {/if}
+ </div>
+ </li>
+ {/foreach}
+ </ul>
+</section>
+
+<script data-relocate="true">
+ require(['Language', 'WoltLabSuite/Core/Ui/User/Session/Delete'], function(Language, UserSessionDelete) {
+ Language.addObject({
+ 'wcf.user.security.deleteSession.confirmMessage': '{jslang}wcf.user.security.deleteSession.confirmMessage{/jslang}',
+ });
+
+ new (UserSessionDelete.default)();
+ });
+</script>
{include file='footer' __disableAds=true}
--- /dev/null
+/**
+ * Handles the deletion of a user session.
+ *
+ * @author Joshua Ruesweg
+ * @copyright 2001-2020 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @module WoltLabSuite/Core/Ui/User/Session/Delete
+ */
+define(["require", "exports", "tslib", "../../../Ajax", "../../Notification", "../../Confirmation", "../../../Language"], function (require, exports, tslib_1, Ajax, UiNotification, UiConfirmation, Language) {
+ "use strict";
+ Object.defineProperty(exports, "__esModule", { value: true });
+ exports.UiUserSessionDelete = void 0;
+ Ajax = tslib_1.__importStar(Ajax);
+ UiNotification = tslib_1.__importStar(UiNotification);
+ UiConfirmation = tslib_1.__importStar(UiConfirmation);
+ Language = tslib_1.__importStar(Language);
+ class UiUserSessionDelete {
+ /**
+ * Initializes the session delete buttons.
+ */
+ constructor() {
+ this.knownElements = new Map();
+ document.querySelectorAll(".sessionDeleteButton").forEach((element) => {
+ if (!element.dataset.sessionId) {
+ throw new Error(`No sessionId for session delete button given.`);
+ }
+ if (!this.knownElements.has(element.dataset.sessionId)) {
+ element.addEventListener("click", (ev) => this.delete(element, ev));
+ this.knownElements.set(element.dataset.sessionId, element);
+ }
+ });
+ }
+ /**
+ * Opens the user trophy list for a specific user.
+ */
+ delete(element, event) {
+ event.preventDefault();
+ UiConfirmation.show({
+ message: Language.get("wcf.user.security.deleteSession.confirmMessage"),
+ confirm: (_parameters) => {
+ Ajax.api(this, {
+ sessionID: element.dataset.sessionId,
+ });
+ },
+ });
+ }
+ _ajaxSuccess(data) {
+ const element = this.knownElements.get(data.sessionID);
+ if (element !== undefined) {
+ const sessionItem = element.closest("li");
+ if (sessionItem !== null) {
+ sessionItem.remove();
+ }
+ }
+ UiNotification.show();
+ }
+ _ajaxSetup() {
+ return {
+ url: "index.php?delete-session/&t=" + window.SECURITY_TOKEN,
+ };
+ }
+ }
+ exports.UiUserSessionDelete = UiUserSessionDelete;
+ exports.default = UiUserSessionDelete;
+});
/**
* @var string
*/
- public $sessionID;
+ private $sessionID;
/**
* @inheritDoc
<?php
namespace wcf\page;
use wcf\system\menu\user\UserMenu;
+use wcf\system\session\Session;
+use wcf\system\session\SessionHandler;
+use wcf\system\WCF;
/**
* Shows the account security page.
*/
public $loginRequired = true;
+ /**
+ * @var Session[]
+ */
+ private $activeSessions;
+
+ /**
+ * @inheritDoc
+ */
+ public function readData() {
+ parent::readData();
+
+ $this->activeSessions = SessionHandler::getInstance()->getUserSessions(WCF::getUser());
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function assignVariables() {
+ parent::assignVariables();
+
+ WCF::getTPL()->assign([
+ 'activeSessions' => $this->activeSessions
+ ]);
+ }
+
/**
* @inheritDoc
*/
--- /dev/null
+.accountSecurityContainer {
+ display: flex;
+ flex-wrap: wrap;
+}
+
+.accountSecurityInformation {
+ flex: 1 1 auto;
+}
--- /dev/null
+/**
+ * Handles the deletion of a user session.
+ *
+ * @author Joshua Ruesweg
+ * @copyright 2001-2020 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @module WoltLabSuite/Core/Ui/User/Session/Delete
+ */
+
+import * as Ajax from "../../../Ajax";
+import { AjaxCallbackObject, AjaxCallbackSetup, DatabaseObjectActionResponse } from "../../../Ajax/Data";
+import * as UiNotification from "../../Notification";
+import * as UiConfirmation from "../../Confirmation";
+import * as Language from "../../../Language";
+
+export class UiUserSessionDelete implements AjaxCallbackObject {
+ private readonly knownElements = new Map<string, HTMLElement>();
+
+ /**
+ * Initializes the session delete buttons.
+ */
+ constructor() {
+ document.querySelectorAll(".sessionDeleteButton").forEach((element: HTMLElement) => {
+ if (!element.dataset.sessionId) {
+ throw new Error(`No sessionId for session delete button given.`);
+ }
+
+ if (!this.knownElements.has(element.dataset.sessionId)) {
+ element.addEventListener("click", (ev) => this.delete(element, ev));
+
+ this.knownElements.set(element.dataset.sessionId, element);
+ }
+ });
+ }
+
+ /**
+ * Opens the user trophy list for a specific user.
+ */
+ private delete(element: HTMLElement, event: MouseEvent): void {
+ event.preventDefault();
+
+ UiConfirmation.show({
+ message: Language.get("wcf.user.security.deleteSession.confirmMessage"),
+ confirm: (_parameters) => {
+ Ajax.api(this, {
+ sessionID: element.dataset.sessionId,
+ });
+ },
+ });
+ }
+
+ _ajaxSuccess(data: AjaxResponse): void {
+ const element = this.knownElements.get(data.sessionID);
+
+ if (element !== undefined) {
+ const sessionItem = element.closest("li");
+
+ if (sessionItem !== null) {
+ sessionItem.remove();
+ }
+ }
+
+ UiNotification.show();
+ }
+
+ _ajaxSetup(): ReturnType<AjaxCallbackSetup> {
+ return {
+ url: "index.php?delete-session/&t=" + window.SECURITY_TOKEN,
+ };
+ }
+}
+
+export default UiUserSessionDelete;
+
+interface AjaxResponse extends DatabaseObjectActionResponse {
+ sessionID: string;
+}
<p><small><em>Quelle: <a href="http://www.mustervorlage.net/disclaimer-muster" class="externalURL">Mustervorlage.net</a></em></small></p>]]></item>
<item name="wcf.user.register.error.blacklistMatches"><![CDATA[Die Registrierung kann aufgrund von Einschränkungen nicht fortgesetzt werden, bitte wende{if LANGUAGE_USE_INFORMAL_VARIANT} dich{else}n Sie sich{/if} direkt an den Administrator dieser Seite.]]></item>
</category>
+ <category name="wcf.user.security">
+ <item name="wcf.user.security.activeSessions"><![CDATA[Aktive Sitzungen]]></item>
+ <item name="wcf.user.security.currentSession"><![CDATA[Aktuelle Sitzung]]></item>
+ <item name="wcf.user.security.sessionLastActive"><![CDATA[Sitzung zuletzt aktiv: {@$session->getLastActivityTime()|time}]]></item>
+ <item name="wcf.user.security.deleteSession"><![CDATA[Sitzung beenden]]></item>
+ <item name="wcf.user.security.deleteSession.confirmMessage"><![CDATA[{if LANGUAGE_USE_INFORMAL_VARIANT}Willst du{else}Wollen Sie{/if} die Sitzung wirklich beenden?]]></item>
+ </category>
<category name="wcf.user.trophy">
<item name="wcf.user.trophy.trophyPoints"><![CDATA[Trophäen]]></item>
<item name="wcf.user.trophy.showTrophies"><![CDATA[Trophäen von {$user->username} anzeigen]]></item>
<p><small><em>Source: <a href="http://www.mustervorlage.net/disclaimer-muster" class="externalURL">Mustervorlage.net</a></em></small></p>]]></item>
<item name="wcf.user.register.error.blacklistMatches"><![CDATA[The registration could not be completed due to active restrictions, please contact the site administrator.]]></item>
</category>
+ <category name="wcf.user.security">
+ <item name="wcf.user.security.activeSessions"><![CDATA[Active Sessions]]></item>
+ <item name="wcf.user.security.currentSession"><![CDATA[Current Session]]></item>
+ <item name="wcf.user.security.sessionLastActive"><![CDATA[Last active: {@$session->getLastActivityTime()|time}]]></item>
+ <item name="wcf.user.security.deleteSession"><![CDATA[Revoke Session]]></item>
+ <item name="wcf.user.security.deleteSession.confirmMessage"><![CDATA[Do you really want to revoke the session?]]></item>
+ </category>
<category name="wcf.user.trophy">
<item name="wcf.user.trophy.trophyPoints"><![CDATA[Trophies]]></item>
<item name="wcf.user.trophy.showTrophies"><![CDATA[Display Trophies of {$user->username}]]></item>