From 413fd5a38ed46f393c1fc9231cb649ec4f999977 Mon Sep 17 00:00:00 2001 From: Marcel Werk Date: Sun, 10 Apr 2016 19:57:00 +0200 Subject: [PATCH] Improved box system * Added support for visibility exceptions in PIP * Renamed classname to controller * Added box controller interface * Added some default boxes --- com.woltlab.wcf/box.xml | 30 +++++ com.woltlab.wcf/package.xml | 1 + com.woltlab.wcf/page.xml | 21 ++-- .../templates/boxRecentActivity.tpl | 33 +++++ .../templates/boxRecentActivitySidebar.tpl | 15 +++ wcfsetup/install/files/acp/install.php | 10 -- wcfsetup/install/files/acp/post_install.php | 23 ++-- .../install/files/acp/templates/boxAdd.tpl | 10 +- .../files/lib/acp/form/BoxAddForm.class.php | 18 +-- .../files/lib/acp/form/BoxEditForm.class.php | 4 +- .../install/files/lib/data/box/Box.class.php | 22 +++- .../box/AbstractBoxController.class.php | 117 ++++++++++++++++++ .../lib/system/box/IBoxController.class.php | 85 +++++++++++++ .../box/RecentActivityBoxController.class.php | 94 ++++++++++++++ .../PackageUninstallationDispatcher.class.php | 2 +- .../BoxPackageInstallationPlugin.class.php | 82 +++++++++++- .../MenuPackageInstallationPlugin.class.php | 56 ++++++++- .../PagePackageInstallationPlugin.class.php | 28 +++-- wcfsetup/setup/db/install.sql | 2 +- 19 files changed, 583 insertions(+), 70 deletions(-) create mode 100644 com.woltlab.wcf/box.xml create mode 100644 com.woltlab.wcf/templates/boxRecentActivity.tpl create mode 100644 com.woltlab.wcf/templates/boxRecentActivitySidebar.tpl create mode 100644 wcfsetup/install/files/lib/system/box/AbstractBoxController.class.php create mode 100644 wcfsetup/install/files/lib/system/box/IBoxController.class.php create mode 100644 wcfsetup/install/files/lib/system/box/RecentActivityBoxController.class.php diff --git a/com.woltlab.wcf/box.xml b/com.woltlab.wcf/box.xml new file mode 100644 index 0000000000..5d7c6c3a01 --- /dev/null +++ b/com.woltlab.wcf/box.xml @@ -0,0 +1,30 @@ + + + + + Letzte Aktivitäten + Recent Activity + system + wcf\system\box\RecentActivityBoxController + contentBottom + 0 + 0 + + com.woltlab.wcf.Dashboard + + + + + Letzte Aktivitäten (Sidebar) + Recent Activity (Sidebar) + system + wcf\system\box\RecentActivityBoxController + sidebarRight + 1 + 0 + + com.woltlab.wcf.Dashboard + + + + diff --git a/com.woltlab.wcf/package.xml b/com.woltlab.wcf/package.xml index f9a9706610..9b6d1e5f6e 100644 --- a/com.woltlab.wcf/package.xml +++ b/com.woltlab.wcf/package.xml @@ -41,6 +41,7 @@ + acp/post_install.php diff --git a/com.woltlab.wcf/page.xml b/com.woltlab.wcf/page.xml index 7cb0b33c7f..f47d509941 100644 --- a/com.woltlab.wcf/page.xml +++ b/com.woltlab.wcf/page.xml @@ -2,14 +2,6 @@ - - system - wcf\page\DashboardPage - - - module_dashboard_page - - system wcf\page\MembersListPage @@ -242,6 +234,19 @@ + + text + + + module_dashboard_page + + + Dashboard + + dashboard + + + text Cookie Policy diff --git a/com.woltlab.wcf/templates/boxRecentActivity.tpl b/com.woltlab.wcf/templates/boxRecentActivity.tpl new file mode 100644 index 0000000000..800835226e --- /dev/null +++ b/com.woltlab.wcf/templates/boxRecentActivity.tpl @@ -0,0 +1,33 @@ +
+
+

{lang}wcf.user.recentActivity{/lang}

+ + {if $canFilterByFollowedUsers}{*todo*} + + {/if} +
+ + {assign var='__events' value=$eventList->getObjects()} + {assign var='__lastEvent' value=$__events|end} +
    + {include file='recentActivityListItem'} +
+
+ + diff --git a/com.woltlab.wcf/templates/boxRecentActivitySidebar.tpl b/com.woltlab.wcf/templates/boxRecentActivitySidebar.tpl new file mode 100644 index 0000000000..695cdc08f0 --- /dev/null +++ b/com.woltlab.wcf/templates/boxRecentActivitySidebar.tpl @@ -0,0 +1,15 @@ + diff --git a/wcfsetup/install/files/acp/install.php b/wcfsetup/install/files/acp/install.php index 98326293c3..42a7a458f5 100644 --- a/wcfsetup/install/files/acp/install.php +++ b/wcfsetup/install/files/acp/install.php @@ -54,16 +54,6 @@ $sql = "UPDATE wcf".WCF_N."_user_group_option $statement = WCF::getDB()->prepareStatement($sql); $statement->execute([1]); -// landing page -$sql = "UPDATE wcf".WCF_N."_page - SET isLandingPage = ? - WHERE identifier = ?"; -$statement = WCF::getDB()->prepareStatement($sql); -$statement->execute([ - 1, - 'com.woltlab.wcf.Dashboard' -]); - // get server timezone if ($timezone = @date_default_timezone_get()) { if ($timezone != 'Europe/London' && in_array($timezone, DateUtil::getAvailableTimezones())) { diff --git a/wcfsetup/install/files/acp/post_install.php b/wcfsetup/install/files/acp/post_install.php index 442713fdd2..fbd220d113 100644 --- a/wcfsetup/install/files/acp/post_install.php +++ b/wcfsetup/install/files/acp/post_install.php @@ -1,22 +1,17 @@ 1, -// sidebar -'com.woltlab.wcf.user.registerButton' => 1, -'com.woltlab.wcf.user.signedInAs' => 2, -'com.woltlab.wcf.user.statsSidebar' => 3 -)); -DashboardHandler::setDefaultValues('com.woltlab.wcf.user.MembersListPage', array( -'com.woltlab.wcf.user.newestMembers' => 1, -'com.woltlab.wcf.user.mostActiveMembers' => 2 -)); +// set default landing page +$sql = "UPDATE wcf".WCF_N."_page + SET isLandingPage = ? + WHERE identifier = ?"; +$statement = WCF::getDB()->prepareStatement($sql); +$statement->execute([ + 1, + 'com.woltlab.wcf.Dashboard' +]); // update administrator user rank and user online marking $editor = new UserEditor(WCF::getUser()); diff --git a/wcfsetup/install/files/acp/templates/boxAdd.tpl b/wcfsetup/install/files/acp/templates/boxAdd.tpl index e77a9bed1e..dffbeac02f 100644 --- a/wcfsetup/install/files/acp/templates/boxAdd.tpl +++ b/wcfsetup/install/files/acp/templates/boxAdd.tpl @@ -120,16 +120,16 @@ - -
+ +
- - {if $errorField == 'className'} + + {if $errorField == 'controller'} {if $errorType == 'empty'} {lang}wcf.global.form.error.empty{/lang} {else} - {lang}wcf.acp.box.className.error.{@$errorType}{/lang} + {lang}wcf.acp.box.controller.error.{@$errorType}{/lang} {/if} {/if} diff --git a/wcfsetup/install/files/lib/acp/form/BoxAddForm.class.php b/wcfsetup/install/files/lib/acp/form/BoxAddForm.class.php index 35c5889e77..a309a6b53b 100644 --- a/wcfsetup/install/files/lib/acp/form/BoxAddForm.class.php +++ b/wcfsetup/install/files/lib/acp/form/BoxAddForm.class.php @@ -79,10 +79,10 @@ class BoxAddForm extends AbstractForm { public $showHeader = 1; /** - * php class name + * box controller * @var string */ - public $className = ''; + public $controller = ''; /** * box name @@ -143,7 +143,7 @@ class BoxAddForm extends AbstractForm { if (isset($_POST['visibleEverywhere'])) $this->visibleEverywhere = intval($_POST['visibleEverywhere']); if (isset($_POST['cssClassName'])) $this->cssClassName = StringUtil::trim($_POST['cssClassName']); if (isset($_POST['showHeader'])) $this->showHeader = intval($_POST['showHeader']); - if (isset($_POST['className'])) $this->className = StringUtil::trim($_POST['className']); + if (isset($_POST['controller'])) $this->controller = StringUtil::trim($_POST['controller']); if (isset($_POST['pageIDs']) && is_array($_POST['pageIDs'])) $this->pageIDs = ArrayUtil::toIntegerArray($_POST['pageIDs']); if (isset($_POST['title']) && is_array($_POST['title'])) $this->title = ArrayUtil::trim($_POST['title']); @@ -195,11 +195,11 @@ class BoxAddForm extends AbstractForm { // validate class name if ($this->boxType == 'system') { - if (empty($this->className)) { - throw new UserInputException('className'); + if (empty($this->controller)) { + throw new UserInputException('controller'); } - // @todo check class + // @todo check controller } // validate page ids @@ -273,7 +273,7 @@ class BoxAddForm extends AbstractForm { 'visibleEverywhere' => $this->visibleEverywhere, 'cssClassName' => $this->cssClassName, 'showHeader' => $this->showHeader, - 'className' => $this->className, + 'controller' => $this->controller, 'identifier' => '' ]), 'content' => $content, 'pageIDs' => $this->pageIDs ]); $returnValues = $this->objectAction->executeAction(); @@ -291,7 +291,7 @@ class BoxAddForm extends AbstractForm { WCF::getTPL()->assign('success', true); // reset variables - $this->boxType = $this->position = $this->cssClassName = $this->className = $this->name = ''; + $this->boxType = $this->position = $this->cssClassName = $this->controller = $this->name = ''; $this->showOrder = 0; $this->visibleEverywhere = $this->showHeader = 1; $this->title = $this->content = $this->images = $this->imageID = []; @@ -310,7 +310,7 @@ class BoxAddForm extends AbstractForm { 'boxType' => $this->boxType, 'position' => $this->position, 'cssClassName' => $this->cssClassName, - 'className' => $this->className, + 'controller' => $this->controller, 'showOrder' => $this->showOrder, 'visibleEverywhere' => $this->visibleEverywhere, 'showHeader' => $this->showHeader, diff --git a/wcfsetup/install/files/lib/acp/form/BoxEditForm.class.php b/wcfsetup/install/files/lib/acp/form/BoxEditForm.class.php index 2093691a9b..817e1adaca 100644 --- a/wcfsetup/install/files/lib/acp/form/BoxEditForm.class.php +++ b/wcfsetup/install/files/lib/acp/form/BoxEditForm.class.php @@ -96,7 +96,7 @@ class BoxEditForm extends BoxAddForm { 'visibleEverywhere' => $this->visibleEverywhere, 'cssClassName' => $this->cssClassName, 'showHeader' => $this->showHeader, - 'className' => $this->className + 'controller' => $this->controller ]), 'content' => $content, 'pageIDs' => $this->pageIDs]); $this->objectAction->executeAction(); @@ -127,7 +127,7 @@ class BoxEditForm extends BoxAddForm { $this->position = $this->box->position; $this->showOrder = $this->box->showOrder; $this->cssClassName = $this->box->cssClassName; - $this->className = $this->box->className; + $this->controller = $this->box->controller; if ($this->box->showHeader) $this->showHeader = 1; if ($this->box->visibleEverywhere) $this->visibleEverywhere = 1; else $this->visibleEverywhere = 0; diff --git a/wcfsetup/install/files/lib/data/box/Box.class.php b/wcfsetup/install/files/lib/data/box/Box.class.php index fd32df450e..3082e4a0c1 100644 --- a/wcfsetup/install/files/lib/data/box/Box.class.php +++ b/wcfsetup/install/files/lib/data/box/Box.class.php @@ -30,7 +30,7 @@ use wcf\util\StringUtil; * @property-read integer $showHeader * @property-read integer $originIsSystem * @property-read integer $packageID - * @property-read string $className + * @property-read string $controller * @property-read integer|null $menuID */ class Box extends DatabaseObject { @@ -86,6 +86,12 @@ class Box extends DatabaseObject { */ protected $pageIDs; + /** + * box controller + * @var \wcf\system\box\IBoxController + */ + protected $__controller; + /** * Returns true if the active user can delete this box. * @@ -219,8 +225,20 @@ class Box extends DatabaseObject { return !empty($content); } + /** + * Returns the box controller. + * + * @return \wcf\system\box\IBoxController + */ public function getController() { - // @todo + if ($this->__controller === null) { + if ($this->controller && class_exists($this->controller)) { + $this->__controller = new $this->controller; + $this->__controller->setBox($this); + } + } + + return $this->__controller; } /** diff --git a/wcfsetup/install/files/lib/system/box/AbstractBoxController.class.php b/wcfsetup/install/files/lib/system/box/AbstractBoxController.class.php new file mode 100644 index 0000000000..ad303dbcd3 --- /dev/null +++ b/wcfsetup/install/files/lib/system/box/AbstractBoxController.class.php @@ -0,0 +1,117 @@ + + * @package com.woltlab.wcf + * @subpackage system.box + * @category Community Framework + */ +abstract class AbstractBoxController implements IBoxController { + /** + * database object of this box + * @var Box + */ + protected $box; + + /** + * box content + * @var string + */ + protected $content; + + /** + * supported box positions + * @var string[] + */ + protected $supportedPositions = []; + + /** + * @inheritDoc + */ + public function getTitle() { + return ''; + } + + /** + * @inheritDoc + */ + public function getContent() { + if ($this->content === null) { + $this->content = ''; + $this->loadContent(); + } + + return $this->content; + } + + /** + * @inheritDoc + */ + public function hasContent() { + return !empty($this->getContent()); + } + + /** + * @inheritDoc + */ + public function getImage() { + return null; + } + + /** + * @inheritDoc + */ + public function hasImage() { + return false; + } + + /** + * @inheritDoc + */ + public function getLink() { + return ''; + } + + /** + * @inheritDoc + */ + public function hasLink() { + return false; + } + + /** + * @inheritDoc + */ + public function getBox() { + return $this->box; + } + + /** + * @inheritDoc + */ + public function setBox(Box $box) { + $this->box = $box; + } + + /** + * @inheritDoc + */ + public function getSupportedPositions() { + if (!empty($this->supportedPositions)) { + return $this->supportedPositions; + } + + return Box::$availablePositions; + } + + /** + * Loads the content of this box. + */ + protected abstract function loadContent(); +} diff --git a/wcfsetup/install/files/lib/system/box/IBoxController.class.php b/wcfsetup/install/files/lib/system/box/IBoxController.class.php new file mode 100644 index 0000000000..c22f23e313 --- /dev/null +++ b/wcfsetup/install/files/lib/system/box/IBoxController.class.php @@ -0,0 +1,85 @@ + + * @package com.woltlab.wcf + * @subpackage system.box + * @category Community Framework + */ +interface IBoxController { + /** + * Returns the title of this box. + * + * @return string + */ + public function getTitle(); + + /** + * Returns the content of this box. + * + * @return string + */ + public function getContent(); + + /** + * Returns false if this box has no content. + * + * @return boolean + */ + public function hasContent(); + + /** + * Returns the image of this box. + * + * @return \wcf\data\media\ViewableMedia + */ + public function getImage(); + + /** + * Returns true if this box has an image. + * + * @return boolean + */ + public function hasImage(); + + /** + * Returns the title link of this box. + * + * @return string + */ + public function getLink(); + + /** + * Returns true if this box has a title link. + * + * @return boolean + */ + public function hasLink(); + + /** + * Returns the database object of this box. + * + * @return Box + */ + public function getBox(); + + /** + * Sets the database object of this box. + * + * @param Box $box + */ + public function setBox(Box $box); + + /** + * Returns a list of supported box positions. + * + * @return string[] + */ + public function getSupportedPositions(); +} \ No newline at end of file diff --git a/wcfsetup/install/files/lib/system/box/RecentActivityBoxController.class.php b/wcfsetup/install/files/lib/system/box/RecentActivityBoxController.class.php new file mode 100644 index 0000000000..70a3ac8b50 --- /dev/null +++ b/wcfsetup/install/files/lib/system/box/RecentActivityBoxController.class.php @@ -0,0 +1,94 @@ + + * @package com.woltlab.wcf + * @subpackage system.box + * @category Community Framework + */ +class RecentActivityBoxController extends AbstractBoxController { + /** + * @inheritDoc + */ + protected $supportedPositions = ['contentTop', 'contentBottom', 'sidebarLeft', 'sidebarRight']; + + /** + * @inheritDoc + */ + public function getTitle() { + return WCF::getLanguage()->get('wcf.user.recentActivity'); + } + + /** + * @inheritDoc + */ + public function getLink() { + return LinkHandler::getInstance()->getLink('RecentActivityList'); + } + + /** + * @inheritDoc + */ + public function hasLink() { + return true; + } + + /** + * @inheritDoc + */ + protected function loadContent() { + if ($this->getBox()->position == 'contentTop' || $this->getBox()->position == 'contentBottom') { + $canFilterByFollowedUsers = $filteredByFollowedUsers = false; + if (WCF::getUser()->userID && count(WCF::getUserProfileHandler()->getFollowingUsers())) { + $canFilterByFollowedUsers = true; + } + + $eventList = new ViewableUserActivityEventList(); + if ($canFilterByFollowedUsers && WCF::getUser()->recentActivitiesFilterByFollowing) { + $filteredByFollowedUsers = true; + $eventList->getConditionBuilder()->add('user_activity_event.userID IN (?)', [WCF::getUserProfileHandler()->getFollowingUsers()]); + } + $eventList->sqlLimit = RECENT_ACTIVITY_ITEMS; + $eventList->readObjects(); + $lastEventTime = $eventList->getLastEventTime(); + + // removes orphaned and non-accessable events + UserActivityEventHandler::validateEvents($eventList); + + if (count($eventList) || $filteredByFollowedUsers) { + WCF::getTPL()->assign([ + 'canFilterByFollowedUsers' => $canFilterByFollowedUsers, + 'eventList' => $eventList, 'lastEventTime' => $lastEventTime, + 'filteredByFollowedUsers' => $filteredByFollowedUsers + ]); + + $this->content = WCF::getTPL()->fetch('boxRecentActivity'); + } + } + else { + $eventList = new ViewableUserActivityEventList(); + $eventList->sqlLimit = RECENT_ACTIVITY_SIDEBAR_ITEMS; + $eventList->readObjects(); + + // removes orphaned and non-accessable events + UserActivityEventHandler::validateEvents($eventList); + + if (count($eventList)) { + WCF::getTPL()->assign([ + 'eventList' => $eventList + ]); + + $this->content = WCF::getTPL()->fetch('boxRecentActivitySidebar'); + } + } + } +} diff --git a/wcfsetup/install/files/lib/system/package/PackageUninstallationDispatcher.class.php b/wcfsetup/install/files/lib/system/package/PackageUninstallationDispatcher.class.php index af195827e1..710422cc6c 100644 --- a/wcfsetup/install/files/lib/system/package/PackageUninstallationDispatcher.class.php +++ b/wcfsetup/install/files/lib/system/package/PackageUninstallationDispatcher.class.php @@ -126,7 +126,7 @@ class PackageUninstallationDispatcher extends PackageInstallationDispatcher { */ protected function executeUninstallScript() { // check if uninstall script file for the uninstalled package exists - $uninstallScript = WCF_DIR.'acp/uninstall/'.$this->package->package.'.php'; + $uninstallScript = WCF_DIR.'acp/uninstall/'.$this->getPackage()->package.'.php'; if (file_exists($uninstallScript)) { include($uninstallScript); } diff --git a/wcfsetup/install/files/lib/system/package/plugin/BoxPackageInstallationPlugin.class.php b/wcfsetup/install/files/lib/system/package/plugin/BoxPackageInstallationPlugin.class.php index 07b67f4441..33672ddc69 100644 --- a/wcfsetup/install/files/lib/system/package/plugin/BoxPackageInstallationPlugin.class.php +++ b/wcfsetup/install/files/lib/system/package/plugin/BoxPackageInstallationPlugin.class.php @@ -2,6 +2,7 @@ namespace wcf\system\package\plugin; use wcf\data\box\Box; use wcf\data\box\BoxEditor; +use wcf\system\database\util\PreparedStatementConditionBuilder; use wcf\system\exception\SystemException; use wcf\system\WCF; @@ -26,6 +27,12 @@ class BoxPackageInstallationPlugin extends AbstractXMLPackageInstallationPlugin */ public $tagName = 'box'; + /** + * visibility exceptions per box + * @var string[] + */ + public $visibilityExceptions = []; + /** * @inheritDoc */ @@ -84,6 +91,13 @@ class BoxPackageInstallationPlugin extends AbstractXMLPackageInstallationPlugin 'title' => $children['title'] ]; } + else if ($element->tagName === 'visibilityExceptions') { + $elements['visibilityExceptions'] = []; + /** @var \DOMElement $child */ + foreach ($xpath->query('child::*', $element) as $child) { + $elements['visibilityExceptions'][] = $child->nodeValue; + } + } else { $elements[$element->tagName] = $nodeValue; } @@ -95,7 +109,7 @@ class BoxPackageInstallationPlugin extends AbstractXMLPackageInstallationPlugin */ protected function prepareImport(array $data) { $boxType = $data['elements']['boxType']; - $className = ''; + $controller = ''; $identifier = $data['attributes']['identifier']; $isMultilingual = false; $position = $data['elements']['position']; @@ -106,15 +120,16 @@ class BoxPackageInstallationPlugin extends AbstractXMLPackageInstallationPlugin switch ($boxType) { case 'system': - if (empty($data['elements']['className'])) { - throw new SystemException("Missing required element 'classname' for 'system'-type box '{$identifier}'"); + if (empty($data['elements']['controller'])) { + throw new SystemException("Missing required element 'controller' for 'system'-type box '{$identifier}'"); } - $className = $data['elements']['className']; + $controller = $data['elements']['controller']; break; case 'html': case 'text': + case 'tpl': if (empty($data['elements']['content'])) { throw new SystemException("Missing required 'content' element(s) for box '{$identifier}'"); } @@ -139,6 +154,10 @@ class BoxPackageInstallationPlugin extends AbstractXMLPackageInstallationPlugin break; } + if (!empty($data['elements']['visibilityExceptions'])) { + $this->visibilityExceptions[$identifier] = $data['elements']['visibilityExceptions']; + } + return [ 'identifier' => $identifier, 'name' => $this->getI18nValues($data['elements']['name'], true), @@ -150,7 +169,7 @@ class BoxPackageInstallationPlugin extends AbstractXMLPackageInstallationPlugin 'cssClassName' => (!empty($data['elements']['cssClassName'])) ? $data['elements']['cssClassName'] : '', 'showHeader' => (!empty($data['elements']['showHeader'])) ? 1 : 0, 'originIsSystem' => 1, - 'className' => $className + 'controller' => $controller ]; } @@ -204,4 +223,57 @@ class BoxPackageInstallationPlugin extends AbstractXMLPackageInstallationPlugin return parent::import($row, $data); } + + /** + * @inheritDoc + */ + protected function postImport() { + if (empty($this->visibilityExceptions)) return; + + // get all boxes belonging to the identifiers + $conditions = new PreparedStatementConditionBuilder(); + $conditions->add("identifier IN (?)", [array_keys($this->visibilityExceptions)]); + $conditions->add("packageID = ?", [$this->installation->getPackageID()]); + + $sql = "SELECT * + FROM wcf".WCF_N."_box + ".$conditions; + $statement = WCF::getDB()->prepareStatement($sql); + $statement->execute($conditions->getParameters()); + $boxes = []; + while ($box = $statement->fetchObject(Box::class)) { + $boxes[$box->identifier] = $box; + } + + // save visibility exceptions + $sql = "DELETE FROM wcf".WCF_N."_box_to_page + WHERE boxID = ?"; + $deleteStatement = WCF::getDB()->prepareStatement($sql); + $sql = "INSERT IGNORE wcf".WCF_N."_box_to_page + (boxID, pageID, visible) + VALUES (?, ?, ?)"; + $insertStatement = WCF::getDB()->prepareStatement($sql); + foreach ($this->visibilityExceptions as $boxIdentifier => $pages) { + // delete old visibility exceptions + $deleteStatement->execute([$boxes[$boxIdentifier]->boxID]); + + // get page ids + $conditionBuilder = new PreparedStatementConditionBuilder(); + $conditionBuilder->add('identifier IN (?)', array($pages)); + $sql = "SELECT pageID + FROM wcf".WCF_N."_page + ".$conditionBuilder; + $statement = WCF::getDB()->prepareStatement($sql); + $statement->execute($conditionBuilder->getParameters()); + $pageIDs = []; + while ($row = $statement->fetchArray()) { + $pageIDs[] = $row['pageID']; + } + + // save page ids + foreach ($pageIDs as $pageID) { + $insertStatement->execute([$boxes[$boxIdentifier]->boxID, $pageID, ($boxes[$boxIdentifier]->visibleEverywhere ? 0 : 1)]); + } + } + } } diff --git a/wcfsetup/install/files/lib/system/package/plugin/MenuPackageInstallationPlugin.class.php b/wcfsetup/install/files/lib/system/package/plugin/MenuPackageInstallationPlugin.class.php index 27f3bb872e..82cec96692 100644 --- a/wcfsetup/install/files/lib/system/package/plugin/MenuPackageInstallationPlugin.class.php +++ b/wcfsetup/install/files/lib/system/package/plugin/MenuPackageInstallationPlugin.class.php @@ -27,6 +27,12 @@ class MenuPackageInstallationPlugin extends AbstractXMLPackageInstallationPlugin */ public $boxData = []; + /** + * visibility exceptions per box + * @var string[] + */ + public $visibilityExceptions = []; + /** * @inheritDoc */ @@ -88,6 +94,13 @@ class MenuPackageInstallationPlugin extends AbstractXMLPackageInstallationPlugin $elements['box']['name'][$element->getAttribute('language')] = $element->nodeValue; } + else if ($child->tagName === 'visibilityExceptions') { + $elements['box']['visibilityExceptions'] = []; + /** @var \DOMElement $child */ + foreach ($xpath->query('child::*', $child) as $child2) { + $elements['box']['visibilityExceptions'][] = $child2->nodeValue; + } + } else { $elements['box'][$child->tagName] = $child->nodeValue; } @@ -126,6 +139,10 @@ class MenuPackageInstallationPlugin extends AbstractXMLPackageInstallationPlugin 'packageID' => $this->installation->getPackageID() ]; + if (!empty($data['elements']['box']['visibilityExceptions'])) { + $this->visibilityExceptions[$identifier] = $data['elements']['box']['visibilityExceptions']; + } + unset($data['elements']['box']); } @@ -199,22 +216,57 @@ class MenuPackageInstallationPlugin extends AbstractXMLPackageInstallationPlugin $menus[$menu->identifier] = $menu; } + // handle visibility exceptions + $sql = "DELETE FROM wcf".WCF_N."_box_to_page + WHERE boxID = ?"; + $deleteStatement = WCF::getDB()->prepareStatement($sql); + $sql = "INSERT IGNORE wcf".WCF_N."_box_to_page + (boxID, pageID, visible) + VALUES (?, ?, ?)"; + $insertStatement = WCF::getDB()->prepareStatement($sql); foreach ($this->boxData as $identifier => $data) { // connect box with menu if (isset($menus[$identifier])) { $data['menuID'] = $menus[$identifier]->menuID; } + $box = null; if (isset($boxes[$identifier])) { + $box = $boxes[$identifier]; + + // delete old visibility exceptions + $deleteStatement->execute([$box->boxID]); + // skip both 'identifier' and 'packageID' as these properties are immutable unset($data['identifier']); unset($data['packageID']); - $boxEditor = new BoxEditor($boxes[$identifier]); + $boxEditor = new BoxEditor($box); $boxEditor->update($data); } else { - BoxEditor::create($data); + $box = BoxEditor::create($data); + } + + // save visibility exceptions + if (!empty($this->visibilityExceptions[$identifier])) { + // get page ids + $conditionBuilder = new PreparedStatementConditionBuilder(); + $conditionBuilder->add('identifier IN (?)', [$this->visibilityExceptions[$identifier]]); + $sql = "SELECT pageID + FROM wcf" . WCF_N . "_page + " . $conditionBuilder; + $statement = WCF::getDB()->prepareStatement($sql); + $statement->execute($conditionBuilder->getParameters()); + $pageIDs = []; + while ($row = $statement->fetchArray()) { + $pageIDs[] = $row['pageID']; + } + + // save page ids + foreach ($pageIDs as $pageID) { + $insertStatement->execute([$box->boxID, $pageID, ($box->visibleEverywhere ? 0 : 1)]); + } } } } diff --git a/wcfsetup/install/files/lib/system/package/plugin/PagePackageInstallationPlugin.class.php b/wcfsetup/install/files/lib/system/package/plugin/PagePackageInstallationPlugin.class.php index cd8bed25b1..13d26ac66e 100644 --- a/wcfsetup/install/files/lib/system/package/plugin/PagePackageInstallationPlugin.class.php +++ b/wcfsetup/install/files/lib/system/package/plugin/PagePackageInstallationPlugin.class.php @@ -88,6 +88,7 @@ class PagePackageInstallationPlugin extends AbstractXMLPackageInstallationPlugin */ protected function prepareImport(array $data) { $isStatic = false; + if (!empty($data['elements']['content'])) { $isStatic = true; @@ -260,18 +261,23 @@ class PagePackageInstallationPlugin extends AbstractXMLPackageInstallationPlugin WCF::getDB()->beginTransaction(); foreach ($this->content as $pageID => $contentData) { foreach ($contentData as $languageCode => $content) { - $language = LanguageFactory::getInstance()->getLanguageByCode($languageCode); - if ($language !== null) { - $statement->execute([ - $pageID, - $language->languageID, - $content['title'], - $content['content'], - $content['metaDescription'], - $content['metaKeywords'], - $content['customURL'] - ]); + $languageID = null; + if ($languageCode != '') { + $language = LanguageFactory::getInstance()->getLanguageByCode($languageCode); + if ($language === null) continue; + + $languageID = $language->languageID; } + + $statement->execute([ + $pageID, + $languageID, + $content['title'], + $content['content'], + $content['metaDescription'], + $content['metaKeywords'], + $content['customURL'] + ]); } } WCF::getDB()->commitTransaction(); diff --git a/wcfsetup/setup/db/install.sql b/wcfsetup/setup/db/install.sql index d925d0da8e..5ed7d56aff 100644 --- a/wcfsetup/setup/db/install.sql +++ b/wcfsetup/setup/db/install.sql @@ -237,7 +237,7 @@ CREATE TABLE wcf1_box ( showHeader TINYINT(1) NOT NULL DEFAULT 1, originIsSystem TINYINT(1) NOT NULL DEFAULT 0, packageID INT(10) NOT NULL, - className VARCHAR(255) NOT NULL DEFAULT '', + controller VARCHAR(255) NOT NULL DEFAULT '', menuID INT(10) NULL ); -- 2.20.1