@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Countdown revamp 2

Summary:
Now has policy support (not really)
Now uses CountdownQuery
Now has handles
Now uses common way for remarkup
Remarkup still looks terrible

Test Plan: Added countdowns, edited countdowns. Did even embed some. Couldn't break it

Reviewers: epriestley

Reviewed By: epriestley

CC: aran, Korvin, AnhNhan

Maniphest Tasks: T2624

Differential Revision: https://secure.phabricator.com/D6012

authored by

Lauri-Henrik Jalonen and committed by
epriestley
689c6f2f bc9c8cc0

+227 -105
+8 -2
src/__phutil_library_map__.php
··· 277 277 'ConpherenceViewController' => 'applications/conpherence/controller/ConpherenceViewController.php', 278 278 'ConpherenceWidgetController' => 'applications/conpherence/controller/ConpherenceWidgetController.php', 279 279 'ConpherenceWidgetView' => 'applications/conpherence/view/ConpherenceWidgetView.php', 280 + 'CountdownQuery' => 'applications/countdown/query/CountdownQuery.php', 280 281 'DarkConsoleController' => 'aphront/console/DarkConsoleController.php', 281 282 'DarkConsoleCore' => 'aphront/console/DarkConsoleCore.php', 282 283 'DarkConsoleDataController' => 'aphront/console/DarkConsoleDataController.php', ··· 2087 2088 'ConpherenceViewController' => 'ConpherenceController', 2088 2089 'ConpherenceWidgetController' => 'ConpherenceController', 2089 2090 'ConpherenceWidgetView' => 'AphrontView', 2091 + 'CountdownQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 2090 2092 'DarkConsoleController' => 'PhabricatorController', 2091 2093 'DarkConsoleDataController' => 'PhabricatorController', 2092 2094 'DarkConsoleErrorLogPlugin' => 'DarkConsolePlugin', ··· 2655 2657 'PhabricatorContentSourceView' => 'AphrontView', 2656 2658 'PhabricatorController' => 'AphrontController', 2657 2659 'PhabricatorCoreConfigOptions' => 'PhabricatorApplicationConfigOptions', 2658 - 'PhabricatorCountdown' => 'PhabricatorCountdownDAO', 2660 + 'PhabricatorCountdown' => 2661 + array( 2662 + 0 => 'PhabricatorCountdownDAO', 2663 + 1 => 'PhabricatorPolicyInterface', 2664 + ), 2659 2665 'PhabricatorCountdownController' => 'PhabricatorController', 2660 2666 'PhabricatorCountdownDAO' => 'PhabricatorLiskDAO', 2661 2667 'PhabricatorCountdownDeleteController' => 'PhabricatorCountdownController', 2662 2668 'PhabricatorCountdownEditController' => 'PhabricatorCountdownController', 2663 2669 'PhabricatorCountdownListController' => 'PhabricatorCountdownController', 2664 - 'PhabricatorCountdownRemarkupRule' => 'PhutilRemarkupRule', 2670 + 'PhabricatorCountdownRemarkupRule' => 'PhabricatorRemarkupRuleObject', 2665 2671 'PhabricatorCountdownViewController' => 'PhabricatorCountdownController', 2666 2672 'PhabricatorCountedToggleButtonsExample' => 'PhabricatorUIExample', 2667 2673 'PhabricatorCrumbView' => 'AphrontView',
+3
src/applications/countdown/application/PhabricatorApplicationCountdown.php
··· 1 1 <?php 2 2 3 + /** 4 + * @group countdown 5 + */ 3 6 final class PhabricatorApplicationCountdown extends PhabricatorApplication { 4 7 5 8 public function getBaseURI() {
+3
src/applications/countdown/controller/PhabricatorCountdownController.php
··· 1 1 <?php 2 2 3 + /** 4 + * @group countdown 5 + */ 3 6 abstract class PhabricatorCountdownController extends PhabricatorController { 4 7 5 8 public function buildSideNavView() {
+12 -5
src/applications/countdown/controller/PhabricatorCountdownDeleteController.php
··· 1 1 <?php 2 2 3 + /** 4 + * @group countdown 5 + */ 3 6 final class PhabricatorCountdownDeleteController 4 7 extends PhabricatorCountdownController { 5 8 ··· 14 17 $request = $this->getRequest(); 15 18 $user = $request->getUser(); 16 19 17 - $timer = id(new PhabricatorCountdown())->load($this->id); 18 - if (!$timer) { 20 + $countdown = id(new CountdownQuery()) 21 + ->setViewer($user) 22 + ->withIDs(array($this->id)) 23 + ->executeOne(); 24 + 25 + if (!$countdown) { 19 26 return new Aphront404Response(); 20 27 } 21 28 22 - if (($timer->getAuthorPHID() !== $user->getPHID()) 29 + if (($countdown->getAuthorPHID() !== $user->getPHID()) 23 30 && $user->getIsAdmin() === false) { 24 31 return new Aphront403Response(); 25 32 } 26 33 27 34 if ($request->isFormPost()) { 28 - $timer->delete(); 35 + $countdown->delete(); 29 36 return id(new AphrontRedirectResponse()) 30 37 ->setURI('/countdown/'); 31 38 } 32 39 33 40 $inst = pht('Are you sure you want to delete the countdown %s?', 34 - $timer->getTitle()); 41 + $countdown->getTitle()); 35 42 36 43 $dialog = new AphrontDialogView(); 37 44 $dialog->setUser($request->getUser());
+21 -14
src/applications/countdown/controller/PhabricatorCountdownEditController.php
··· 1 1 <?php 2 2 3 + /** 4 + * @group countdown 5 + */ 3 6 final class PhabricatorCountdownEditController 4 7 extends PhabricatorCountdownController { 5 8 ··· 15 18 $action_label = pht('Create Countdown'); 16 19 17 20 if ($this->id) { 18 - $timer = id(new PhabricatorCountdown())->load($this->id); 19 - // If no timer is found 20 - if (!$timer) { 21 + $countdown = id(new CountdownQuery()) 22 + ->setViewer($user) 23 + ->withIDs(array($this->id)) 24 + ->executeOne(); 25 + 26 + // If no countdown is found 27 + if (!$countdown) { 21 28 return new Aphront404Response(); 22 29 } 23 30 24 - if (($timer->getAuthorPHID() != $user->getPHID()) 31 + if (($countdown->getAuthorPHID() != $user->getPHID()) 25 32 && $user->getIsAdmin() == false) { 26 33 return new Aphront403Response(); 27 34 } 28 35 29 36 $action_label = pht('Update Countdown'); 30 37 } else { 31 - $timer = new PhabricatorCountdown(); 32 - $timer->setEpoch(time()); 38 + $countdown = new PhabricatorCountdown(); 39 + $countdown->setEpoch(time()); 33 40 } 34 41 35 42 $error_view = null; ··· 60 67 $timestamp = null; 61 68 } 62 69 63 - $timer->setTitle($title); 64 - $timer->setEpoch($timestamp); 70 + $countdown->setTitle($title); 71 + $countdown->setEpoch($timestamp); 65 72 66 73 if (!count($errors)) { 67 - $timer->setAuthorPHID($user->getPHID()); 68 - $timer->save(); 74 + $countdown->setAuthorPHID($user->getPHID()); 75 + $countdown->save(); 69 76 return id(new AphrontRedirectResponse()) 70 - ->setURI('/countdown/'.$timer->getID().'/'); 77 + ->setURI('/countdown/'.$countdown->getID().'/'); 71 78 } else { 72 79 $error_view = id(new AphrontErrorView()) 73 80 ->setErrors($errors) ··· 76 83 } 77 84 } 78 85 79 - if ($timer->getEpoch()) { 86 + if ($countdown->getEpoch()) { 80 87 $display_epoch = phabricator_datetime( 81 - $timer->getEpoch(), 88 + $countdown->getEpoch(), 82 89 $user); 83 90 } else { 84 91 $display_epoch = $request->getStr('epoch'); ··· 90 97 ->appendChild( 91 98 id(new AphrontFormTextControl()) 92 99 ->setLabel(pht('Title')) 93 - ->setValue($timer->getTitle()) 100 + ->setValue($countdown->getTitle()) 94 101 ->setName('title')) 95 102 ->appendChild( 96 103 id(new AphrontFormTextControl())
+10 -10
src/applications/countdown/controller/PhabricatorCountdownListController.php
··· 1 1 <?php 2 2 3 + /** 4 + * @group countdown 5 + */ 3 6 final class PhabricatorCountdownListController 4 7 extends PhabricatorCountdownController { 5 8 ··· 8 11 $request = $this->getRequest(); 9 12 $user = $request->getUser(); 10 13 11 - $pager = new AphrontPagerView(); 12 - $pager->setOffset($request->getInt('page')); 13 - $pager->setURI($request->getRequestURI(), 'page'); 14 + $pager = new AphrontCursorPagerView(); 15 + $pager->readFromRequest($request); 14 16 15 - $timers = id(new PhabricatorCountdown())->loadAllWhere( 16 - '1 = 1 ORDER BY id DESC LIMIT %d, %d', 17 - $pager->getOffset(), 18 - $pager->getPageSize() + 1); 17 + $query = id(new CountdownQuery()) 18 + ->setViewer($user); 19 19 20 - $timers = $pager->sliceResults($timers); 20 + $countdowns = $query->executeWithCursorPager($pager); 21 21 22 - $phids = mpull($timers, 'getAuthorPHID'); 22 + $phids = mpull($countdowns, 'getAuthorPHID'); 23 23 $handles = $this->loadViewerHandles($phids); 24 24 25 25 $rows = array(); 26 - foreach ($timers as $timer) { 26 + foreach ($countdowns as $timer) { 27 27 $edit_button = null; 28 28 $delete_button = null; 29 29 if ($user->getIsAdmin() ||
+15 -7
src/applications/countdown/controller/PhabricatorCountdownViewController.php
··· 1 1 <?php 2 2 3 + /** 4 + * @group countdown 5 + */ 3 6 final class PhabricatorCountdownViewController 4 7 extends PhabricatorCountdownController { 5 8 ··· 14 17 15 18 $request = $this->getRequest(); 16 19 $user = $request->getUser(); 17 - $timer = id(new PhabricatorCountdown())->load($this->id); 18 - if (!$timer) { 20 + 21 + $countdown = id(new CountdownQuery()) 22 + ->setViewer($user) 23 + ->withIDs(array($this->id)) 24 + ->executeOne(); 25 + 26 + if (!$countdown) { 19 27 return new Aphront404Response(); 20 28 } 21 29 ··· 49 57 %s 50 58 </div>', 51 59 $container, 52 - $timer->getTitle(), 53 - phabricator_datetime($timer->getEpoch(), $user), 60 + $countdown->getTitle(), 61 + phabricator_datetime($countdown->getEpoch(), $user), 54 62 pht('Days'), 55 63 pht('Hours'), 56 64 pht('Minutes'), ··· 62 70 $chrome_link); 63 71 64 72 Javelin::initBehavior('countdown-timer', array( 65 - 'timestamp' => $timer->getEpoch(), 73 + 'timestamp' => $countdown->getEpoch(), 66 74 'container' => $container, 67 75 )); 68 76 ··· 72 80 ->buildApplicationCrumbs() 73 81 ->addCrumb( 74 82 id(new PhabricatorCrumbView()) 75 - ->setName($timer->getTitle()) 83 + ->setName($countdown->getTitle()) 76 84 ->setHref($this->getApplicationURI($this->id.'/'))); 77 85 78 86 return $this->buildApplicationPage( ··· 81 89 $panel, 82 90 ), 83 91 array( 84 - 'title' => pht('Countdown: %s', $timer->getTitle()), 92 + 'title' => pht('Countdown: %s', $countdown->getTitle()), 85 93 'chrome' => $chrome_visible, 86 94 'device' => true, 87 95 ));
+75
src/applications/countdown/query/CountdownQuery.php
··· 1 + <?php 2 + 3 + /** 4 + * @group countdown 5 + */ 6 + final class CountdownQuery 7 + extends PhabricatorCursorPagedPolicyAwareQuery { 8 + 9 + private $ids; 10 + private $phids; 11 + private $authorPHIDs; 12 + 13 + public function withIDs(array $ids) { 14 + $this->ids = $ids; 15 + return $this; 16 + } 17 + 18 + public function withPHIDs(array $phids) { 19 + $this->phids = $phids; 20 + return $this; 21 + } 22 + 23 + public function withAuthorPHIDs(array $author_phids) { 24 + $this->authorPHIDs = $author_phids; 25 + return $this; 26 + } 27 + 28 + protected function loadPage() { 29 + $table = new PhabricatorCountdown(); 30 + $conn_r = $table->establishConnection('r'); 31 + 32 + $data = queryfx_all( 33 + $conn_r, 34 + 'SELECT * FROM %T %Q %Q %Q', 35 + $table->getTableName(), 36 + $this->buildWhereClause($conn_r), 37 + $this->buildOrderClause($conn_r), 38 + $this->buildLimitClause($conn_r)); 39 + 40 + $countdowns = $table->loadAllFromArray($data); 41 + 42 + 43 + return $countdowns; 44 + } 45 + 46 + private function buildWhereClause(AphrontDatabaseConnection $conn_r) { 47 + $where = array(); 48 + 49 + $where[] = $this->buildPagingClause($conn_r); 50 + 51 + if ($this->ids) { 52 + $where[] = qsprintf( 53 + $conn_r, 54 + 'id IN (%Ld)', 55 + $this->ids); 56 + } 57 + 58 + if ($this->phids) { 59 + $where[] = qsprintf( 60 + $conn_r, 61 + 'phid IN (%Ls)', 62 + $this->phids); 63 + } 64 + 65 + if ($this->authorPHIDs) { 66 + $where[] = qsprintf( 67 + $conn_r, 68 + 'authorPHID in (%Ls)', 69 + $this->authorPHIDs); 70 + } 71 + 72 + return $this->formatWhereClause($where); 73 + } 74 + 75 + }
+29 -65
src/applications/countdown/remarkup/PhabricatorCountdownRemarkupRule.php
··· 1 1 <?php 2 2 3 3 /** 4 - * @group markup 4 + * @group countdown 5 5 */ 6 - final class PhabricatorCountdownRemarkupRule extends PhutilRemarkupRule { 7 - 8 - const KEY_RULE_COUNTDOWN = 'rule.countdown'; 6 + final class PhabricatorCountdownRemarkupRule 7 + extends PhabricatorRemarkupRuleObject { 9 8 10 - public function apply($text) { 11 - return preg_replace_callback( 12 - "@\B{C(\d+)}\B@", 13 - array($this, 'markupCountdown'), 14 - $text); 9 + protected function getObjectNamePrefix() { 10 + return 'C'; 15 11 } 16 12 17 - protected function markupCountdown($matches) { 18 - $countdown = id(new PhabricatorCountdown())->load($matches[1]); 19 - if (!$countdown) { 20 - return $matches[0]; 21 - } 22 - 23 - $engine = $this->getEngine(); 24 - 25 - if ($engine->isTextMode()) { 26 - $date = $countdown->getEpoch(); 27 - $viewer = $engine->getConfig('viewer'); 28 - if ($viewer) { 29 - $date = phabricator_datetime($date, $viewer); 30 - } 31 - return $engine->storeText($date); 32 - } 33 - 34 - $id = celerity_generate_unique_node_id(); 35 - $token = $engine->storeText(''); 36 - 37 - $metadata_key = self::KEY_RULE_COUNTDOWN; 38 - $metadata = $engine->getTextMetadata($metadata_key, array()); 39 - $metadata[$id] = array($countdown->getEpoch(), $token); 40 - $engine->setTextMetadata($metadata_key, $metadata); 41 - 42 - return $token; 13 + protected function loadObjects(array $ids) { 14 + $viewer = $this->getEngine()->getConfig('viewer'); 15 + return id(new CountdownQuery()) 16 + ->setViewer($viewer) 17 + ->withIDs($ids) 18 + ->execute(); 43 19 } 44 20 45 - public function didMarkupText() { 46 - $engine = $this->getEngine(); 47 - 48 - $metadata_key = self::KEY_RULE_COUNTDOWN; 49 - $metadata = $engine->getTextMetadata($metadata_key, array()); 50 - 51 - if (!$metadata) { 52 - return; 53 - } 54 - 21 + protected function renderObjectEmbed($object, $handle, $options) { 55 22 require_celerity_resource('javelin-behavior-countdown-timer'); 56 23 57 - foreach ($metadata as $id => $info) { 58 - list($time, $token) = $info; 59 - $prefix = 'phabricator-timer-'; 60 - $count = phutil_tag( 61 - 'span', 62 - array( 63 - 'id' => $id, 64 - ), 65 - array( 66 - javelin_tag('span', array('sigil' => $prefix.'days'), ''), 'd', 67 - javelin_tag('span', array('sigil' => $prefix.'hours'), ''), 'h', 68 - javelin_tag('span', array('sigil' => $prefix.'minutes'), ''), 'm', 69 - javelin_tag('span', array('sigil' => $prefix.'seconds'), ''), 's', 70 - )); 71 - Javelin::initBehavior('countdown-timer', array( 72 - 'timestamp' => $time, 73 - 'container' => $id, 24 + $prefix = 'phabricator-timer-'; 25 + $counter = phutil_tag( 26 + 'span', 27 + array( 28 + 'id' => $object->getPHID(), 29 + ), 30 + array( 31 + javelin_tag('span', array('sigil' => $prefix.'days'), ''), 'd', 32 + javelin_tag('span', array('sigil' => $prefix.'hours'), ''), 'h', 33 + javelin_tag('span', array('sigil' => $prefix.'minutes'), ''), 'm', 34 + javelin_tag('span', array('sigil' => $prefix.'seconds'), ''), 's', 74 35 )); 75 - $engine->overwriteStoredText($token, $count); 76 - } 36 + 37 + Javelin::initBehavior('countdown-timer', array( 38 + 'timestamp' => $object->getEpoch(), 39 + 'container' => $object->getPHID(), 40 + )); 77 41 78 - $engine->setTextMetadata($metadata_key, array()); 42 + return $counter; 79 43 } 80 44 81 45 }
+29 -1
src/applications/countdown/storage/PhabricatorCountdown.php
··· 1 1 <?php 2 2 3 - final class PhabricatorCountdown extends PhabricatorCountdownDAO { 3 + /** 4 + * @group countdown 5 + */ 6 + final class PhabricatorCountdown extends PhabricatorCountdownDAO 7 + implements PhabricatorPolicyInterface { 4 8 5 9 protected $id; 6 10 protected $phid; 7 11 protected $title; 8 12 protected $authorPHID; 9 13 protected $epoch; 14 + // protected $viewPolicy; //commented out till we have it on countdown table 10 15 11 16 public function getConfiguration() { 12 17 return array( ··· 16 21 17 22 public function generatePHID() { 18 23 return PhabricatorPHID::generateNewPHID('CDWN'); 24 + } 25 + 26 + public function getViewPolicy() { 27 + return "users"; 28 + } 29 + 30 + /* -( PhabricatorPolicyInterface Implementation )------------------------- */ 31 + 32 + public function getCapabilities() { 33 + return array( 34 + PhabricatorPolicyCapability::CAN_VIEW 35 + ); 36 + } 37 + 38 + public function getPolicy($capability) { 39 + switch ($capability) { 40 + case PhabricatorPolicyCapability::CAN_VIEW: 41 + return $this->getViewPolicy(); 42 + } 43 + } 44 + 45 + public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { 46 + return ($viewer->getPHID() == $this->getAuthorPHID()); 19 47 } 20 48 21 49 }
+3
src/applications/countdown/storage/PhabricatorCountdownDAO.php
··· 1 1 <?php 2 2 3 + /** 4 + * @group countdown 5 + */ 3 6 abstract class PhabricatorCountdownDAO extends PhabricatorLiskDAO { 4 7 5 8 public function getApplicationName() {
+1
src/applications/phid/PhabricatorPHIDConstants.php
··· 39 39 const PHID_TYPE_PAYM = 'PAYM'; 40 40 const PHID_TYPE_CHRG = 'CHRG'; 41 41 const PHID_TYPE_CART = 'CART'; 42 + const PHID_TYPE_CDWN = 'CDWN'; 42 43 43 44 const PHID_TYPE_XACT = 'XACT'; 44 45 const PHID_TYPE_XCMT = 'XCMT';
+18
src/applications/phid/handle/PhabricatorObjectHandleData.php
··· 705 705 } 706 706 break; 707 707 708 + case PhabricatorPHIDConstants::PHID_TYPE_CDWN: 709 + foreach ($phids as $phid) { 710 + $handle = new PhabricatorObjectHandle(); 711 + $handle->setPHID($phid); 712 + $handle->setType($type); 713 + if (empty($objects[$phid])) { 714 + $handle->setName('Unknown Countdown'); 715 + } else { 716 + $countdown = $objects[$phid]; 717 + $handle->setName($countdown->getTitle()); 718 + $handle->setFullName($countdown->getTitle()); 719 + $handle->setURI('/countdown/'.$countdown->getID().'/'); 720 + $handle->setComplete(true); 721 + } 722 + $handles[$phid] = $handle; 723 + } 724 + break; 725 + 708 726 default: 709 727 $loader = null; 710 728 if (isset($external_loaders[$type])) {
-1
src/applications/pholio/view/PholioMockEmbedView.php
··· 22 22 23 23 require_celerity_resource('pholio-css'); 24 24 25 - 26 25 $mock_link = phutil_tag( 27 26 'a', 28 27 array(