From 5f33aa5b4f6a9a78fdaf848ebe007e9be04f2c54 Mon Sep 17 00:00:00 2001 From: Bob Trahan Date: Mon, 19 May 2014 16:09:31 -0700 Subject: [PATCH] Dashboards - add ability to install dashboard as home Summary: See title. Adds PhabricatorDashboardInstall data object which scopes installs to objectPHID + applicationClass. This is because we already have a collision for user home pages and user profiles. Assume only one dashboard per objectPHID + applicationClass though at the database level. Fixes T5076. Test Plan: From dashboard view, installed a dashboard - success! Went back to dashboard view and uninstalled it! Reviewers: chad, epriestley Reviewed By: epriestley Subscribers: epriestley, Korvin Maniphest Tasks: T5076 Differential Revision: https://secure.phabricator.com/D9206 --- .../autopatches/20140519.dashboardinstall.sql | 10 ++ src/__phutil_library_map__.php | 6 + .../PhabricatorApplicationDashboard.php | 2 + .../PhabricatorDashboardInstallController.php | 139 ++++++++++++++++++ ...habricatorDashboardUninstallController.php | 136 +++++++++++++++++ .../PhabricatorDashboardViewController.php | 20 +++ .../storage/PhabricatorDashboardInstall.php | 38 +++++ .../PhabricatorHomeMainController.php | 44 ++++-- 8 files changed, 380 insertions(+), 15 deletions(-) create mode 100644 resources/sql/autopatches/20140519.dashboardinstall.sql create mode 100644 src/applications/dashboard/controller/PhabricatorDashboardInstallController.php create mode 100644 src/applications/dashboard/controller/PhabricatorDashboardUninstallController.php create mode 100644 src/applications/dashboard/storage/PhabricatorDashboardInstall.php diff --git a/resources/sql/autopatches/20140519.dashboardinstall.sql b/resources/sql/autopatches/20140519.dashboardinstall.sql new file mode 100644 index 0000000000..71bd551e92 --- /dev/null +++ b/resources/sql/autopatches/20140519.dashboardinstall.sql @@ -0,0 +1,10 @@ +CREATE TABLE {$NAMESPACE}_dashboard.dashboard_install ( + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + installerPHID VARCHAR(64) NOT NULL COLLATE utf8_bin, + objectPHID VARCHAR(64) NOT NULL COLLATE utf8_bin, + applicationClass VARCHAR(64) NOT NULL COLLATE utf8_bin, + dashboardPHID VARCHAR(64) NOT NULL COLLATE utf8_bin, + dateCreated INT UNSIGNED NOT NULL, + dateModified INT UNSIGNED NOT NULL, + UNIQUE KEY (objectPHID, applicationClass) +) ENGINE=InnoDB, COLLATE utf8_general_ci; diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 6dd9cddcdd..437aedb09b 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1463,6 +1463,8 @@ phutil_register_library_map(array( 'PhabricatorDashboardController' => 'applications/dashboard/controller/PhabricatorDashboardController.php', 'PhabricatorDashboardDAO' => 'applications/dashboard/storage/PhabricatorDashboardDAO.php', 'PhabricatorDashboardEditController' => 'applications/dashboard/controller/PhabricatorDashboardEditController.php', + 'PhabricatorDashboardInstall' => 'applications/dashboard/storage/PhabricatorDashboardInstall.php', + 'PhabricatorDashboardInstallController' => 'applications/dashboard/controller/PhabricatorDashboardInstallController.php', 'PhabricatorDashboardLayoutConfig' => 'applications/dashboard/layoutconfig/PhabricatorDashboardLayoutConfig.php', 'PhabricatorDashboardListController' => 'applications/dashboard/controller/PhabricatorDashboardListController.php', 'PhabricatorDashboardMovePanelController' => 'applications/dashboard/controller/PhabricatorDashboardMovePanelController.php', @@ -1493,6 +1495,7 @@ phutil_register_library_map(array( 'PhabricatorDashboardTransaction' => 'applications/dashboard/storage/PhabricatorDashboardTransaction.php', 'PhabricatorDashboardTransactionEditor' => 'applications/dashboard/editor/PhabricatorDashboardTransactionEditor.php', 'PhabricatorDashboardTransactionQuery' => 'applications/dashboard/query/PhabricatorDashboardTransactionQuery.php', + 'PhabricatorDashboardUninstallController' => 'applications/dashboard/controller/PhabricatorDashboardUninstallController.php', 'PhabricatorDashboardViewController' => 'applications/dashboard/controller/PhabricatorDashboardViewController.php', 'PhabricatorDataNotAttachedException' => 'infrastructure/storage/lisk/PhabricatorDataNotAttachedException.php', 'PhabricatorDebugController' => 'applications/system/controller/PhabricatorDebugController.php', @@ -4247,6 +4250,8 @@ phutil_register_library_map(array( 'PhabricatorDashboardController' => 'PhabricatorController', 'PhabricatorDashboardDAO' => 'PhabricatorLiskDAO', 'PhabricatorDashboardEditController' => 'PhabricatorDashboardController', + 'PhabricatorDashboardInstall' => 'PhabricatorDashboardDAO', + 'PhabricatorDashboardInstallController' => 'PhabricatorDashboardController', 'PhabricatorDashboardListController' => 'PhabricatorDashboardController', 'PhabricatorDashboardMovePanelController' => 'PhabricatorDashboardController', 'PhabricatorDashboardPHIDTypeDashboard' => 'PhabricatorPHIDType', @@ -4285,6 +4290,7 @@ phutil_register_library_map(array( 'PhabricatorDashboardTransaction' => 'PhabricatorApplicationTransaction', 'PhabricatorDashboardTransactionEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorDashboardTransactionQuery' => 'PhabricatorApplicationTransactionQuery', + 'PhabricatorDashboardUninstallController' => 'PhabricatorDashboardController', 'PhabricatorDashboardViewController' => 'PhabricatorDashboardController', 'PhabricatorDataNotAttachedException' => 'Exception', 'PhabricatorDebugController' => 'PhabricatorController', diff --git a/src/applications/dashboard/application/PhabricatorApplicationDashboard.php b/src/applications/dashboard/application/PhabricatorApplicationDashboard.php index 7572688e64..d18aa348a6 100644 --- a/src/applications/dashboard/application/PhabricatorApplicationDashboard.php +++ b/src/applications/dashboard/application/PhabricatorApplicationDashboard.php @@ -24,6 +24,8 @@ final class PhabricatorApplicationDashboard extends PhabricatorApplication { 'arrange/(?P\d+)/' => 'PhabricatorDashboardArrangeController', 'create/' => 'PhabricatorDashboardEditController', 'edit/(?:(?P\d+)/)?' => 'PhabricatorDashboardEditController', + 'install/(?P\d+)/' => 'PhabricatorDashboardInstallController', + 'uninstall/(?P\d+)/' => 'PhabricatorDashboardUninstallController', 'addpanel/(?P\d+)/' => 'PhabricatorDashboardAddPanelController', 'movepanel/(?P\d+)/' => 'PhabricatorDashboardMovePanelController', 'removepanel/(?P\d+)/' diff --git a/src/applications/dashboard/controller/PhabricatorDashboardInstallController.php b/src/applications/dashboard/controller/PhabricatorDashboardInstallController.php new file mode 100644 index 0000000000..1c4da16dd8 --- /dev/null +++ b/src/applications/dashboard/controller/PhabricatorDashboardInstallController.php @@ -0,0 +1,139 @@ +id = idx($data, 'id'); + } + + public function processRequest() { + $request = $this->getRequest(); + $viewer = $request->getUser(); + + $dashboard = id(new PhabricatorDashboardQuery()) + ->setViewer($viewer) + ->withIDs(array($this->id)) + ->executeOne(); + if (!$dashboard) { + return new Aphront404Response(); + } + $dashboard_phid = $dashboard->getPHID(); + + $object_phid = $request->getStr('objectPHID', $viewer->getPHID()); + $object = id(new PhabricatorObjectQuery()) + ->setViewer($viewer) + ->requireCapabilities( + array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + )) + ->withPHIDs(array($object_phid)) + ->executeOne(); + if (!$object) { + return new Aphront404Response(); + } + + $installer_phid = $viewer->getPHID(); + $application_class = $request->getStr( + 'applicationClass', + 'PhabricatorApplicationHome'); + + $handles = $this->loadHandles(array( + $object_phid, + $installer_phid)); + + if ($request->isFormPost()) { + $dashboard_install = id(new PhabricatorDashboardInstall()) + ->loadOneWhere( + 'objectPHID = %s AND applicationClass = %s', + $object_phid, + $application_class); + if (!$dashboard_install) { + $dashboard_install = id(new PhabricatorDashboardInstall()) + ->setObjectPHID($object_phid) + ->setApplicationClass($application_class); + } + $dashboard_install + ->setInstallerPHID($installer_phid) + ->setDashboardPHID($dashboard_phid) + ->save(); + return id(new AphrontRedirectResponse()) + ->setURI($this->getRedirectURI($application_class, $object_phid)); + } + + $body = $this->getBodyContent( + $application_class, + $object_phid, + $installer_phid); + + $form = id(new AphrontFormView()) + ->setUser($viewer) + ->appendChild($body); + + return $this->newDialog() + ->setTitle(pht('Install Dashboard')) + ->appendChild($form->buildLayoutView()) + ->addCancelButton($this->getCancelURI( + $application_class, $object_phid)) + ->addSubmitButton(pht('Install Dashboard')); + } + + private function getBodyContent( + $application_class, + $object_phid, + $installer_phid) { + + $body = array(); + switch ($application_class) { + case 'PhabricatorApplicationHome': + if ($installer_phid == $object_phid) { + $body[] = phutil_tag( + 'p', + array(), + pht( + 'Are you sure you want to install this dashboard as your '. + 'home page?')); + $body[] = phutil_tag( + 'p', + array(), + pht( + 'You will be re-directed to your spiffy new home page if you '. + 'choose to install this dashboard.')); + } else { + $body[] = phutil_tag( + 'p', + array(), + pht( + 'Are you sure you want to install this dashboard as the home '. + 'page for %s?', + $this->getHandle($object_phid)->getName())); + } + break; + } + return $body; + } + + private function getCancelURI($application_class, $object_phid) { + $uri = null; + switch ($application_class) { + case 'PhabricatorApplicationHome': + $uri = '/dashboard/view/'.$this->id.'/'; + break; + } + return $uri; + } + + private function getRedirectURI($application_class, $object_phid) { + $uri = null; + switch ($application_class) { + case 'PhabricatorApplicationHome': + $uri = '/'; + break; + } + return $uri; + } + +} diff --git a/src/applications/dashboard/controller/PhabricatorDashboardUninstallController.php b/src/applications/dashboard/controller/PhabricatorDashboardUninstallController.php new file mode 100644 index 0000000000..2b36fbee92 --- /dev/null +++ b/src/applications/dashboard/controller/PhabricatorDashboardUninstallController.php @@ -0,0 +1,136 @@ +id = idx($data, 'id'); + } + + public function processRequest() { + $request = $this->getRequest(); + $viewer = $request->getUser(); + + $dashboard = id(new PhabricatorDashboardQuery()) + ->setViewer($viewer) + ->withIDs(array($this->id)) + ->executeOne(); + if (!$dashboard) { + return new Aphront404Response(); + } + $dashboard_phid = $dashboard->getPHID(); + + $object_phid = $request->getStr('objectPHID', $viewer->getPHID()); + $object = id(new PhabricatorObjectQuery()) + ->setViewer($viewer) + ->requireCapabilities( + array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + )) + ->withPHIDs(array($object_phid)) + ->executeOne(); + if (!$object) { + return new Aphront404Response(); + } + + $application_class = $request->getStr( + 'applicationClass', + 'PhabricatorApplicationHome'); + + $dashboard_install = id(new PhabricatorDashboardInstall()) + ->loadOneWhere( + 'objectPHID = %s AND applicationClass = %s', + $object_phid, + $application_class); + if (!$dashboard_install) { + return new Aphront404Response(); + } + if ($dashboard_install->getDashboardPHID() != $dashboard_phid) { + return new Aphront404Response(); + } + + $installer_phid = $viewer->getPHID(); + $handles = $this->loadHandles(array($object_phid, $installer_phid)); + + if ($request->isFormPost()) { + $dashboard_install->delete(); + return id(new AphrontRedirectResponse()) + ->setURI($this->getRedirectURI($application_class, $object_phid)); + } + + $body = $this->getBodyContent( + $application_class, + $object_phid, + $installer_phid); + + $form = id(new AphrontFormView()) + ->setUser($viewer) + ->appendChild($body); + + return $this->newDialog() + ->setTitle(pht('Uninstall Dashboard')) + ->appendChild($form->buildLayoutView()) + ->addCancelButton($this->getCancelURI( + $application_class, $object_phid)) + ->addSubmitButton(pht('Uninstall Dashboard')); + } + + private function getBodyContent( + $application_class, + $object_phid, + $installer_phid) { + + $body = array(); + switch ($application_class) { + case 'PhabricatorApplicationHome': + if ($installer_phid == $object_phid) { + $body[] = phutil_tag( + 'p', + array(), + pht( + 'Are you sure you want to uninstall this dashboard as your '. + 'home page?')); + $body[] = phutil_tag( + 'p', + array(), + pht( + 'You will be re-directed to your bland, default home page if '. + 'you choose to uninstall this dashboard.')); + } else { + $body[] = phutil_tag( + 'p', + array(), + pht( + 'Are you sure you want to uninstall this dashboard as the home '. + 'page for %s?', + $this->getHandle($object_phid)->getName())); + } + break; + } + return $body; + } + + private function getCancelURI($application_class, $object_phid) { + $uri = null; + switch ($application_class) { + case 'PhabricatorApplicationHome': + $uri = '/dashboard/view/'.$this->id.'/'; + break; + } + return $uri; + } + + private function getRedirectURI($application_class, $object_phid) { + $uri = null; + switch ($application_class) { + case 'PhabricatorApplicationHome': + $uri = '/'; + break; + } + return $uri; + } + +} diff --git a/src/applications/dashboard/controller/PhabricatorDashboardViewController.php b/src/applications/dashboard/controller/PhabricatorDashboardViewController.php index dbf4848c4b..59fe51ae4a 100644 --- a/src/applications/dashboard/controller/PhabricatorDashboardViewController.php +++ b/src/applications/dashboard/controller/PhabricatorDashboardViewController.php @@ -92,6 +92,26 @@ final class PhabricatorDashboardViewController ->setDisabled(!$can_edit) ->setWorkflow(!$can_edit)); + $installed_dashboard = id(new PhabricatorDashboardInstall()) + ->loadOneWhere( + 'objectPHID = %s AND applicationClass = %s', + $viewer->getPHID(), + 'PhabricatorApplicationHome'); + if ($installed_dashboard && + $installed_dashboard->getDashboardPHID() == $dashboard->getPHID()) { + $title_install = pht('Uninstall Dashboard'); + $href_install = "uninstall/{$id}/"; + } else { + $title_install = pht('Install Dashboard'); + $href_install = "install/{$id}/"; + } + $actions->addAction( + id(new PhabricatorActionView()) + ->setName($title_install) + ->setIcon('fa-wrench') + ->setHref($this->getApplicationURI($href_install)) + ->setWorkflow(true)); + $actions->addAction( id(new PhabricatorActionView()) ->setName(pht('Add Panel')) diff --git a/src/applications/dashboard/storage/PhabricatorDashboardInstall.php b/src/applications/dashboard/storage/PhabricatorDashboardInstall.php new file mode 100644 index 0000000000..8d59d45c52 --- /dev/null +++ b/src/applications/dashboard/storage/PhabricatorDashboardInstall.php @@ -0,0 +1,38 @@ +loadOneWhere( + 'objectPHID = %s AND applicationClass = %s', + $object_phid, + $application_class); + if ($dashboard_install) { + $dashboard = id(new PhabricatorDashboardQuery()) + ->setViewer($viewer) + ->withPHIDs(array($dashboard_install->getDashboardPHID())) + ->needPanels(true) + ->executeOne(); + } + + return $dashboard; + } +} diff --git a/src/applications/home/controller/PhabricatorHomeMainController.php b/src/applications/home/controller/PhabricatorHomeMainController.php index a6b4004b66..adfad2863d 100644 --- a/src/applications/home/controller/PhabricatorHomeMainController.php +++ b/src/applications/home/controller/PhabricatorHomeMainController.php @@ -20,15 +20,36 @@ final class PhabricatorHomeMainController if ($this->filter == 'jump') { return $this->buildJumpResponse(); } - $nav = $this->buildNav(); - $project_query = new PhabricatorProjectQuery(); - $project_query->setViewer($user); - $project_query->withMemberPHIDs(array($user->getPHID())); - $projects = $project_query->execute(); + $dashboard = PhabricatorDashboardInstall::getDashboard( + $user, + $user->getPHID(), + get_class($this->getCurrentApplication())); + if ($dashboard) { + $rendered_dashboard = id(new PhabricatorDashboardRenderingEngine()) + ->setViewer($user) + ->setDashboard($dashboard) + ->renderDashboard(); + $nav->appendChild($rendered_dashboard); + } else { + $project_query = new PhabricatorProjectQuery(); + $project_query->setViewer($user); + $project_query->withMemberPHIDs(array($user->getPHID())); + $projects = $project_query->execute(); - return $this->buildMainResponse($nav, $projects); + $nav = $this->buildMainResponse($nav, $projects); + } + + $nav->appendChild(id(new PhabricatorGlobalUploadTargetView()) + ->setUser($user)); + + return $this->buildApplicationPage( + $nav, + array( + 'title' => 'Phabricator', + 'device' => true, + )); } private function buildMainResponse($nav, array $projects) { @@ -91,17 +112,10 @@ final class PhabricatorHomeMainController $this->minipanels, ); - $user = $this->getRequest()->getUser(); $nav->appendChild($content); - $nav->appendChild(id(new PhabricatorGlobalUploadTargetView()) - ->setUser($user)); - return $this->buildApplicationPage( - $nav, - array( - 'title' => 'Phabricator', - 'device' => true, - )); + return $nav; + } private function buildJumpResponse() {