@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.

Adding some filters and queries to Macro application

Summary:
Fixes T2778

Introduces `PhabricatorMacroQuery`, which should consolidate all queries regarding macros

Adds `PolicyInterface` to `PhabricatorImageMacro`, as else the query would fail (we should consider adding it to the ApplicationTransaction instead, if that was ever planned)

Adds `Active Macros` filter, making it the default

Adds `My Macros` filter. You may ask why it overwrites `$authors`. Well, I did not want the page jump to the conclusion that it is a search result. It //is// one more or less, but the filter would jump to `seach` instead of `my`. If you want `My Macros` removed, tell me. It is useful only to heavy-macro-uploaders-and-users though. Five or six people in `http://secure.phabricator.(org|com)`, and an estimated dozen and a half at bigger installs.

Test Plan: created multiple macros from multiple authors, disabled them at will. browsed around, verified that Macros only appeared in the right filters and that nothing else broke.

Reviewers: epriestley, chad, btrahan

CC: aran, Korvin

Maniphest Tasks: T2778

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

authored by

Anh Nhan Nguyen and committed by
epriestley
ecfb7207 ae1f0e3b

+225 -50
+3
src/__phutil_library_map__.php
··· 1032 1032 'PhabricatorMacroListController' => 'applications/macro/controller/PhabricatorMacroListController.php', 1033 1033 'PhabricatorMacroMemeController' => 'applications/macro/controller/PhabricatorMacroMemeController.php', 1034 1034 'PhabricatorMacroMemeDialogController' => 'applications/macro/controller/PhabricatorMacroMemeDialogController.php', 1035 + 'PhabricatorMacroQuery' => 'applications/macro/query/PhabricatorMacroQuery.php', 1035 1036 'PhabricatorMacroReplyHandler' => 'applications/macro/mail/PhabricatorMacroReplyHandler.php', 1036 1037 'PhabricatorMacroTransaction' => 'applications/macro/storage/PhabricatorMacroTransaction.php', 1037 1038 'PhabricatorMacroTransactionComment' => 'applications/macro/storage/PhabricatorMacroTransactionComment.php', ··· 2588 2589 0 => 'PhabricatorFileDAO', 2589 2590 1 => 'PhabricatorSubscribableInterface', 2590 2591 2 => 'PhabricatorApplicationTransactionInterface', 2592 + 3 => 'PhabricatorPolicyInterface', 2591 2593 ), 2592 2594 'PhabricatorFileInfoController' => 'PhabricatorFileController', 2593 2595 'PhabricatorFileLinkListView' => 'AphrontView', ··· 2658 2660 'PhabricatorMacroListController' => 'PhabricatorMacroController', 2659 2661 'PhabricatorMacroMemeController' => 'PhabricatorMacroController', 2660 2662 'PhabricatorMacroMemeDialogController' => 'PhabricatorMacroController', 2663 + 'PhabricatorMacroQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 2661 2664 'PhabricatorMacroReplyHandler' => 'PhabricatorMailReplyHandler', 2662 2665 'PhabricatorMacroTransaction' => 'PhabricatorApplicationTransaction', 2663 2666 'PhabricatorMacroTransactionComment' => 'PhabricatorApplicationTransactionComment',
+1 -1
src/applications/macro/application/PhabricatorApplicationMacro.php
··· 25 25 public function getRoutes() { 26 26 return array( 27 27 '/macro/' => array( 28 - '' => 'PhabricatorMacroListController', 28 + '((?P<filter>all|active|my)/)?' => 'PhabricatorMacroListController', 29 29 'create/' => 'PhabricatorMacroEditController', 30 30 'view/(?P<id>[1-9]\d*)/' => 'PhabricatorMacroViewController', 31 31 'comment/(?P<id>[1-9]\d*)/' => 'PhabricatorMacroCommentController',
+3 -1
src/applications/macro/controller/PhabricatorMacroController.php
··· 15 15 } 16 16 17 17 $nav->addLabel(pht('Macros')); 18 - $nav->addFilter('/', pht('All Macros')); 18 + $nav->addFilter('active', pht('Active Macros')); 19 + $nav->addFilter('all', pht('All Macros')); 20 + $nav->addFilter('my', pht('My Macros')); 19 21 if ($has_search) { 20 22 $nav->addFilter('search', 21 23 pht('Search'),
+43 -47
src/applications/macro/controller/PhabricatorMacroListController.php
··· 3 3 final class PhabricatorMacroListController 4 4 extends PhabricatorMacroController { 5 5 6 + private $filter; 7 + 8 + public function willProcessRequest(array $data) { 9 + $this->filter = idx($data, 'filter', 'active'); 10 + } 11 + 6 12 public function processRequest() { 7 13 8 14 $request = $this->getRequest(); ··· 12 18 $file_table = new PhabricatorFile(); 13 19 $conn = $macro_table->establishConnection('r'); 14 20 15 - $where = array(); 21 + $pager = id(new AphrontCursorPagerView()) 22 + ->readFromRequest($request); 16 23 17 - $join = array(); 18 - $join[] = qsprintf($conn, '%T m', $macro_table->getTableName()); 24 + $query = new PhabricatorMacroQuery(); 25 + $query->setViewer($viewer); 19 26 20 27 $filter = $request->getStr('name'); 21 28 if (strlen($filter)) { 22 - $where[] = qsprintf($conn, 'm.name LIKE %~', $filter); 29 + $query->withNameLike($filter); 23 30 } 24 31 25 32 $authors = $request->getArr('authors'); 33 + 26 34 if ($authors) { 27 - $join[] = qsprintf( 28 - $conn, 29 - '%T f ON m.filePHID = f.phid', 30 - $file_table->getTableName()); 31 - $where[] = qsprintf($conn, 'f.authorPHID IN (%Ls)', $authors); 35 + $query->withAuthorPHIDs($authors); 36 + } 37 + 38 + $has_search = $filter || $authors; 39 + 40 + if ($this->filter == 'my') { 41 + $query->withAuthorPHIDs(array($viewer->getPHID())); 42 + // For pre-filling the tokenizer 43 + $authors = array($viewer->getPHID()); 32 44 } 33 45 34 - $has_search = $where; 46 + if ($this->filter == 'active') { 47 + $query->withStatus(PhabricatorMacroQuery::STATUS_ACTIVE); 48 + } 35 49 50 + $macros = $query->executeWithCursorPager($pager); 36 51 if ($has_search) { 37 - $macros = queryfx_all( 38 - $conn, 39 - 'SELECT m.* FROM %Q WHERE %Q', 40 - implode(' JOIN ', $join), 41 - implode(' AND ', $where)); 42 - $macros = $macro_table->loadAllFromArray($macros); 43 52 $nodata = pht('There are no macros matching the filter.'); 44 53 } else { 45 - $pager = new AphrontPagerView(); 46 - $pager->setOffset($request->getInt('page')); 47 - 48 - $macros = $macro_table->loadAllWhere( 49 - '1 = 1 ORDER BY id DESC LIMIT %d, %d', 50 - $pager->getOffset(), 51 - $pager->getPageSize()); 52 - 53 - // Get an exact count since the size here is reasonably going to be a few 54 - // thousand at most in any reasonable case. 55 - $count = queryfx_one( 56 - $conn, 57 - 'SELECT COUNT(*) N FROM %T', 58 - $macro_table->getTableName()); 59 - $count = $count['N']; 60 - 61 - $pager->setCount($count); 62 - $pager->setURI($request->getRequestURI(), 'page'); 63 - 64 54 $nodata = pht('There are no image macros yet.'); 65 55 } 66 56 ··· 70 60 $author_phids = array(); 71 61 } 72 62 73 - $file_phids = mpull($macros, 'getFilePHID'); 74 - 75 - $files = array(); 76 - if ($file_phids) { 77 - $files = $file_table->loadAllWhere( 78 - "phid IN (%Ls)", 79 - $file_phids); 63 + $files = mpull($macros, 'getFile'); 64 + if ($files) { 80 65 $author_phids += mpull($files, 'getAuthorPHID', 'getAuthorPHID'); 81 66 } 82 - $files_map = mpull($files, null, 'getPHID'); 83 67 84 68 $this->loadHandles($author_phids); 85 69 $author_handles = array_select_keys($this->getLoadedHandles(), $authors); ··· 108 92 $nav = $this->buildSideNavView( 109 93 $for_app = false, 110 94 $has_search); 111 - $nav->selectFilter($has_search ? 'search' : '/'); 95 + $nav->selectFilter($has_search ? 'search' : $this->filter); 112 96 113 97 $nav->appendChild($filter_view); 114 98 115 99 $pinboard = new PhabricatorPinboardView(); 116 100 $pinboard->setNoDataString($nodata); 117 101 foreach ($macros as $macro) { 118 - $file_phid = $macro->getFilePHID(); 119 - $file = idx($files_map, $file_phid); 102 + $file = $macro->getFile(); 120 103 121 104 $item = new PhabricatorPinboardItemView(); 122 105 if ($file) { ··· 143 126 144 127 if (!$has_search) { 145 128 $nav->appendChild($pager); 146 - $name = pht('All Macros'); 129 + switch ($this->filter) { 130 + case 'all': 131 + $name = pht('All Macros'); 132 + break; 133 + case 'my': 134 + $name = pht('My Macros'); 135 + break; 136 + case 'active': 137 + $name = pht('Active Macros'); 138 + break; 139 + default: 140 + throw new Exception("Unknown filter $this->filter"); 141 + break; 142 + } 147 143 } else { 148 144 $name = pht('Search'); 149 145 }
+143
src/applications/macro/query/PhabricatorMacroQuery.php
··· 1 + <?php 2 + 3 + /** 4 + * @group phriction 5 + */ 6 + final class PhabricatorMacroQuery 7 + extends PhabricatorCursorPagedPolicyAwareQuery { 8 + 9 + private $ids; 10 + private $phids; 11 + private $authors; 12 + private $name; 13 + 14 + private $status = 'status-any'; 15 + const STATUS_ANY = 'status-any'; 16 + const STATUS_ACTIVE = 'status-active'; 17 + 18 + public function withIDs(array $ids) { 19 + $this->ids = $ids; 20 + return $this; 21 + } 22 + 23 + public function withPHIDs(array $phids) { 24 + $this->phids = $phids; 25 + return $this; 26 + } 27 + 28 + public function withAuthorPHIDs(array $authors) { 29 + $this->authors = $authors; 30 + return $this; 31 + } 32 + 33 + public function withNameLike($name) { 34 + $this->name = $name; 35 + return $this; 36 + } 37 + 38 + public function withStatus($status) { 39 + $this->status = $status; 40 + return $this; 41 + } 42 + 43 + protected function loadPage() { 44 + $macro_table = new PhabricatorFileImageMacro(); 45 + $conn = $macro_table->establishConnection('r'); 46 + 47 + $rows = queryfx_all( 48 + $conn, 49 + 'SELECT * FROM %T m %Q %Q %Q %Q', 50 + $macro_table->getTableName(), 51 + $this->buildJoinClause($conn), 52 + $this->buildWhereClause($conn), 53 + $this->buildOrderClause($conn), 54 + $this->buildLimitClause($conn)); 55 + 56 + return $macro_table->loadAllFromArray($rows); 57 + } 58 + 59 + protected function buildJoinClause(AphrontDatabaseConnection $conn) { 60 + $joins = array(); 61 + 62 + if ($this->authors) { 63 + $file_table = new PhabricatorFile(); 64 + $joins[] = qsprintf( 65 + $conn, 66 + 'JOIN %T f ON m.filePHID = f.phid', 67 + $file_table->getTableName()); 68 + } 69 + 70 + return implode(' ', $joins); 71 + } 72 + 73 + protected function buildWhereClause(AphrontDatabaseConnection $conn) { 74 + $where = array(); 75 + 76 + if ($this->ids) { 77 + $where[] = qsprintf( 78 + $conn, 79 + 'm.id IN (%Ld)', 80 + $this->ids); 81 + } 82 + 83 + if ($this->phids) { 84 + $where[] = qsprintf( 85 + $conn, 86 + 'm.phid IN (%Ld)', 87 + $this->phids); 88 + } 89 + 90 + if ($this->authors) { 91 + $where[] = qsprintf( 92 + $conn, 93 + 'f.authorPHID IN (%Ls)', 94 + $this->authors); 95 + } 96 + 97 + if ($this->name) { 98 + $where[] = qsprintf( 99 + $conn, 100 + 'm.name LIKE %~', 101 + $this->name); 102 + } 103 + 104 + if ($this->status == self::STATUS_ACTIVE) { 105 + $where[] = qsprintf( 106 + $conn, 107 + 'm.isDisabled = 0'); 108 + } 109 + 110 + $where[] = $this->buildPagingClause($conn); 111 + 112 + return $this->formatWhereClause($where); 113 + } 114 + 115 + protected function willFilterPage(array $macros) { 116 + if (!$macros) { 117 + return array(); 118 + } 119 + 120 + $file_phids = mpull($macros, 'getFilePHID'); 121 + $files = id(new PhabricatorFileQuery()) 122 + ->setViewer($this->getViewer()) 123 + ->withPHIDs($file_phids) 124 + ->execute(); 125 + $files = mpull($files, null, 'getPHID'); 126 + 127 + foreach ($macros as $key => $macro) { 128 + $file = idx($files, $macro->getFilePHID()); 129 + if (!$file) { 130 + unset($macros[$key]); 131 + continue; 132 + } 133 + $macro->attachFile($file); 134 + } 135 + 136 + return $macros; 137 + } 138 + 139 + protected function getPagingColumn() { 140 + return 'm.id'; 141 + } 142 + 143 + }
+32 -1
src/applications/macro/storage/PhabricatorFileImageMacro.php
··· 3 3 final class PhabricatorFileImageMacro extends PhabricatorFileDAO 4 4 implements 5 5 PhabricatorSubscribableInterface, 6 - PhabricatorApplicationTransactionInterface { 6 + PhabricatorApplicationTransactionInterface, 7 + PhabricatorPolicyInterface { 7 8 8 9 protected $filePHID; 9 10 protected $phid; 10 11 protected $name; 11 12 protected $isDisabled = 0; 12 13 14 + private $file; 15 + 16 + public function attachFile(PhabricatorFile $file) { 17 + $this->file = $file; 18 + return $this; 19 + } 20 + 21 + public function getFile() { 22 + if (!$this->file) { 23 + throw new Exception("Attach a file with attachFile() first!"); 24 + } 25 + 26 + return $this->file; 27 + } 28 + 13 29 public function getConfiguration() { 14 30 return array( 15 31 self::CONFIG_AUX_PHID => true, ··· 31 47 32 48 public function getApplicationTransactionObject() { 33 49 return new PhabricatorMacroTransaction(); 50 + } 51 + 52 + public function getCapabilities() { 53 + return array( 54 + PhabricatorPolicyCapability::CAN_VIEW, 55 + PhabricatorPolicyCapability::CAN_EDIT, 56 + ); 57 + } 58 + 59 + public function getPolicy($capability) { 60 + return PhabricatorPolicies::POLICY_USER; 61 + } 62 + 63 + public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { 64 + return false; 34 65 } 35 66 36 67 }