diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 8a729bcac2..f5df925d46 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -277,6 +277,7 @@ phutil_register_library_map(array( 'ConpherenceViewController' => 'applications/conpherence/controller/ConpherenceViewController.php', 'ConpherenceWidgetController' => 'applications/conpherence/controller/ConpherenceWidgetController.php', 'ConpherenceWidgetView' => 'applications/conpherence/view/ConpherenceWidgetView.php', + 'CountdownQuery' => 'applications/countdown/query/CountdownQuery.php', 'DarkConsoleController' => 'aphront/console/DarkConsoleController.php', 'DarkConsoleCore' => 'aphront/console/DarkConsoleCore.php', 'DarkConsoleDataController' => 'aphront/console/DarkConsoleDataController.php', @@ -2087,6 +2088,7 @@ phutil_register_library_map(array( 'ConpherenceViewController' => 'ConpherenceController', 'ConpherenceWidgetController' => 'ConpherenceController', 'ConpherenceWidgetView' => 'AphrontView', + 'CountdownQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'DarkConsoleController' => 'PhabricatorController', 'DarkConsoleDataController' => 'PhabricatorController', 'DarkConsoleErrorLogPlugin' => 'DarkConsolePlugin', @@ -2655,13 +2657,17 @@ phutil_register_library_map(array( 'PhabricatorContentSourceView' => 'AphrontView', 'PhabricatorController' => 'AphrontController', 'PhabricatorCoreConfigOptions' => 'PhabricatorApplicationConfigOptions', - 'PhabricatorCountdown' => 'PhabricatorCountdownDAO', + 'PhabricatorCountdown' => + array( + 0 => 'PhabricatorCountdownDAO', + 1 => 'PhabricatorPolicyInterface', + ), 'PhabricatorCountdownController' => 'PhabricatorController', 'PhabricatorCountdownDAO' => 'PhabricatorLiskDAO', 'PhabricatorCountdownDeleteController' => 'PhabricatorCountdownController', 'PhabricatorCountdownEditController' => 'PhabricatorCountdownController', 'PhabricatorCountdownListController' => 'PhabricatorCountdownController', - 'PhabricatorCountdownRemarkupRule' => 'PhutilRemarkupRule', + 'PhabricatorCountdownRemarkupRule' => 'PhabricatorRemarkupRuleObject', 'PhabricatorCountdownViewController' => 'PhabricatorCountdownController', 'PhabricatorCountedToggleButtonsExample' => 'PhabricatorUIExample', 'PhabricatorCrumbView' => 'AphrontView', diff --git a/src/applications/countdown/application/PhabricatorApplicationCountdown.php b/src/applications/countdown/application/PhabricatorApplicationCountdown.php index eaee1a8fbb..e83525e124 100644 --- a/src/applications/countdown/application/PhabricatorApplicationCountdown.php +++ b/src/applications/countdown/application/PhabricatorApplicationCountdown.php @@ -1,5 +1,8 @@ getRequest(); $user = $request->getUser(); - $timer = id(new PhabricatorCountdown())->load($this->id); - if (!$timer) { + $countdown = id(new CountdownQuery()) + ->setViewer($user) + ->withIDs(array($this->id)) + ->executeOne(); + + if (!$countdown) { return new Aphront404Response(); } - if (($timer->getAuthorPHID() !== $user->getPHID()) + if (($countdown->getAuthorPHID() !== $user->getPHID()) && $user->getIsAdmin() === false) { return new Aphront403Response(); } if ($request->isFormPost()) { - $timer->delete(); + $countdown->delete(); return id(new AphrontRedirectResponse()) ->setURI('/countdown/'); } $inst = pht('Are you sure you want to delete the countdown %s?', - $timer->getTitle()); + $countdown->getTitle()); $dialog = new AphrontDialogView(); $dialog->setUser($request->getUser()); diff --git a/src/applications/countdown/controller/PhabricatorCountdownEditController.php b/src/applications/countdown/controller/PhabricatorCountdownEditController.php index 452f34e3ab..4072412fd6 100644 --- a/src/applications/countdown/controller/PhabricatorCountdownEditController.php +++ b/src/applications/countdown/controller/PhabricatorCountdownEditController.php @@ -1,5 +1,8 @@ id) { - $timer = id(new PhabricatorCountdown())->load($this->id); - // If no timer is found - if (!$timer) { + $countdown = id(new CountdownQuery()) + ->setViewer($user) + ->withIDs(array($this->id)) + ->executeOne(); + + // If no countdown is found + if (!$countdown) { return new Aphront404Response(); } - if (($timer->getAuthorPHID() != $user->getPHID()) + if (($countdown->getAuthorPHID() != $user->getPHID()) && $user->getIsAdmin() == false) { return new Aphront403Response(); } $action_label = pht('Update Countdown'); } else { - $timer = new PhabricatorCountdown(); - $timer->setEpoch(time()); + $countdown = new PhabricatorCountdown(); + $countdown->setEpoch(time()); } $error_view = null; @@ -60,14 +67,14 @@ final class PhabricatorCountdownEditController $timestamp = null; } - $timer->setTitle($title); - $timer->setEpoch($timestamp); + $countdown->setTitle($title); + $countdown->setEpoch($timestamp); if (!count($errors)) { - $timer->setAuthorPHID($user->getPHID()); - $timer->save(); + $countdown->setAuthorPHID($user->getPHID()); + $countdown->save(); return id(new AphrontRedirectResponse()) - ->setURI('/countdown/'.$timer->getID().'/'); + ->setURI('/countdown/'.$countdown->getID().'/'); } else { $error_view = id(new AphrontErrorView()) ->setErrors($errors) @@ -76,9 +83,9 @@ final class PhabricatorCountdownEditController } } - if ($timer->getEpoch()) { + if ($countdown->getEpoch()) { $display_epoch = phabricator_datetime( - $timer->getEpoch(), + $countdown->getEpoch(), $user); } else { $display_epoch = $request->getStr('epoch'); @@ -90,7 +97,7 @@ final class PhabricatorCountdownEditController ->appendChild( id(new AphrontFormTextControl()) ->setLabel(pht('Title')) - ->setValue($timer->getTitle()) + ->setValue($countdown->getTitle()) ->setName('title')) ->appendChild( id(new AphrontFormTextControl()) diff --git a/src/applications/countdown/controller/PhabricatorCountdownListController.php b/src/applications/countdown/controller/PhabricatorCountdownListController.php index 2ead86805e..9cc0099b2e 100644 --- a/src/applications/countdown/controller/PhabricatorCountdownListController.php +++ b/src/applications/countdown/controller/PhabricatorCountdownListController.php @@ -1,5 +1,8 @@ getRequest(); $user = $request->getUser(); - $pager = new AphrontPagerView(); - $pager->setOffset($request->getInt('page')); - $pager->setURI($request->getRequestURI(), 'page'); + $pager = new AphrontCursorPagerView(); + $pager->readFromRequest($request); - $timers = id(new PhabricatorCountdown())->loadAllWhere( - '1 = 1 ORDER BY id DESC LIMIT %d, %d', - $pager->getOffset(), - $pager->getPageSize() + 1); + $query = id(new CountdownQuery()) + ->setViewer($user); - $timers = $pager->sliceResults($timers); + $countdowns = $query->executeWithCursorPager($pager); - $phids = mpull($timers, 'getAuthorPHID'); + $phids = mpull($countdowns, 'getAuthorPHID'); $handles = $this->loadViewerHandles($phids); $rows = array(); - foreach ($timers as $timer) { + foreach ($countdowns as $timer) { $edit_button = null; $delete_button = null; if ($user->getIsAdmin() || diff --git a/src/applications/countdown/controller/PhabricatorCountdownViewController.php b/src/applications/countdown/controller/PhabricatorCountdownViewController.php index aa04444365..b4cf4a684b 100644 --- a/src/applications/countdown/controller/PhabricatorCountdownViewController.php +++ b/src/applications/countdown/controller/PhabricatorCountdownViewController.php @@ -1,5 +1,8 @@ getRequest(); $user = $request->getUser(); - $timer = id(new PhabricatorCountdown())->load($this->id); - if (!$timer) { + + $countdown = id(new CountdownQuery()) + ->setViewer($user) + ->withIDs(array($this->id)) + ->executeOne(); + + if (!$countdown) { return new Aphront404Response(); } @@ -49,8 +57,8 @@ final class PhabricatorCountdownViewController %s ', $container, - $timer->getTitle(), - phabricator_datetime($timer->getEpoch(), $user), + $countdown->getTitle(), + phabricator_datetime($countdown->getEpoch(), $user), pht('Days'), pht('Hours'), pht('Minutes'), @@ -62,7 +70,7 @@ final class PhabricatorCountdownViewController $chrome_link); Javelin::initBehavior('countdown-timer', array( - 'timestamp' => $timer->getEpoch(), + 'timestamp' => $countdown->getEpoch(), 'container' => $container, )); @@ -72,7 +80,7 @@ final class PhabricatorCountdownViewController ->buildApplicationCrumbs() ->addCrumb( id(new PhabricatorCrumbView()) - ->setName($timer->getTitle()) + ->setName($countdown->getTitle()) ->setHref($this->getApplicationURI($this->id.'/'))); return $this->buildApplicationPage( @@ -81,7 +89,7 @@ final class PhabricatorCountdownViewController $panel, ), array( - 'title' => pht('Countdown: %s', $timer->getTitle()), + 'title' => pht('Countdown: %s', $countdown->getTitle()), 'chrome' => $chrome_visible, 'device' => true, )); diff --git a/src/applications/countdown/query/CountdownQuery.php b/src/applications/countdown/query/CountdownQuery.php new file mode 100644 index 0000000000..b89ab0eb9f --- /dev/null +++ b/src/applications/countdown/query/CountdownQuery.php @@ -0,0 +1,75 @@ +ids = $ids; + return $this; + } + + public function withPHIDs(array $phids) { + $this->phids = $phids; + return $this; + } + + public function withAuthorPHIDs(array $author_phids) { + $this->authorPHIDs = $author_phids; + return $this; + } + + protected function loadPage() { + $table = new PhabricatorCountdown(); + $conn_r = $table->establishConnection('r'); + + $data = queryfx_all( + $conn_r, + 'SELECT * FROM %T %Q %Q %Q', + $table->getTableName(), + $this->buildWhereClause($conn_r), + $this->buildOrderClause($conn_r), + $this->buildLimitClause($conn_r)); + + $countdowns = $table->loadAllFromArray($data); + + + return $countdowns; + } + + private function buildWhereClause(AphrontDatabaseConnection $conn_r) { + $where = array(); + + $where[] = $this->buildPagingClause($conn_r); + + if ($this->ids) { + $where[] = qsprintf( + $conn_r, + 'id IN (%Ld)', + $this->ids); + } + + if ($this->phids) { + $where[] = qsprintf( + $conn_r, + 'phid IN (%Ls)', + $this->phids); + } + + if ($this->authorPHIDs) { + $where[] = qsprintf( + $conn_r, + 'authorPHID in (%Ls)', + $this->authorPHIDs); + } + + return $this->formatWhereClause($where); + } + +} diff --git a/src/applications/countdown/remarkup/PhabricatorCountdownRemarkupRule.php b/src/applications/countdown/remarkup/PhabricatorCountdownRemarkupRule.php index cd35e0d358..8f11b333f5 100644 --- a/src/applications/countdown/remarkup/PhabricatorCountdownRemarkupRule.php +++ b/src/applications/countdown/remarkup/PhabricatorCountdownRemarkupRule.php @@ -1,81 +1,45 @@ load($matches[1]); - if (!$countdown) { - return $matches[0]; - } - - $engine = $this->getEngine(); - - if ($engine->isTextMode()) { - $date = $countdown->getEpoch(); - $viewer = $engine->getConfig('viewer'); - if ($viewer) { - $date = phabricator_datetime($date, $viewer); - } - return $engine->storeText($date); - } - - $id = celerity_generate_unique_node_id(); - $token = $engine->storeText(''); - - $metadata_key = self::KEY_RULE_COUNTDOWN; - $metadata = $engine->getTextMetadata($metadata_key, array()); - $metadata[$id] = array($countdown->getEpoch(), $token); - $engine->setTextMetadata($metadata_key, $metadata); - - return $token; + protected function loadObjects(array $ids) { + $viewer = $this->getEngine()->getConfig('viewer'); + return id(new CountdownQuery()) + ->setViewer($viewer) + ->withIDs($ids) + ->execute(); } - public function didMarkupText() { - $engine = $this->getEngine(); - - $metadata_key = self::KEY_RULE_COUNTDOWN; - $metadata = $engine->getTextMetadata($metadata_key, array()); - - if (!$metadata) { - return; - } - + protected function renderObjectEmbed($object, $handle, $options) { require_celerity_resource('javelin-behavior-countdown-timer'); - foreach ($metadata as $id => $info) { - list($time, $token) = $info; - $prefix = 'phabricator-timer-'; - $count = phutil_tag( - 'span', - array( - 'id' => $id, - ), - array( - javelin_tag('span', array('sigil' => $prefix.'days'), ''), 'd', - javelin_tag('span', array('sigil' => $prefix.'hours'), ''), 'h', - javelin_tag('span', array('sigil' => $prefix.'minutes'), ''), 'm', - javelin_tag('span', array('sigil' => $prefix.'seconds'), ''), 's', - )); - Javelin::initBehavior('countdown-timer', array( - 'timestamp' => $time, - 'container' => $id, + $prefix = 'phabricator-timer-'; + $counter = phutil_tag( + 'span', + array( + 'id' => $object->getPHID(), + ), + array( + javelin_tag('span', array('sigil' => $prefix.'days'), ''), 'd', + javelin_tag('span', array('sigil' => $prefix.'hours'), ''), 'h', + javelin_tag('span', array('sigil' => $prefix.'minutes'), ''), 'm', + javelin_tag('span', array('sigil' => $prefix.'seconds'), ''), 's', )); - $engine->overwriteStoredText($token, $count); - } - $engine->setTextMetadata($metadata_key, array()); + Javelin::initBehavior('countdown-timer', array( + 'timestamp' => $object->getEpoch(), + 'container' => $object->getPHID(), + )); + + return $counter; } } diff --git a/src/applications/countdown/storage/PhabricatorCountdown.php b/src/applications/countdown/storage/PhabricatorCountdown.php index f6a0e2eecd..114c1a0501 100644 --- a/src/applications/countdown/storage/PhabricatorCountdown.php +++ b/src/applications/countdown/storage/PhabricatorCountdown.php @@ -1,12 +1,17 @@ getViewPolicy(); + } + } + + public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { + return ($viewer->getPHID() == $this->getAuthorPHID()); + } + } diff --git a/src/applications/countdown/storage/PhabricatorCountdownDAO.php b/src/applications/countdown/storage/PhabricatorCountdownDAO.php index 50d05d149c..fecc8ffae6 100644 --- a/src/applications/countdown/storage/PhabricatorCountdownDAO.php +++ b/src/applications/countdown/storage/PhabricatorCountdownDAO.php @@ -1,5 +1,8 @@ setPHID($phid); + $handle->setType($type); + if (empty($objects[$phid])) { + $handle->setName('Unknown Countdown'); + } else { + $countdown = $objects[$phid]; + $handle->setName($countdown->getTitle()); + $handle->setFullName($countdown->getTitle()); + $handle->setURI('/countdown/'.$countdown->getID().'/'); + $handle->setComplete(true); + } + $handles[$phid] = $handle; + } + break; + default: $loader = null; if (isset($external_loaders[$type])) { diff --git a/src/applications/pholio/view/PholioMockEmbedView.php b/src/applications/pholio/view/PholioMockEmbedView.php index 77658a4caa..f578ea6f38 100644 --- a/src/applications/pholio/view/PholioMockEmbedView.php +++ b/src/applications/pholio/view/PholioMockEmbedView.php @@ -22,7 +22,6 @@ final class PholioMockEmbedView extends AphrontView { require_celerity_resource('pholio-css'); - $mock_link = phutil_tag( 'a', array(