From: Tim Düsterhus Date: Tue, 23 Feb 2021 14:14:32 +0000 (+0100) Subject: Merge branch '5.3' X-Git-Tag: 5.4.0_Alpha_1~235 X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=26577a4e7b5e17466e289e691cb99d6c61519342;p=GitHub%2FWoltLab%2FWCF.git Merge branch '5.3' --- 26577a4e7b5e17466e289e691cb99d6c61519342 diff --cc wcfsetup/install/files/lib/data/user/object/watch/UserObjectWatchAction.class.php index afc58cac16,77ce4ade08..dda2b6090b --- a/wcfsetup/install/files/lib/data/user/object/watch/UserObjectWatchAction.class.php +++ b/wcfsetup/install/files/lib/data/user/object/watch/UserObjectWatchAction.class.php @@@ -10,225 -8,192 +10,225 @@@ use wcf\system\WCF /** * Executes watched object-related actions. - * - * @author Alexander Ebert - * @copyright 2001-2019 WoltLab GmbH - * @license GNU Lesser General Public License - * @package WoltLabSuite\Core\Data\User\Object\Watch - * - * @method UserObjectWatch create() - * @method UserObjectWatchEditor[] getObjects() - * @method UserObjectWatchEditor getSingleObject() + * + * @author Alexander Ebert + * @copyright 2001-2019 WoltLab GmbH + * @license GNU Lesser General Public License + * @package WoltLabSuite\Core\Data\User\Object\Watch + * + * @method UserObjectWatch create() + * @method UserObjectWatchEditor[] getObjects() + * @method UserObjectWatchEditor getSingleObject() */ -class UserObjectWatchAction extends AbstractDatabaseObjectAction { - /** - * object type object - * @var \wcf\data\object\type\ObjectType - */ - protected $objectType = null; - - /** - * user object watch object - * @var UserObjectWatch - */ - protected $userObjectWatch = null; - - /** - * Validates parameters to manage a subscription. - */ - public function validateManageSubscription() { - $this->readInteger('objectID'); - $this->readString('objectType'); - - // validate object type - $this->objectType = ObjectTypeCache::getInstance()->getObjectTypeByName('com.woltlab.wcf.user.objectWatch', $this->parameters['objectType']); - if ($this->objectType === null) { - throw new UserInputException('objectType'); - } - - // validate object id - $this->objectType->getProcessor()->validateObjectID($this->parameters['objectID']); - - // get existing subscription - $this->userObjectWatch = UserObjectWatch::getUserObjectWatch($this->objectType->objectTypeID, WCF::getUser()->userID, $this->parameters['objectID']); - } - - /** - * Returns a form to manage a subscription. - * - * @return array - */ - public function manageSubscription() { - WCF::getTPL()->assign([ - 'objectType' => $this->objectType, - 'userObjectWatch' => $this->userObjectWatch - ]); - - return [ - 'objectID' => $this->parameters['objectID'], - 'objectType' => $this->parameters['objectType'], - 'template' => WCF::getTPL()->fetch('manageSubscription') - ]; - } - - /** - * Validates parameters to save subscription state. - */ - public function validateSaveSubscription() { - $this->readBoolean('enableNotification'); - $this->readBoolean('subscribe'); - - $this->validateManageSubscription(); - } - - /** - * Saves subscription state. - */ - public function saveSubscription() { - // subscribe - if ($this->parameters['subscribe']) { - // newly subscribed - if ($this->userObjectWatch === null) { - UserObjectWatchEditor::createOrIgnore([ - 'notification' => $this->parameters['enableNotification'] ? 1 : 0, - 'objectID' => $this->parameters['objectID'], - 'objectTypeID' => $this->objectType->objectTypeID, - 'userID' => WCF::getUser()->userID - ]); - } - else if ($this->userObjectWatch->notification != $this->parameters['enableNotification']) { - // update notification type - $editor = new UserObjectWatchEditor($this->userObjectWatch); - $editor->update([ - 'notification' => $this->parameters['enableNotification'] ? 1 : 0 - ]); - } - - // reset user storage - $this->objectType->getProcessor()->resetUserStorage([WCF::getUser()->userID]); - } - else if ($this->userObjectWatch !== null) { - // unsubscribe - $editor = new UserObjectWatchEditor($this->userObjectWatch); - $editor->delete(); - - // reset user storage - $this->objectType->getProcessor()->resetUserStorage([WCF::getUser()->userID]); - } - - return [ - 'objectID' => $this->parameters['objectID'], - 'objectType' => $this->parameters['objectType'], - 'subscribe' => $this->parameters['subscribe'] - ]; - } - - /** - * Adds a subscription. - */ - public function subscribe() { - $objectType = ObjectTypeCache::getInstance()->getObjectTypeByName('com.woltlab.wcf.user.objectWatch', $this->parameters['data']['objectType']); - - UserObjectWatchEditor::create([ - 'userID' => WCF::getUser()->userID, - 'objectID' => intval($this->parameters['data']['objectID']), - 'objectTypeID' => $objectType->objectTypeID, - 'notification' => !empty($this->parameters['enableNotification']) ? 1 : 0 - ]); - - // reset user storage - $objectType->getProcessor()->resetUserStorage([WCF::getUser()->userID]); - } - - /** - * Removes a subscription. - */ - public function unsubscribe() { - $objectType = ObjectTypeCache::getInstance()->getObjectTypeByName('com.woltlab.wcf.user.objectWatch', $this->parameters['data']['objectType']); - - if ($this->userObjectWatch !== null) $userObjectWatch = $this->userObjectWatch; - else { - $userObjectWatch = UserObjectWatch::getUserObjectWatch($objectType->objectTypeID, WCF::getUser()->userID, intval($this->parameters['data']['objectID'])); - } - $editor = new UserObjectWatchEditor($userObjectWatch); - $editor->delete(); - - // reset user storage - $objectType->getProcessor()->resetUserStorage([WCF::getUser()->userID]); - } - - /** - * Validates the subscribe action. - */ - protected function __validateSubscribe() { - $this->readInteger('objectID', false, 'data'); - $this->readString('objectType', false, 'data'); - - // validate object type - $objectType = ObjectTypeCache::getInstance()->getObjectTypeByName('com.woltlab.wcf.user.objectWatch', $this->parameters['data']['objectType']); - if ($objectType === null) { - throw new UserInputException('objectType'); - } - - // validate object id - $objectType->getProcessor()->validateObjectID(intval($this->parameters['data']['objectID'])); - - // get existing subscription - $this->userObjectWatch = UserObjectWatch::getUserObjectWatch($objectType->objectTypeID, WCF::getUser()->userID, intval($this->parameters['data']['objectID'])); - } - - /** - * Validates the subscribe action. - */ - public function validateSubscribe() { - $this->__validateSubscribe(); - - if ($this->userObjectWatch !== null) { - throw new PermissionDeniedException(); - } - } - - /** - * Validates the unsubscribe action. - */ - public function validateUnsubscribe() { - $this->__validateSubscribe(); - - if ($this->userObjectWatch === null) { - throw new PermissionDeniedException(); - } - } +class UserObjectWatchAction extends AbstractDatabaseObjectAction +{ + /** + * object type object + * @var \wcf\data\object\type\ObjectType + */ + protected $objectType; + + /** + * user object watch object + * @var UserObjectWatch + */ + protected $userObjectWatch; + + /** + * Validates parameters to manage a subscription. + */ + public function validateManageSubscription() + { + $this->readInteger('objectID'); + $this->readString('objectType'); + + // validate object type + $this->objectType = ObjectTypeCache::getInstance()->getObjectTypeByName( + 'com.woltlab.wcf.user.objectWatch', + $this->parameters['objectType'] + ); + if ($this->objectType === null) { + throw new UserInputException('objectType'); + } + + // validate object id + $this->objectType->getProcessor()->validateObjectID($this->parameters['objectID']); + + // get existing subscription + $this->userObjectWatch = UserObjectWatch::getUserObjectWatch( + $this->objectType->objectTypeID, + WCF::getUser()->userID, + $this->parameters['objectID'] + ); + } + + /** + * Returns a form to manage a subscription. + * + * @return array + */ + public function manageSubscription() + { + WCF::getTPL()->assign([ + 'objectType' => $this->objectType, + 'userObjectWatch' => $this->userObjectWatch, + ]); + + return [ + 'objectID' => $this->parameters['objectID'], + 'objectType' => $this->parameters['objectType'], + 'template' => WCF::getTPL()->fetch('manageSubscription'), + ]; + } + + /** + * Validates parameters to save subscription state. + */ + public function validateSaveSubscription() + { + $this->readBoolean('enableNotification'); + $this->readBoolean('subscribe'); + + $this->validateManageSubscription(); + } + + /** + * Saves subscription state. + */ + public function saveSubscription() + { + // subscribe + if ($this->parameters['subscribe']) { + // newly subscribed + if ($this->userObjectWatch === null) { - UserObjectWatchEditor::create([ ++ UserObjectWatchEditor::createOrIgnore([ + 'notification' => $this->parameters['enableNotification'] ? 1 : 0, + 'objectID' => $this->parameters['objectID'], + 'objectTypeID' => $this->objectType->objectTypeID, + 'userID' => WCF::getUser()->userID, + ]); + } elseif ($this->userObjectWatch->notification != $this->parameters['enableNotification']) { + // update notification type + $editor = new UserObjectWatchEditor($this->userObjectWatch); + $editor->update([ + 'notification' => $this->parameters['enableNotification'] ? 1 : 0, + ]); + } + + // reset user storage + $this->objectType->getProcessor()->resetUserStorage([WCF::getUser()->userID]); + } elseif ($this->userObjectWatch !== null) { + // unsubscribe + $editor = new UserObjectWatchEditor($this->userObjectWatch); + $editor->delete(); + + // reset user storage + $this->objectType->getProcessor()->resetUserStorage([WCF::getUser()->userID]); + } + + return [ + 'objectID' => $this->parameters['objectID'], + 'objectType' => $this->parameters['objectType'], + 'subscribe' => $this->parameters['subscribe'], + ]; + } + + /** + * Adds a subscription. + */ + public function subscribe() + { + $objectType = ObjectTypeCache::getInstance()->getObjectTypeByName( + 'com.woltlab.wcf.user.objectWatch', + $this->parameters['data']['objectType'] + ); + + UserObjectWatchEditor::create([ + 'userID' => WCF::getUser()->userID, + 'objectID' => \intval($this->parameters['data']['objectID']), + 'objectTypeID' => $objectType->objectTypeID, + 'notification' => !empty($this->parameters['enableNotification']) ? 1 : 0, + ]); + + // reset user storage + $objectType->getProcessor()->resetUserStorage([WCF::getUser()->userID]); + } + + /** + * Removes a subscription. + */ + public function unsubscribe() + { + $objectType = ObjectTypeCache::getInstance()->getObjectTypeByName( + 'com.woltlab.wcf.user.objectWatch', + $this->parameters['data']['objectType'] + ); + + if ($this->userObjectWatch !== null) { + $userObjectWatch = $this->userObjectWatch; + } else { + $userObjectWatch = UserObjectWatch::getUserObjectWatch( + $objectType->objectTypeID, + WCF::getUser()->userID, + \intval($this->parameters['data']['objectID']) + ); + } + $editor = new UserObjectWatchEditor($userObjectWatch); + $editor->delete(); + + // reset user storage + $objectType->getProcessor()->resetUserStorage([WCF::getUser()->userID]); + } + + /** + * Validates the subscribe action. + */ + protected function __validateSubscribe() + { + $this->readInteger('objectID', false, 'data'); + $this->readString('objectType', false, 'data'); + + // validate object type + $objectType = ObjectTypeCache::getInstance()->getObjectTypeByName( + 'com.woltlab.wcf.user.objectWatch', + $this->parameters['data']['objectType'] + ); + if ($objectType === null) { + throw new UserInputException('objectType'); + } + + // validate object id + $objectType->getProcessor()->validateObjectID(\intval($this->parameters['data']['objectID'])); + + // get existing subscription + $this->userObjectWatch = UserObjectWatch::getUserObjectWatch( + $objectType->objectTypeID, + WCF::getUser()->userID, + \intval($this->parameters['data']['objectID']) + ); + } + + /** + * Validates the subscribe action. + */ + public function validateSubscribe() + { + $this->__validateSubscribe(); + + if ($this->userObjectWatch !== null) { + throw new PermissionDeniedException(); + } + } + + /** + * Validates the unsubscribe action. + */ + public function validateUnsubscribe() + { + $this->__validateSubscribe(); + + if ($this->userObjectWatch === null) { + throw new PermissionDeniedException(); + } + } } diff --cc wcfsetup/install/files/lib/util/ExceptionLogUtil.class.php index 5c9898b2d9,161d4615fd..a76d919d89 --- a/wcfsetup/install/files/lib/util/ExceptionLogUtil.class.php +++ b/wcfsetup/install/files/lib/util/ExceptionLogUtil.class.php @@@ -7,122 -5,117 +7,126 @@@ use wcf\system\Regex /** * Contains helper functions to process the Exception log. - * - * @author Tim Duesterhus - * @copyright 2001-2019 WoltLab GmbH - * @license GNU Lesser General Public License - * @package WoltLabSuite\Core\Util - * @since 5.2 + * + * @author Tim Duesterhus + * @copyright 2001-2019 WoltLab GmbH + * @license GNU Lesser General Public License + * @package WoltLabSuite\Core\Util + * @since 5.2 */ -final class ExceptionLogUtil { - /** - * Splits the given string of Exceptions into an array. - * - * @param string $contents - * @return string[] - */ - public static function splitLog($contents) { - // unify newlines - $contents = StringUtil::unifyNewlines($contents); - - // split contents - $split = new Regex('(?:^|\n<<<<\n\n)(?:<<<<<<<<([a-f0-9]{40})<<<<\n|$)'); - $contents = $split->split($contents, Regex::SPLIT_NON_EMPTY_ONLY | Regex::CAPTURE_SPLIT_DELIMITER); - - if (empty($contents)) { - return []; - } - - // even items become keys, odd items become values - return array_merge(...array_map( - function($v) { - return [$v[0] => $v[1]]; - }, - array_chunk($contents, 2) - )); - } - - /** - * Parses the given log entry. - * - * @param string $entry - * @return mixed[] - */ - public static function parseException($entry) { - static $regex = null; - static $chainRegex = null; - if ($regex === null || $chainRegex === null) { - $regex = new Regex("(?P[MTWFS][a-z]{2}, \d{1,2} [JFMASOND][a-z]{2} \d{4} \d{2}:\d{2}:\d{2} [+-]\d{4})\s*\n". - "Message: (?P.*?)\s*\n". - "PHP version: (?P.*?)\s*\n". - "WoltLab Suite version: (?P.*?)\s*\n". - "Request URI: (?P.*?)\s*\n". - "Referrer: (?P.*?)\s*\n". - "User Agent: (?P.*?)\s*\n". - "Peak Memory Usage: (?\d+)/(?(?:\d+|-1))\s*\n". - "(?======\n". - ".*)", Regex::DOT_ALL); - $chainRegex = new Regex("======\n". - "Error Class: (?P.*?)\s*\n". - "Error Message: (?P.*?)\s*\n". - "Error Code: (?P[a-zA-Z0-9]+)\s*\n". - "File: (?P.*?) \((?P\d+)\)\s*\n". - "Extra Information: (?P(?:-|[a-zA-Z0-9+/]+={0,2}))\s*\n". - "Stack Trace: (?P\[[^\n]+\])", Regex::DOT_ALL); - } - - if (!$regex->match($entry)) { - throw new \InvalidArgumentException('The given entry is malformed.'); - } - $matches = $regex->getMatches(); - $chainRegex->match($matches['chain'], true, Regex::ORDER_MATCH_BY_SET); - - $chainMatches = array_map(function ($item) { - if ($item['information'] === '-') { - $item['information'] = null; - } - else { - try { - $item['information'] = unserialize(base64_decode($item['information']), ['allowed_classes' => false]); - } - catch (SystemException $e) { - throw new \InvalidArgumentException('The additional information section of the given entry is malformed.', 0, $e); - } - } - - try { - $item['stack'] = JSON::decode($item['stack']); - } - catch (SystemException $e) { - throw new \InvalidArgumentException('The stack trace of the given entry is malformed.', 0, $e); - } - - return $item; - }, $chainRegex->getMatches()); - - $matches['stackHash'] = sha1(implode("\0", array_map(function ($item) { - $result = ""; - foreach ($item['stack'] as $stack) { - $result .= $stack['file']."\t".$stack['line']."\t".$stack['class'].$stack['type'].$stack['function']."\n"; - } - return $result; - }, $chainMatches))); - - $matches['date'] = strtotime($matches['date']); - $matches['chain'] = $chainMatches; - - return $matches; - } - - /** - * Forbid creation of ExceptionLogUtil objects. - */ - private function __construct() { - // does nothing - } +final class ExceptionLogUtil +{ + /** + * Splits the given string of Exceptions into an array. + * + * @param string $contents + * @return string[] + */ + public static function splitLog($contents) + { + // unify newlines + $contents = StringUtil::unifyNewlines($contents); + + // split contents + $split = new Regex('(?:^|\n<<<<\n\n)(?:<<<<<<<<([a-f0-9]{40})<<<<\n|$)'); + $contents = $split->split($contents, Regex::SPLIT_NON_EMPTY_ONLY | Regex::CAPTURE_SPLIT_DELIMITER); + ++ if (empty($contents)) { ++ return []; ++ } ++ + // even items become keys, odd items become values + return \array_merge(...\array_map( + static function ($v) { + return [$v[0] => $v[1]]; + }, + \array_chunk($contents, 2) + )); + } + + /** + * Parses the given log entry. + * + * @param string $entry + * @return mixed[] + */ + public static function parseException($entry) + { + static $regex = null; + static $chainRegex = null; + if ($regex === null || $chainRegex === null) { + $regex = new Regex("(?P[MTWFS][a-z]{2}, \\d{1,2} [JFMASOND][a-z]{2} \\d{4} \\d{2}:\\d{2}:\\d{2} [+-]\\d{4})\\s*\n" + . "Message: (?P.*?)\\s*\n" + . "PHP version: (?P.*?)\\s*\n" + . "WoltLab Suite version: (?P.*?)\\s*\n" + . "Request URI: (?P.*?)\\s*\n" + . "Referrer: (?P.*?)\\s*\n" + . "User Agent: (?P.*?)\\s*\n" + . "Peak Memory Usage: (?\\d+)/(?(?:\\d+|-1))\\s*\n" + . "(?======\n" + . ".*)", Regex::DOT_ALL); + $chainRegex = new Regex("======\n" + . "Error Class: (?P.*?)\\s*\n" + . "Error Message: (?P.*?)\\s*\n" + . "Error Code: (?P[a-zA-Z0-9]+)\\s*\n" + . "File: (?P.*?) \\((?P\\d+)\\)\\s*\n" + . "Extra Information: (?P(?:-|[a-zA-Z0-9+/]+={0,2}))\\s*\n" + . "Stack Trace: (?P\\[[^\n]+\\])", Regex::DOT_ALL); + } + + if (!$regex->match($entry)) { + throw new \InvalidArgumentException('The given entry is malformed.'); + } + $matches = $regex->getMatches(); + $chainRegex->match($matches['chain'], true, Regex::ORDER_MATCH_BY_SET); + + $chainMatches = \array_map(static function ($item) { + if ($item['information'] === '-') { + $item['information'] = null; + } else { + try { + $item['information'] = \unserialize( + \base64_decode($item['information']), + ['allowed_classes' => false] + ); + } catch (SystemException $e) { + throw new \InvalidArgumentException( + 'The additional information section of the given entry is malformed.', + 0, + $e + ); + } + } + + try { + $item['stack'] = JSON::decode($item['stack']); + } catch (SystemException $e) { + throw new \InvalidArgumentException('The stack trace of the given entry is malformed.', 0, $e); + } + + return $item; + }, $chainRegex->getMatches()); + + $matches['stackHash'] = \sha1(\implode("\0", \array_map(static function ($item) { + $result = ""; + foreach ($item['stack'] as $stack) { + $result .= $stack['file'] . "\t" . $stack['line'] . "\t" . $stack['class'] . $stack['type'] . $stack['function'] . "\n"; + } + + return $result; + }, $chainMatches))); + + $matches['date'] = \strtotime($matches['date']); + $matches['chain'] = $chainMatches; + + return $matches; + } + + /** + * Forbid creation of ExceptionLogUtil objects. + */ + private function __construct() + { + // does nothing + } }