* Scaled embedded youtube videos to maximum width
* `\wcf\form\AbstractCaptchaForm`: added parameter to force captcha usage for registered users.
* Added global disable switch for languages.
+* Overhauled page tracking in sessions / user online locations
#### CMS
* Option `message_sidebar_enable_rank` removed.
* Option `message_sidebar_enable_avatar` removed.
* Removed obsolete `$activeMenuItem` in frontend forms/pages
+* Obsolete interface `wcf\page\ITrackablePage` deprecated.
#### Documentation
}
// get current location
- $this->sqlSelects .= ", session.controller, session.objectID AS locationObjectID, session.lastActivityTime AS sessionLastActivityTime";
+ $this->sqlSelects .= ", session.pageID, session.pageObjectID, session.lastActivityTime AS sessionLastActivityTime";
$this->sqlJoins .= " LEFT JOIN wcf".WCF_N."_session session ON (session.userID = user_table.userID)";
}
*/
public function setLocation($location = null) {
if ($location === null) {
- if ($this->controller) {
- if ($this->controller === CmsPage::class) {
- // create location based on cms page title
- if ($this->objectType) {
- $page = PageCache::getInstance()->getPageByIdentifier($this->objectType);
- if ($page !== null) {
- // TODO: check if active user may access the page
- $pageContent = $page->getPageContentByLanguage(WCF::getLanguage()->languageID);
- if (isset($pageContent['title'])) {
- $this->location = $pageContent['title'];
-
- return false;
- }
- }
+ if ($this->pageID) {
+ $page = PageCache::getInstance()->getPage($this->pageID);
+ if ($page !== null) {
+ if ($page->getHandler() !== null && $page->getHandler() instanceof IOnlineLocationPageHandler) {
+ // refer to page handler
+ $this->location = $page->getHandler()->getOnlineLocation($page, $this);
+ return true;
}
- }
- else {
- $page = PageCache::getInstance()->getPageByController($this->controller);
- if ($page !== null) {
- if ($page->getHandler() !== null && $page->getHandler() instanceof IOnlineLocationPageHandler) {
- // refer to page handler
- $this->location = $page->getHandler()->getOnlineLocation($page, $this);
-
- return true;
- }
- else {
- // check if static language item exists
- $languageItem = 'wcf.page.onlineLocation.' . $page->identifier;
- $languageItemValue = WCF::getLanguage()->get($languageItem);
-
- if ($languageItemValue !== $languageItem) {
- $this->location = $languageItemValue;
-
- return true;
+ else {
+ // TODO: check if active user may access the page
+ $title = $page->getTitle();
+ if (!empty($title)) {
+ if ($page->pageType != 'system') {
+ $this->location = '<a href="' . StringUtil::encodeHTML($page->getLink()) . '">' . StringUtil::encodeHTML($title) . '</a>';
+ }
+ else {
+ $this->location = StringUtil::encodeHTML($title);
}
}
+
+ return ($this->location != '');
}
}
}
* @category Community Framework
*/
class AccountManagementForm extends AbstractForm {
- /**
- * @inheritDoc
- */
- public $enableTracking = true;
-
/**
* @inheritDoc
*/
* @category Community Framework
*/
class AvatarEditForm extends AbstractForm {
- /**
- * @inheritDoc
- */
- public $enableTracking = true;
-
/**
* @inheritDoc
*/
class LoginForm extends \wcf\acp\form\LoginForm {
const AVAILABLE_DURING_OFFLINE_MODE = true;
- /**
- * @inheritDoc
- */
- public $enableTracking = true;
-
/**
* true enables the usage of cookies to save login credentials
* @var boolean
class LostPasswordForm extends AbstractCaptchaForm {
const AVAILABLE_DURING_OFFLINE_MODE = true;
- /**
- * @inheritDoc
- */
- public $enableTracking = true;
-
/**
* username
* @var string
class NewPasswordForm extends AbstractForm {
const AVAILABLE_DURING_OFFLINE_MODE = true;
- /**
- * @inheritDoc
- */
- public $enableTracking = true;
-
/**
* user id
* @var integer
* @category Community Framework
*/
class RegisterForm extends UserAddForm {
- /**
- * @inheritDoc
- */
- public $enableTracking = true;
-
/**
* true if external authentication is used
* @var boolean
* @category Community Framework
*/
class SettingsForm extends AbstractForm {
- /**
- * @inheritDoc
- */
- public $enableTracking = true;
-
/**
* @inheritDoc
*/
* @category Community Framework
*/
class SignatureEditForm extends MessageForm {
- /**
- * @inheritDoc
- */
- public $enableTracking = true;
-
/**
* @inheritDoc
*/
* @subpackage page
* @category Community Framework
*/
-abstract class AbstractPage implements IPage, ITrackablePage {
+abstract class AbstractPage implements IPage {
/**
* name of the active menu item
* @var string
*/
public $canonicalURL = '';
- /**
- * enables the tracking of this page
- * @var boolean
- */
- public $enableTracking = false;
-
/**
* is true if canonical URL will be enforced even if POST data is represent
* @var boolean
}
}
}
-
- /**
- * @inheritDoc
- */
- public function isTracked() {
- return $this->enableTracking;
- }
-
- /**
- * @inheritDoc
- */
- public function getController() {
- return get_class($this);
- }
-
- /**
- * @inheritDoc
- */
- public function getParentObjectType() {
- return '';
- }
-
- /**
- * @inheritDoc
- */
- public function getParentObjectID() {
- return 0;
- }
-
- /**
- * @inheritDoc
- */
- public function getObjectType() {
- return '';
- }
-
- /**
- * @inheritDoc
- */
- public function getObjectID() {
- return 0;
- }
}
*/
public $content;
- /**
- * @inheritDoc
- */
- public $enableTracking = true;
-
/**
* @var integer
*/
'pageID' => $this->pageID
]);
}
-
- /**
- * @inheritDoc
- */
- public function getObjectType() {
- return $this->page ? $this->page->identifier : '';
- }
}
* @package com.woltlab.wcf
* @subpackage page
* @category Community Framework
+ * @deprecated 2.2
*/
interface ITrackablePage {
/**
*/
public $neededModules = ['MODULE_MEMBERS_LIST'];
- /**
- * @inheritDoc
- */
- public $enableTracking = true;
-
/**
* @inheritDoc
*/
*/
public $neededModules = ['MODULE_TEAM_PAGE'];
- /**
- * @inheritDoc
- */
- public $enableTracking = true;
-
/**
* @inheritDoc
*/
* @category Community Framework
*/
class UserPage extends AbstractPage {
- /**
- * @inheritDoc
- */
- public $enableTracking = true;
-
/**
* edit profile on page load
* @var boolean
parent::show();
}
-
- /**
- * @inheritDoc
- */
- public function getObjectType() {
- return 'com.woltlab.wcf.user';
- }
-
- /**
- * @inheritDoc
- */
- public function getObjectID() {
- return $this->userID;
- }
}
*/
public $neededPermissions = ['user.profile.canViewUsersOnlineList'];
- /**
- * @inheritDoc
- */
- public $enableTracking = true;
-
/**
* @inheritDoc
*/
// cache all necessary data for showing locations
foreach ($this->objectList as $userOnline) {
if ($userOnline->controller) {
- $page = PageCache::getInstance()->getPageByController($userOnline->controller);
+ $page = PageCache::getInstance()->getPage($userOnline->pageID);
if ($page !== null && $page->getHandler() !== null && $page->getHandler() instanceof IOnlineLocationPageHandler) {
$page->getHandler()->prepareOnlineLocation($page, $userOnline);
}
<?php
namespace wcf\system\exception;
+use wcf\system\session\SessionHandler;
use wcf\system\WCF;
/**
* Shows a styled page with the given error message.
*/
public function show() {
+ SessionHandler::getInstance()->disableTracking();
+
WCF::getTPL()->assign([
'name' => get_class($this),
'file' => $this->getFile(),
<?php
namespace wcf\system\exception;
+use wcf\system\session\SessionHandler;
use wcf\system\WCF;
/**
* Prints a permission denied exception.
*/
public function show() {
+ SessionHandler::getInstance()->disableTracking();
+
@header('HTTP/1.0 403 Forbidden');
WCF::getTPL()->assign([
* @param string $identifier internal page identifier
* @param integer $pageObjectID page object id
* @param ITitledLinkObject $locationObject optional label for breadcrumbs usage
+ * @param boolean $useAsParentLocation
* @throws SystemException
*/
- public function addParentLocation($identifier, $pageObjectID = 0, ITitledLinkObject $locationObject = null) {
+ public function addParentLocation($identifier, $pageObjectID = 0, ITitledLinkObject $locationObject = null, $useAsParentLocation = false) {
$page = PageCache::getInstance()->getPageByIdentifier($identifier);
if ($page === null) {
throw new SystemException("Unknown page identifier '".$identifier."'.");
'link' => $link,
'pageID' => $page->pageID,
'pageObjectID' => $pageObjectID,
- 'title' => $title
+ 'title' => $title,
+ 'useAsParentLocation' => $useAsParentLocation,
];
}
* @inheritDoc
*/
public function getOnlineLocation(Page $page, UserOnline $user) {
- if ($user->objectID === null) {
+ if ($user->pageObjectID === null) {
return '';
}
- $visitedUser = UserRuntimeCache::getInstance()->getObject($user->objectID);
+ $visitedUser = UserRuntimeCache::getInstance()->getObject($user->pageObjectID);
if ($visitedUser === null) {
return '';
}
* @inheritDoc
*/
public function prepareOnlineLocation(Page $page, UserOnline $user) {
- if ($user->objectID !== null) {
- UserRuntimeCache::getInstance()->cacheObjectID($user->objectID);
+ if ($user->pageObjectID !== null) {
+ UserRuntimeCache::getInstance()->cacheObjectID($user->pageObjectID);
}
}
}
use wcf\data\session\SessionEditor;
use wcf\data\user\User;
use wcf\data\user\UserEditor;
-use wcf\page\ITrackablePage;
use wcf\system\cache\builder\SpiderCacheBuilder;
use wcf\system\cache\builder\UserGroupOptionCacheBuilder;
use wcf\system\cache\builder\UserGroupPermissionCacheBuilder;
use wcf\system\database\DatabaseException;
use wcf\system\event\EventHandler;
use wcf\system\exception\PermissionDeniedException;
-use wcf\system\request\RequestHandler;
+use wcf\system\page\PageLocationManager;
use wcf\system\user\authentication\UserAuthenticationFactory;
use wcf\system\user\storage\UserStorageHandler;
use wcf\system\SingletonFactory;
*/
protected $doNotUpdate = false;
+ /**
+ * disables page tracking
+ * @var boolean
+ */
+ protected $disableTracking = false;
+
/**
* various environment variables
* @var array
$this->doNotUpdate = true;
}
+ /**
+ * Disables page tracking.
+ */
+ public function disableTracking() {
+ $this->disableTracking = true;
+ }
+
/**
* Defines global wcf constants related to session.
*/
'requestMethod' => $this->requestMethod,
'lastActivityTime' => TIME_NOW
];
- if (!class_exists('wcf\system\CLIWCF', false) && PACKAGE_ID && RequestHandler::getInstance()->getActiveRequest() && RequestHandler::getInstance()->getActiveRequest()->getRequestObject() instanceof ITrackablePage && RequestHandler::getInstance()->getActiveRequest()->getRequestObject()->isTracked()) {
- $data['controller'] = RequestHandler::getInstance()->getActiveRequest()->getRequestObject()->getController();
- $data['parentObjectType'] = RequestHandler::getInstance()->getActiveRequest()->getRequestObject()->getParentObjectType();
- $data['parentObjectID'] = RequestHandler::getInstance()->getActiveRequest()->getRequestObject()->getParentObjectID();
- $data['objectType'] = RequestHandler::getInstance()->getActiveRequest()->getRequestObject()->getObjectType();
- $data['objectID'] = RequestHandler::getInstance()->getActiveRequest()->getRequestObject()->getObjectID();
+ if (!class_exists('wcf\system\CLIWCF', false) && !$this->isACP && !$this->disableTracking) {
+ $pageLocations = PageLocationManager::getInstance()->getLocations();
+ if (isset($pageLocations[0])) {
+ $data['pageID'] = $pageLocations[0]['pageID'];
+ $data['pageObjectID'] = ($pageLocations[0]['pageObjectID'] ?: null);
+ $data['parentPageID'] = null;
+ $data['parentPageObjectID'] = null;
+
+ for ($i = 1; $i < count($pageLocations); $i++) {
+ if (!empty($pageLocations[$i]['useAsParentLocation'])) {
+ $data['parentPageID'] = $pageLocations[$i]['pageID'];
+ $data['parentPageObjectID'] = ($pageLocations[$i]['pageObjectID'] ?: null);
+ break;
+ }
+ }
+ }
}
// update session
userAgent VARCHAR(255) NOT NULL DEFAULT '',
lastActivityTime INT(10) NOT NULL DEFAULT 0,
requestURI VARCHAR(255) NOT NULL DEFAULT '',
- requestMethod VARCHAR(7) NOT NULL DEFAULT '',
- controller VARCHAR(255) NOT NULL DEFAULT '',
- parentObjectType VARCHAR(255) NOT NULL DEFAULT '',
- parentObjectID INT(10) NOT NULL DEFAULT 0,
- objectType VARCHAR(255) NOT NULL DEFAULT '',
- objectID INT(10) NOT NULL DEFAULT 0
+ requestMethod VARCHAR(7) NOT NULL DEFAULT ''
);
DROP TABLE IF EXISTS wcf1_acp_session_access_log;
lastActivityTime INT(10) NOT NULL DEFAULT 0,
requestURI VARCHAR(255) NOT NULL DEFAULT '',
requestMethod VARCHAR(7) NOT NULL DEFAULT '',
- controller VARCHAR(255) NOT NULL DEFAULT '',
- parentObjectType VARCHAR(255) NOT NULL DEFAULT '',
- parentObjectID INT(10) NOT NULL DEFAULT 0,
- objectType VARCHAR(255) NOT NULL DEFAULT '',
- objectID INT(10) NOT NULL DEFAULT 0,
+ pageID INT(10),
+ pageObjectID INT(10),
+ parentPageID INT(10),
+ parentPageObjectID INT(10),
spiderID INT(10),
KEY packageID (lastActivityTime, spiderID),
+ KEY pageID (pageID, pageObjectID),
+ KEY parentPageID (parentPageID, parentPageObjectID),
UNIQUE KEY uniqueUserID (userID)
);
ALTER TABLE wcf1_session ADD FOREIGN KEY (userID) REFERENCES wcf1_user (userID) ON DELETE CASCADE;
ALTER TABLE wcf1_session ADD FOREIGN KEY (spiderID) REFERENCES wcf1_spider (spiderID) ON DELETE CASCADE;
+ALTER TABLE wcf1_session ADD FOREIGN KEY (pageID) REFERENCES wcf1_page (pageID) ON DELETE SET NULL;
+ALTER TABLE wcf1_session ADD FOREIGN KEY (parentPageID) REFERENCES wcf1_page (pageID) ON DELETE SET NULL;
ALTER TABLE wcf1_session_virtual ADD FOREIGN KEY (sessionID) REFERENCES wcf1_session (sessionID) ON DELETE CASCADE ON UPDATE CASCADE;