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

Audit - move over to application search

Summary: ...also kills off "PhabricatorAuditCommitQuery" and "PhabricatorAuditQuery", by moving the work to "DiffusionCommitQuery". Generally cleans up some code around the joint on this too. Also provides policies for audit requests, which is basically the policy for the underlying commit. Fixes T4715. (For the TODO I added about files, I just grabbed T4713.)

Test Plan:
Audit: verified the three default views all showed the correct things, including highligthing. did some custom queries and got the correct results.
Diffusion: verified "blame view" still worked. verified paths were highlighted for packages i owned.
Home: verified audit boxes showed up with proper commits w/ audits
bin/audit: played around with it via --dry-run and got the right audits back

Reviewers: epriestley

Reviewed By: epriestley

Subscribers: chad, epriestley, Korvin

Maniphest Tasks: T4715

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

+660 -1329
+12 -6
src/__phutil_library_map__.php
··· 1189 1189 'PhabricatorAuditAddCommentController' => 'applications/audit/controller/PhabricatorAuditAddCommentController.php', 1190 1190 'PhabricatorAuditComment' => 'applications/audit/storage/PhabricatorAuditComment.php', 1191 1191 'PhabricatorAuditCommentEditor' => 'applications/audit/editor/PhabricatorAuditCommentEditor.php', 1192 - 'PhabricatorAuditCommitListView' => 'applications/audit/view/PhabricatorAuditCommitListView.php', 1193 - 'PhabricatorAuditCommitQuery' => 'applications/audit/query/PhabricatorAuditCommitQuery.php', 1194 1192 'PhabricatorAuditCommitStatusConstants' => 'applications/audit/constants/PhabricatorAuditCommitStatusConstants.php', 1195 1193 'PhabricatorAuditController' => 'applications/audit/controller/PhabricatorAuditController.php', 1196 1194 'PhabricatorAuditDAO' => 'applications/audit/storage/PhabricatorAuditDAO.php', ··· 1201 1199 'PhabricatorAuditManagementDeleteWorkflow' => 'applications/audit/management/PhabricatorAuditManagementDeleteWorkflow.php', 1202 1200 'PhabricatorAuditManagementWorkflow' => 'applications/audit/management/PhabricatorAuditManagementWorkflow.php', 1203 1201 'PhabricatorAuditPreviewController' => 'applications/audit/controller/PhabricatorAuditPreviewController.php', 1204 - 'PhabricatorAuditQuery' => 'applications/audit/query/PhabricatorAuditQuery.php', 1205 1202 'PhabricatorAuditReplyHandler' => 'applications/audit/mail/PhabricatorAuditReplyHandler.php', 1206 1203 'PhabricatorAuditStatusConstants' => 'applications/audit/constants/PhabricatorAuditStatusConstants.php', 1207 1204 'PhabricatorAuthAccountView' => 'applications/auth/view/PhabricatorAuthAccountView.php', ··· 1312 1309 'PhabricatorChatLogQuery' => 'applications/chatlog/query/PhabricatorChatLogQuery.php', 1313 1310 'PhabricatorCommitBranchesField' => 'applications/repository/customfield/PhabricatorCommitBranchesField.php', 1314 1311 'PhabricatorCommitCustomField' => 'applications/repository/customfield/PhabricatorCommitCustomField.php', 1312 + 'PhabricatorCommitSearchEngine' => 'applications/audit/query/PhabricatorCommitSearchEngine.php', 1315 1313 'PhabricatorCommitTagsField' => 'applications/repository/customfield/PhabricatorCommitTagsField.php', 1316 1314 'PhabricatorCommonPasswords' => 'applications/auth/constants/PhabricatorCommonPasswords.php', 1317 1315 'PhabricatorConduitAPIController' => 'applications/conduit/controller/PhabricatorConduitAPIController.php', ··· 3926 3924 1 => 'PhabricatorMarkupInterface', 3927 3925 ), 3928 3926 'PhabricatorAuditCommentEditor' => 'PhabricatorEditor', 3929 - 'PhabricatorAuditCommitListView' => 'AphrontView', 3930 3927 'PhabricatorAuditController' => 'PhabricatorController', 3931 3928 'PhabricatorAuditDAO' => 'PhabricatorLiskDAO', 3932 3929 'PhabricatorAuditInlineComment' => ··· 3934 3931 0 => 'PhabricatorAuditDAO', 3935 3932 1 => 'PhabricatorInlineCommentInterface', 3936 3933 ), 3937 - 'PhabricatorAuditListController' => 'PhabricatorAuditController', 3934 + 'PhabricatorAuditListController' => 3935 + array( 3936 + 0 => 'PhabricatorAuditController', 3937 + 1 => 'PhabricatorApplicationSearchResultsControllerInterface', 3938 + ), 3938 3939 'PhabricatorAuditListView' => 'AphrontView', 3939 3940 'PhabricatorAuditMailReceiver' => 'PhabricatorObjectMailReceiver', 3940 3941 'PhabricatorAuditManagementDeleteWorkflow' => 'PhabricatorAuditManagementWorkflow', ··· 4066 4067 'PhabricatorChatLogQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 4067 4068 'PhabricatorCommitBranchesField' => 'PhabricatorCommitCustomField', 4068 4069 'PhabricatorCommitCustomField' => 'PhabricatorCustomField', 4070 + 'PhabricatorCommitSearchEngine' => 'PhabricatorApplicationSearchEngine', 4069 4071 'PhabricatorCommitTagsField' => 'PhabricatorCommitCustomField', 4070 4072 'PhabricatorCommonPasswords' => 'Phobject', 4071 4073 'PhabricatorConduitAPIController' => 'PhabricatorConduitController', ··· 4795 4797 'PhabricatorRepositoryArcanistProjectDeleteController' => 'PhabricatorRepositoryController', 4796 4798 'PhabricatorRepositoryArcanistProjectEditController' => 'PhabricatorRepositoryController', 4797 4799 'PhabricatorRepositoryArcanistProjectQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 4798 - 'PhabricatorRepositoryAuditRequest' => 'PhabricatorRepositoryDAO', 4800 + 'PhabricatorRepositoryAuditRequest' => 4801 + array( 4802 + 0 => 'PhabricatorRepositoryDAO', 4803 + 1 => 'PhabricatorPolicyInterface', 4804 + ), 4799 4805 'PhabricatorRepositoryBranch' => 'PhabricatorRepositoryDAO', 4800 4806 'PhabricatorRepositoryCommit' => 4801 4807 array(
+12 -12
src/applications/audit/application/PhabricatorApplicationAudit.php
··· 27 27 public function getRoutes() { 28 28 return array( 29 29 '/audit/' => array( 30 - '' => 'PhabricatorAuditListController', 31 - 'view/(?P<filter>[^/]+)/(?:(?P<name>[^/]+)/)?' 32 - => 'PhabricatorAuditListController', 30 + '(?:query/(?P<queryKey>[^/]+)/)?' => 'PhabricatorAuditListController', 33 31 'addcomment/' => 'PhabricatorAuditAddCommentController', 34 32 'preview/(?P<id>[1-9]\d*)/' => 'PhabricatorAuditPreviewController', 35 33 ), ··· 49 47 50 48 $phids = PhabricatorAuditCommentEditor::loadAuditPHIDsForUser($user); 51 49 52 - $commits = id(new PhabricatorAuditCommitQuery()) 53 - ->withAuthorPHIDs($phids) 54 - ->withStatus(PhabricatorAuditCommitQuery::STATUS_CONCERN) 55 - ->execute(); 50 + $query = id(new DiffusionCommitQuery()) 51 + ->setViewer($user) 52 + ->withAuthorPHIDs(array($user->getPHID())) 53 + ->withAuditStatus(DiffusionCommitQuery::AUDIT_STATUS_CONCERN); 54 + $commits = $query->execute(); 56 55 57 56 $count = count($commits); 58 57 $type = PhabricatorApplicationStatusView::TYPE_NEEDS_ATTENTION; ··· 61 60 ->setText(pht('%d Problem Commit(s)', $count)) 62 61 ->setCount($count); 63 62 64 - $audits = id(new PhabricatorAuditQuery()) 63 + $query = id(new DiffusionCommitQuery()) 64 + ->setViewer($user) 65 65 ->withAuditorPHIDs($phids) 66 - ->withStatus(PhabricatorAuditQuery::STATUS_OPEN) 67 - ->withAwaitingUser($user) 68 - ->execute(); 66 + ->withAuditStatus(DiffusionCommitQuery::AUDIT_STATUS_OPEN) 67 + ->withAuditAwaitingUser($user); 68 + $commits = $query->execute(); 69 69 70 - $count = count($audits); 70 + $count = count($commits); 71 71 $type = PhabricatorApplicationStatusView::TYPE_WARNING; 72 72 $status[] = id(new PhabricatorApplicationStatusView()) 73 73 ->setType($type)
+19 -13
src/applications/audit/conduit/ConduitAPI_audit_query_Method.php
··· 31 31 32 32 protected function execute(ConduitAPIRequest $request) { 33 33 34 - $query = new PhabricatorAuditQuery(); 34 + $query = id(new DiffusionCommitQuery()) 35 + ->setViewer($request->getUser()); 35 36 36 37 $auditor_phids = $request->getValue('auditorPHIDs', array()); 37 38 if ($auditor_phids) { ··· 40 41 41 42 $commit_phids = $request->getValue('commitPHIDs', array()); 42 43 if ($commit_phids) { 43 - $query->withCommitPHIDs($commit_phids); 44 + $query->withPHIDs($commit_phids); 44 45 } 45 46 46 - $status = $request->getValue('status', PhabricatorAuditQuery::STATUS_ANY); 47 - $query->withStatus($status); 47 + $status = $request->getValue( 48 + 'status', 49 + DiffusionCommitQuery::AUDIT_STATUS_ANY); 50 + $query->withAuditStatus($status); 48 51 49 52 $query->setOffset($request->getValue('offset', 0)); 50 53 $query->setLimit($request->getValue('limit', 100)); 51 54 52 - $requests = $query->execute(); 55 + $commits = $query->execute(); 53 56 54 57 $results = array(); 55 - foreach ($requests as $request) { 56 - $results[] = array( 57 - 'id' => $request->getID(), 58 - 'commitPHID' => $request->getCommitPHID(), 59 - 'auditorPHID' => $request->getAuditorPHID(), 60 - 'reasons' => $request->getAuditReasons(), 61 - 'status' => $request->getAuditStatus(), 62 - ); 58 + foreach ($commits as $commit) { 59 + $requests = $commit->getAudits(); 60 + foreach ($requests as $request) { 61 + $results[] = array( 62 + 'id' => $request->getID(), 63 + 'commitPHID' => $request->getCommitPHID(), 64 + 'auditorPHID' => $request->getAuditorPHID(), 65 + 'reasons' => $request->getAuditReasons(), 66 + 'status' => $request->getAuditStatus(), 67 + ); 68 + } 63 69 } 64 70 65 71 return $results;
+7 -31
src/applications/audit/controller/PhabricatorAuditController.php
··· 2 2 3 3 abstract class PhabricatorAuditController extends PhabricatorController { 4 4 5 - public $filter; 5 + public function buildSideNavView() { 6 6 7 - public function buildSideNavView() { 7 + $user = $this->getRequest()->getUser(); 8 8 9 9 $nav = new AphrontSideNavFilterView(); 10 - $nav->setBaseURI(new PhutilURI('/audit/view/')); 11 - $nav->addLabel(pht('Active')); 12 - $nav->addFilter('active', pht('Need Attention')); 10 + $nav->setBaseURI(new PhutilURI($this->getApplicationURI())); 13 11 14 - $nav->addLabel(pht('Audits')); 15 - $nav->addFilter('audits', pht('All')); 16 - $nav->addFilter('user', pht('By User')); 17 - $nav->addFilter('project', pht('By Project')); 18 - $nav->addFilter('package', pht('By Package')); 19 - $nav->addFilter('repository', pht('By Repository')); 20 - 21 - $nav->addLabel(pht('Commits')); 22 - $nav->addFilter('commits', pht('All')); 23 - $nav->addFilter('author', pht('By Author')); 24 - $nav->addFilter('packagecommits', pht('By Package')); 12 + id(new PhabricatorCommitSearchEngine()) 13 + ->setViewer($user) 14 + ->addNavigationItems($nav->getMenu()); 25 15 26 - $this->filter = $nav->selectFilter($this->filter, 'active'); 16 + $nav->selectFilter(null); 27 17 28 18 return $nav; 29 19 } ··· 32 22 return $this->buildSideNavView()->getMenu(); 33 23 } 34 24 35 - public function buildStandardPageResponse($view, array $data) { 36 - 37 - $page = $this->buildStandardPageView(); 38 - 39 - $page->setApplicationName(pht('Audit')); 40 - $page->setBaseURI('/audit/'); 41 - $page->setTitle(idx($data, 'title')); 42 - $page->setGlyph("\xE2\x9C\x8D"); 43 - $page->appendChild($view); 44 - 45 - $response = new AphrontWebpageResponse(); 46 - return $response->setContent($page->render()); 47 - 48 - } 49 25 }
+27 -462
src/applications/audit/controller/PhabricatorAuditListController.php
··· 1 1 <?php 2 2 3 - final class PhabricatorAuditListController extends PhabricatorAuditController { 3 + final class PhabricatorAuditListController 4 + extends PhabricatorAuditController 5 + implements PhabricatorApplicationSearchResultsControllerInterface { 4 6 7 + private $queryKey; 5 8 private $name; 6 9 private $filterStatus; 7 10 11 + public function shouldAllowPublic() { 12 + return true; 13 + } 14 + 8 15 public function willProcessRequest(array $data) { 9 - $this->filter = idx($data, 'filter'); 10 - $this->name = idx($data, 'name'); 16 + $this->queryKey = idx($data, 'queryKey'); 11 17 } 12 18 13 19 public function processRequest() { 14 20 $request = $this->getRequest(); 15 - $nav = $this->buildSideNavView(); 16 - 17 - if ($request->isFormPost()) { 18 - // If the list filter is POST'ed, redirect to GET so the page can be 19 - // bookmarked. 20 - $uri = $request->getRequestURI(); 21 - $phid = head($request->getArr('set_phid')); 22 - $user = id(new PhabricatorUser())->loadOneWhere( 23 - 'phid = %s', 24 - $phid); 25 - 26 - $uri = $request->getRequestURI(); 27 - if ($user) { 28 - $username = phutil_escape_uri($user->getUsername()); 29 - $uri = '/audit/view/'.$this->filter.'/'.$username.'/'; 30 - } else if ($phid) { 31 - $uri = $request->getRequestURI(); 32 - $uri = $uri->alter('phid', $phid); 33 - } 34 - 35 - return id(new AphrontRedirectResponse())->setURI($uri); 36 - } 37 - 38 - $this->filterStatus = $request->getStr('status', 'all'); 39 - 40 - $handle = $this->loadHandle(); 41 - 42 - $nav->appendChild($this->buildListFilters($handle)); 43 - 21 + $controller = id(new PhabricatorApplicationSearchController($request)) 22 + ->setQueryKey($this->queryKey) 23 + ->setSearchEngine(new PhabricatorCommitSearchEngine()) 24 + ->setNavigation($this->buildSideNavView()); 44 25 45 - $title = null; 46 - $message = null; 47 - 48 - if (!$handle) { 49 - switch ($this->filter) { 50 - case 'project': 51 - $title = pht('Choose A Project'); 52 - $message = pht('Choose a project to view audits for.'); 53 - break; 54 - case 'repository': 55 - $title = pht('Choose A Repository'); 56 - $message = pht('Choose a repository to view audits for.'); 57 - break; 58 - case 'package': 59 - case 'packagecommits': 60 - $title = pht('Choose a Package'); 61 - $message = pht('Choose a package to view audits for.'); 62 - break; 63 - } 64 - } 65 - 66 - if (!$message) { 67 - $nav->appendChild($this->buildViews($handle)); 68 - } else { 69 - $panel = id(new AphrontErrorView()) 70 - ->setSeverity(AphrontErrorView::SEVERITY_NODATA) 71 - ->setTitle($title) 72 - ->appendChild($message); 73 - $nav->appendChild($panel); 74 - } 75 - 76 - return $this->buildApplicationPage( 77 - $nav, 78 - array( 79 - 'title' => pht('Audits'), 80 - 'device' => true, 81 - )); 26 + return $this->delegateToController($controller); 82 27 } 83 28 84 - private function buildListFilters(PhabricatorObjectHandle $handle = null) { 85 - $request = $this->getRequest(); 86 - $user = $request->getUser(); 29 + public function renderResultsList( 30 + array $commits, 31 + PhabricatorSavedQuery $query) { 32 + assert_instances_of($commits, 'PhabricatorRepositoryCommit'); 87 33 88 - $form = new AphrontFormView(); 89 - $form->setUser($user); 90 - 91 - $show_status = false; 92 - $show_user = false; 93 - $show_project = false; 94 - $show_package = false; 95 - $show_repository = false; 96 - 97 - switch ($this->filter) { 98 - case 'audits': 99 - case 'commits': 100 - $show_status = true; 101 - break; 102 - case 'active': 103 - $show_user = true; 104 - break; 105 - case 'author': 106 - case 'user': 107 - $show_user = true; 108 - $show_status = true; 109 - break; 110 - case 'project': 111 - $show_project = true; 112 - $show_status = true; 113 - break; 114 - case 'repository': 115 - $show_repository = true; 116 - $show_status = true; 117 - break; 118 - case 'package': 119 - case 'packagecommits': 120 - $show_package = true; 121 - $show_status = true; 122 - break; 123 - } 124 - 125 - if ($show_user || $show_project || $show_package || $show_repository) { 126 - if ($show_user) { 127 - $uri = '/typeahead/common/users/'; 128 - $label = pht('User'); 129 - } else if ($show_project) { 130 - $uri = '/typeahead/common/projects/'; 131 - $label = pht('Project'); 132 - } else if ($show_package) { 133 - $uri = '/typeahead/common/packages/'; 134 - $label = pht('Package'); 135 - } else if ($show_repository) { 136 - $uri = '/typeahead/common/repositories/'; 137 - $label = pht('Repository'); 138 - } 139 - 140 - $tok_value = null; 141 - if ($handle) { 142 - $tok_value = array($handle); 143 - } 144 - 145 - $form->appendChild( 146 - id(new AphrontFormTokenizerControl()) 147 - ->setName('set_phid') 148 - ->setLabel($label) 149 - ->setLimit(1) 150 - ->setDatasource($uri) 151 - ->setValue($tok_value)); 152 - } 153 - 154 - if ($show_status) { 155 - $form->appendChild( 156 - id(new AphrontFormToggleButtonsControl()) 157 - ->setName('status') 158 - ->setLabel(pht('Status')) 159 - ->setBaseURI($request->getRequestURI(), 'status') 160 - ->setValue($this->filterStatus) 161 - ->setButtons( 162 - array( 163 - 'all' => pht('All'), 164 - 'open' => pht('Open'), 165 - 'concern' => pht('Concern Raised'), 166 - ))); 167 - } 168 - 169 - $form->appendChild( 170 - id(new AphrontFormSubmitControl()) 171 - ->setValue(pht('Filter Audits'))); 172 - 173 - $view = new AphrontListFilterView(); 174 - $view->appendChild($form); 175 - return $view; 176 - } 177 - 178 - private function loadHandle() { 179 - $request = $this->getRequest(); 180 - 181 - $default = null; 182 - switch ($this->filter) { 183 - case 'user': 184 - case 'active': 185 - case 'author': 186 - $default = $request->getUser()->getPHID(); 187 - if ($this->name) { 188 - $user = id(new PhabricatorUser())->loadOneWhere( 189 - 'username = %s', 190 - $this->name); 191 - if ($user) { 192 - $default = $user->getPHID(); 193 - } 194 - } 195 - break; 196 - } 197 - 198 - $phid = $request->getStr('phid', $default); 199 - if (!$phid) { 200 - return null; 201 - } 202 - 203 - $phids = array($phid); 204 - $handles = $this->loadViewerHandles($phids); 205 - $handle = $handles[$phid]; 206 - 207 - $this->validateHandle($handle); 208 - return $handle; 209 - } 210 - 211 - private function validateHandle(PhabricatorObjectHandle $handle) { 212 - $type = $handle->getType(); 213 - 214 - switch ($this->filter) { 215 - case 'active': 216 - case 'user': 217 - case 'author': 218 - if ($type !== PhabricatorPeoplePHIDTypeUser::TYPECONST) { 219 - throw new Exception("PHID must be a user PHID!"); 220 - } 221 - break; 222 - case 'package': 223 - case 'packagecommits': 224 - if ($type !== PhabricatorOwnersPHIDTypePackage::TYPECONST) { 225 - throw new Exception("PHID must be a package PHID!"); 226 - } 227 - break; 228 - case 'project': 229 - if ($type !== PhabricatorProjectPHIDTypeProject::TYPECONST) { 230 - throw new Exception("PHID must be a project PHID!"); 231 - } 232 - break; 233 - case 'repository': 234 - if ($type !== PhabricatorRepositoryPHIDTypeRepository::TYPECONST) { 235 - throw new Exception("PHID must be a repository PHID!"); 236 - } 237 - break; 238 - case 'audits': 239 - case 'commits': 240 - break; 241 - default: 242 - throw new Exception("Unknown filter '{$this->filter}'!"); 243 - } 244 - } 245 - 246 - private function buildViews(PhabricatorObjectHandle $handle = null) { 247 - $views = array(); 248 - switch ($this->filter) { 249 - case 'active': 250 - $views[] = $this->buildCommitView($handle); 251 - $views[] = $this->buildAuditView($handle); 252 - break; 253 - case 'audits': 254 - case 'user': 255 - case 'package': 256 - case 'project': 257 - case 'repository': 258 - $views[] = $this->buildAuditView($handle); 259 - break; 260 - case 'commits': 261 - case 'packagecommits': 262 - case 'author': 263 - $views[] = $this->buildCommitView($handle); 264 - break; 265 - } 266 - return $views; 267 - } 268 - 269 - private function buildAuditView(PhabricatorObjectHandle $handle = null) { 270 - $request = $this->getRequest(); 271 - 272 - $query = new PhabricatorAuditQuery(); 273 - 274 - $pager = new AphrontPagerView(); 275 - $pager->setURI($request->getRequestURI(), 'offset'); 276 - $pager->setOffset($request->getInt('offset')); 277 - 278 - $query->setOffset($pager->getOffset()); 279 - $query->setLimit($pager->getPageSize() + 1); 280 - 281 - $awaiting = null; 282 - 283 - $phids = null; 284 - $repository_phids = null; 285 - switch ($this->filter) { 286 - case 'user': 287 - case 'active': 288 - $obj = id(new PhabricatorUser())->loadOneWhere( 289 - 'phid = %s', 290 - $handle->getPHID()); 291 - if (!$obj) { 292 - throw new Exception("Invalid user!"); 293 - } 294 - $phids = PhabricatorAuditCommentEditor::loadAuditPHIDsForUser($obj); 295 - $awaiting = $obj; 296 - break; 297 - case 'project': 298 - case 'package': 299 - $phids = array($handle->getPHID()); 300 - break; 301 - case 'repository': 302 - $repository_phids = array($handle->getPHID()); 303 - break; 304 - case 'audits'; 305 - break; 306 - default: 307 - throw new Exception("Unknown filter!"); 308 - } 309 - 310 - if ($phids) { 311 - $query->withAuditorPHIDs($phids); 312 - } 313 - 314 - if ($repository_phids) { 315 - $query->withRepositoryPHIDs($repository_phids); 316 - } 317 - 318 - if ($awaiting) { 319 - $query->withAwaitingUser($awaiting); 320 - } 321 - 322 - switch ($this->filter) { 323 - case 'active': 324 - $query->withStatus(PhabricatorAuditQuery::STATUS_OPEN); 325 - break; 326 - default: 327 - switch ($this->filterStatus) { 328 - case 'open': 329 - $query->withStatus(PhabricatorAuditQuery::STATUS_OPEN); 330 - break; 331 - case 'concern': 332 - $query->withStatus(PhabricatorAuditQuery::STATUS_CONCERN); 333 - break; 334 - } 335 - break; 336 - } 337 - 338 - if ($handle) { 339 - $handle_name = $handle->getFullName(); 340 - } else { 341 - $handle_name = null; 342 - } 343 - 344 - switch ($this->filter) { 345 - case 'active': 346 - $header = pht('Required Audits'); 347 - $nodata = pht('No commits require your audit.'); 348 - break; 349 - case 'user': 350 - $header = pht("Audits for %s", $handle_name); 351 - $nodata = pht("No matching audits by %s.", $handle_name); 352 - break; 353 - case 'audits': 354 - $header = pht('Audits'); 355 - $nodata = pht('No matching audits.'); 356 - break; 357 - case 'project': 358 - $header = pht("Audits in Project %s", $handle_name); 359 - $nodata = pht("No matching audits in project %s.", $handle_name); 360 - break; 361 - case 'package': 362 - $header = pht("Audits for Package %s", $handle_name); 363 - $nodata = pht("No matching audits in package %s.", $handle_name); 364 - break; 365 - case 'repository': 366 - $header = pht("Audits in Repository %s", $handle_name); 367 - $nodata = pht("No matching audits in repository %s.", $handle_name); 368 - break; 369 - } 370 - 371 - $query->needCommitData(true); 372 - 373 - $audits = $query->execute(); 374 - $audits = $pager->sliceResults($audits); 375 - 376 - $view = new PhabricatorAuditListView(); 377 - $view->setAudits($audits); 378 - $view->setCommits($query->getCommits()); 379 - $view->setUser($request->getUser()); 380 - $view->setNoDataString($nodata); 34 + $viewer = $this->getRequest()->getUser(); 35 + $nodata = pht('No matching audits.'); 36 + $view = id(new PhabricatorAuditListView()) 37 + ->setUser($viewer) 38 + ->setCommits($commits) 39 + ->setAuthorityPHIDs( 40 + PhabricatorAuditCommentEditor::loadAuditPHIDsForUser($viewer)) 41 + ->setNoDataString($nodata); 381 42 382 43 $phids = $view->getRequiredHandlePHIDs(); 383 44 $handles = $this->loadViewerHandles($phids); 384 45 $view->setHandles($handles); 385 - 386 - $panel = new AphrontPanelView(); 387 - $panel->setHeader($header); 388 - $panel->appendChild($view); 389 - $panel->setNoBackground(); 390 - 391 - $panel->appendChild($pager); 392 - 393 - return $panel; 394 - } 395 - 396 - private function buildCommitView(PhabricatorObjectHandle $handle = null) { 397 - $request = $this->getRequest(); 398 - 399 - $query = new PhabricatorAuditCommitQuery(); 400 - $query->needCommitData(true); 401 - $query->needAudits(true); 402 - 403 - $pager = new AphrontPagerView(); 404 - $pager->setURI($request->getRequestURI(), 'offset'); 405 - $pager->setOffset($request->getInt('offset')); 406 - 407 - $query->setOffset($pager->getOffset()); 408 - $query->setLimit($pager->getPageSize() + 1); 409 - 410 - switch ($this->filter) { 411 - case 'active': 412 - case 'author': 413 - $query->withAuthorPHIDs(array($handle->getPHID())); 414 - break; 415 - case 'packagecommits': 416 - $query->withPackagePHIDs(array($handle->getPHID())); 417 - break; 418 - } 419 - 420 - switch ($this->filter) { 421 - case 'active': 422 - $query->withStatus(PhabricatorAuditCommitQuery::STATUS_CONCERN); 423 - break; 424 - default: 425 - switch ($this->filterStatus) { 426 - case 'open': 427 - $query->withStatus(PhabricatorAuditCommitQuery::STATUS_OPEN); 428 - break; 429 - case 'concern': 430 - $query->withStatus(PhabricatorAuditCommitQuery::STATUS_CONCERN); 431 - break; 432 - } 433 - break; 434 - } 435 - 436 - if ($handle) { 437 - $handle_name = $handle->getName(); 438 - } else { 439 - $handle_name = null; 440 - } 441 - 442 - switch ($this->filter) { 443 - case 'active': 444 - $header = pht('Problem Commits'); 445 - $nodata = pht('None of your commits have open concerns.'); 446 - break; 447 - case 'author': 448 - $header = pht("Commits by %s", $handle_name); 449 - $nodata = pht("No matching commits by %s.", $handle_name); 450 - break; 451 - case 'commits': 452 - $header = pht("Commits"); 453 - $nodata = pht("No matching commits."); 454 - break; 455 - case 'packagecommits': 456 - $header = pht("Commits in Package %s", $handle_name); 457 - $nodata = pht("No matching commits in package %s.", $handle_name); 458 - break; 459 - } 460 - 461 - $commits = $query->execute(); 462 - $commits = $pager->sliceResults($commits); 463 - 464 - $view = new PhabricatorAuditCommitListView(); 465 - $view->setUser($request->getUser()); 466 - $view->setCommits($commits); 467 - $view->setNoDataString($nodata); 468 - 469 - $phids = $view->getRequiredHandlePHIDs(); 470 - $handles = $this->loadViewerHandles($phids); 471 - $view->setHandles($handles); 472 - 473 - $panel = new AphrontPanelView(); 474 - $panel->setHeader($header); 475 - $panel->appendChild($view); 476 - $panel->setNoBackground(); 477 - 478 - $panel->appendChild($pager); 479 - 480 - return $panel; 46 + return $view->buildList(); 481 47 } 482 - 483 48 }
+25 -36
src/applications/audit/management/PhabricatorAuditManagementDeleteWorkflow.php
··· 65 65 66 66 $status = $args->getArg('status'); 67 67 if (!$status) { 68 - $status = PhabricatorAuditQuery::STATUS_OPEN; 68 + $status = DiffusionCommitQuery::AUDIT_STATUS_OPEN; 69 69 } 70 70 71 71 $min_date = $this->loadDate($args->getArg('min-commit-date')); ··· 77 77 78 78 $is_dry_run = $args->getArg('dry-run'); 79 79 80 - $query = id(new PhabricatorAuditQuery()) 81 - ->needCommits(true); 80 + $query = id(new DiffusionCommitQuery()) 81 + ->setViewer($this->getViewer()) 82 + ->needAuditRequests(true); 82 83 83 84 if ($status) { 84 - $query->withStatus($status); 85 + $query->withAuditStatus($status); 85 86 } 86 87 87 88 if ($ids) { 88 - $query->withIDs($ids); 89 + $query->withAuditIDs($ids); 89 90 } 90 91 91 92 if ($repos) { 92 - $query->withRepositoryPHIDs(mpull($repos, 'getPHID')); 93 + $query->withRepositoryIDs(mpull($repos, 'getID')); 93 94 } 94 95 95 96 if ($users) { ··· 97 98 } 98 99 99 100 if ($commits) { 100 - $query->withCommitPHIDs(mpull($commits, 'getPHID')); 101 + $query->withPHIDs(mpull($commits, 'getPHID')); 101 102 } 102 103 103 - $audits = $query->execute(); 104 - $commits = $query->getCommits(); 104 + $commits = $query->execute(); 105 + $commits = mpull($commits, null, 'getPHID'); 106 + $audits = array(); 107 + foreach ($commits as $commit) { 108 + $curr_audits = $commit->getAudits(); 109 + foreach ($audits as $key => $audit) { 110 + if ($min_date && $commit->getEpoch() < $min_date) { 111 + unset($audits[$key]); 112 + continue; 113 + } 105 114 106 - if ($commits) { 107 - // TODO: AuditQuery is currently not policy-aware and uses an old query 108 - // to load commits. Load them in the modern way to get repositories. 109 - // Remove this after modernizing PhabricatorAuditQuery. 110 - $commits = id(new DiffusionCommitQuery()) 111 - ->setViewer($viewer) 112 - ->withPHIDs(mpull($commits, 'getPHID')) 113 - ->execute(); 114 - $commits = mpull($commits, null, 'getPHID'); 115 - } 116 - 117 - foreach ($audits as $key => $audit) { 118 - $commit = idx($commits, $audit->getCommitPHID()); 119 - if (!$commit) { 120 - unset($audits[$key]); 121 - continue; 115 + if ($max_date && $commit->getEpoch() > $max_date) { 116 + unset($audits[$key]); 117 + continue; 118 + } 122 119 } 123 - 124 - if ($min_date && $commit->getEpoch() < $min_date) { 125 - unset($audits[$key]); 126 - continue; 127 - } 128 - 129 - if ($max_date && $commit->getEpoch() > $max_date) { 130 - unset($audits[$key]); 131 - continue; 132 - } 120 + $audits[] = $curr_audits; 133 121 } 122 + $audits = array_mergev($audits); 134 123 135 124 $console = PhutilConsole::getConsole(); 136 125 ··· 146 135 147 136 148 137 foreach ($audits as $audit) { 149 - $commit = idx($commits, $audit->getCommitPHID()); 138 + $commit = $commits[$audit->getCommitPHID()]; 150 139 151 140 $console->writeOut( 152 141 "%s\n",
-220
src/applications/audit/query/PhabricatorAuditCommitQuery.php
··· 1 - <?php 2 - 3 - final class PhabricatorAuditCommitQuery { 4 - 5 - private $offset; 6 - private $limit; 7 - 8 - private $commitPHIDs; 9 - private $authorPHIDs; 10 - private $packagePHIDs; 11 - private $identifiers = array(); 12 - 13 - private $needCommitData; 14 - private $needAudits; 15 - 16 - private $status = 'status-any'; 17 - const STATUS_ANY = 'status-any'; 18 - const STATUS_OPEN = 'status-open'; 19 - const STATUS_CONCERN = 'status-concern'; 20 - 21 - public function withAuthorPHIDs(array $author_phids) { 22 - $this->authorPHIDs = $author_phids; 23 - return $this; 24 - } 25 - 26 - public function withPackagePHIDs(array $phids) { 27 - $this->packagePHIDs = $phids; 28 - return $this; 29 - } 30 - 31 - public function withCommitPHIDs(array $phids) { 32 - $this->commitPHIDs = $phids; 33 - return $this; 34 - } 35 - 36 - public function withStatus($status) { 37 - $this->status = $status; 38 - return $this; 39 - } 40 - 41 - public function withIdentifiers($repository_id, array $identifiers) { 42 - $this->identifiers[] = array($repository_id, $identifiers); 43 - return $this; 44 - } 45 - 46 - public function needCommitData($need) { 47 - $this->needCommitData = $need; 48 - return $this; 49 - } 50 - 51 - public function needAudits($need) { 52 - $this->needAudits = $need; 53 - return $this; 54 - } 55 - 56 - public function setOffset($offset) { 57 - $this->offset = $offset; 58 - return $this; 59 - } 60 - 61 - public function setLimit($limit) { 62 - $this->limit = $limit; 63 - return $this; 64 - } 65 - 66 - public function execute() { 67 - 68 - $table = new PhabricatorRepositoryCommit(); 69 - $conn_r = $table->establishConnection('r'); 70 - 71 - $join = $this->buildJoinClause($conn_r); 72 - $where = $this->buildWhereClause($conn_r); 73 - $order = $this->buildOrderClause($conn_r); 74 - $limit = $this->buildLimitClause($conn_r); 75 - 76 - $data = queryfx_all( 77 - $conn_r, 78 - 'SELECT c.* FROM %T c %Q %Q %Q %Q', 79 - $table->getTableName(), 80 - $join, 81 - $where, 82 - $order, 83 - $limit); 84 - 85 - $commits = $table->loadAllFromArray($data); 86 - 87 - if ($this->needCommitData && $commits) { 88 - $data = id(new PhabricatorRepositoryCommitData())->loadAllWhere( 89 - 'commitID in (%Ld)', 90 - mpull($commits, 'getID')); 91 - $data = mpull($data, null, 'getCommitID'); 92 - foreach ($commits as $commit) { 93 - if (idx($data, $commit->getID())) { 94 - $commit->attachCommitData($data[$commit->getID()]); 95 - } else { 96 - $commit->attachCommitData(new PhabricatorRepositoryCommitData()); 97 - } 98 - } 99 - } 100 - 101 - if ($this->needAudits && $commits) { 102 - $audits = id(new PhabricatorAuditComment())->loadAllWhere( 103 - 'targetPHID in (%Ls)', 104 - mpull($commits, 'getPHID')); 105 - $audits = mgroup($audits, 'getTargetPHID'); 106 - foreach ($commits as $commit) { 107 - $commit->attachAudits(idx($audits, $commit->getPHID(), array())); 108 - } 109 - } 110 - 111 - return $commits; 112 - 113 - } 114 - 115 - private function buildOrderClause($conn_r) { 116 - return 'ORDER BY c.epoch DESC'; 117 - } 118 - 119 - private function buildJoinClause($conn_r) { 120 - $join = array(); 121 - 122 - if ($this->packagePHIDs) { 123 - $join[] = qsprintf( 124 - $conn_r, 125 - 'JOIN %T req ON c.phid = req.commitPHID', 126 - id(new PhabricatorRepositoryAuditRequest())->getTableName()); 127 - } 128 - 129 - if ($join) { 130 - $join = implode(' ', $join); 131 - } else { 132 - $join = ''; 133 - } 134 - 135 - return $join; 136 - } 137 - 138 - private function buildWhereClause($conn_r) { 139 - $where = array(); 140 - 141 - if ($this->commitPHIDs) { 142 - $where[] = qsprintf( 143 - $conn_r, 144 - 'c.phid IN (%Ls)', 145 - $this->commitPHIDs); 146 - } 147 - 148 - if ($this->authorPHIDs) { 149 - $where[] = qsprintf( 150 - $conn_r, 151 - 'c.authorPHID IN (%Ls)', 152 - $this->authorPHIDs); 153 - } 154 - 155 - if ($this->packagePHIDs) { 156 - $where[] = qsprintf( 157 - $conn_r, 158 - 'req.auditorPHID in (%Ls)', 159 - $this->packagePHIDs); 160 - } 161 - 162 - if ($this->identifiers) { 163 - $clauses = array(); 164 - foreach ($this->identifiers as $spec) { 165 - list($repository_id, $identifiers) = $spec; 166 - if ($identifiers) { 167 - $clauses[] = qsprintf( 168 - $conn_r, 169 - 'c.repositoryID = %d AND c.commitIdentifier IN (%Ls)', 170 - $repository_id, 171 - $identifiers); 172 - } 173 - } 174 - if ($clauses) { 175 - $where[] = '('.implode(') OR (', $clauses).')'; 176 - } 177 - } 178 - 179 - $status = $this->status; 180 - switch ($status) { 181 - case self::STATUS_CONCERN: 182 - $where[] = qsprintf( 183 - $conn_r, 184 - 'c.auditStatus = %d', 185 - PhabricatorAuditCommitStatusConstants::CONCERN_RAISED); 186 - break; 187 - case self::STATUS_OPEN: 188 - $where[] = qsprintf( 189 - $conn_r, 190 - 'c.auditStatus IN (%Ld)', 191 - PhabricatorAuditCommitStatusConstants::getOpenStatusConstants()); 192 - break; 193 - case self::STATUS_ANY: 194 - break; 195 - default: 196 - throw new Exception("Unknown status '{$status}'!"); 197 - } 198 - 199 - if ($where) { 200 - $where = 'WHERE ('.implode(') AND (', $where).')'; 201 - } else { 202 - $where = ''; 203 - } 204 - 205 - return $where; 206 - } 207 - 208 - private function buildLimitClause($conn_r) { 209 - if ($this->limit && $this->offset) { 210 - return qsprintf($conn_r, 'LIMIT %d, %d', $this->offset, $this->limit); 211 - } else if ($this->limit) { 212 - return qsprintf($conn_r, 'LIMIT %d', $this->limit); 213 - } else if ($this->offset) { 214 - return qsprintf($conn_r, 'LIMIT %d, %d', $this->offset, PHP_INT_MAX); 215 - } else { 216 - return ''; 217 - } 218 - } 219 - 220 - }
-263
src/applications/audit/query/PhabricatorAuditQuery.php
··· 1 - <?php 2 - 3 - final class PhabricatorAuditQuery { 4 - 5 - private $ids; 6 - private $offset; 7 - private $limit; 8 - 9 - private $auditorPHIDs; 10 - private $commitPHIDs; 11 - 12 - private $repositoryPHIDs; 13 - 14 - private $needCommits; 15 - private $needCommitData; 16 - 17 - private $awaitingUser; 18 - 19 - private $status = 'status-any'; 20 - const STATUS_ANY = 'status-any'; 21 - const STATUS_OPEN = 'status-open'; 22 - const STATUS_CONCERN = 'status-concern'; 23 - 24 - private $commits; 25 - 26 - public function withIDs(array $ids) { 27 - $this->ids = $ids; 28 - return $this; 29 - } 30 - 31 - public function withCommitPHIDs(array $commit_phids) { 32 - $this->commitPHIDs = $commit_phids; 33 - return $this; 34 - } 35 - 36 - public function withAuditorPHIDs(array $auditor_phids) { 37 - $this->auditorPHIDs = $auditor_phids; 38 - return $this; 39 - } 40 - 41 - public function withRepositoryPHIDs(array $repository_phids) { 42 - $this->repositoryPHIDs = $repository_phids; 43 - return $this; 44 - } 45 - 46 - public function withAwaitingUser(PhabricatorUser $user) { 47 - $this->awaitingUser = $user; 48 - return $this; 49 - } 50 - 51 - public function withStatus($status) { 52 - $this->status = $status; 53 - return $this; 54 - } 55 - 56 - public function setOffset($offset) { 57 - $this->offset = $offset; 58 - return $this; 59 - } 60 - 61 - public function setLimit($limit) { 62 - $this->limit = $limit; 63 - return $this; 64 - } 65 - 66 - public function needCommits($need) { 67 - $this->needCommits = $need; 68 - return $this; 69 - } 70 - 71 - public function needCommitData($need) { 72 - $this->needCommitData = $need; 73 - return $this; 74 - } 75 - 76 - public function execute() { 77 - $table = new PhabricatorRepositoryAuditRequest(); 78 - $conn_r = $table->establishConnection('r'); 79 - 80 - $joins = $this->buildJoinClause($conn_r); 81 - $where = $this->buildWhereClause($conn_r); 82 - $order = $this->buildOrderClause($conn_r); 83 - $limit = $this->buildLimitClause($conn_r); 84 - 85 - $data = queryfx_all( 86 - $conn_r, 87 - 'SELECT req.* FROM %T req %Q %Q %Q %Q', 88 - $table->getTableName(), 89 - $joins, 90 - $where, 91 - $order, 92 - $limit); 93 - 94 - $audits = $table->loadAllFromArray($data); 95 - 96 - if ($this->needCommits || $this->needCommitData) { 97 - $phids = mpull($audits, 'getCommitPHID', 'getCommitPHID'); 98 - if ($phids) { 99 - $cquery = new PhabricatorAuditCommitQuery(); 100 - $cquery->needCommitData($this->needCommitData); 101 - $cquery->withCommitPHIDs(array_keys($phids)); 102 - $commits = $cquery->execute(); 103 - } else { 104 - $commits = array(); 105 - } 106 - $this->commits = $commits; 107 - } 108 - 109 - return $audits; 110 - } 111 - 112 - public function getCommits() { 113 - if ($this->commits === null) { 114 - throw new Exception( 115 - "Call needCommits() or needCommitData() and then execute() the query ". 116 - "before calling getCommits()!"); 117 - } 118 - 119 - return $this->commits; 120 - } 121 - 122 - private function buildJoinClause($conn_r) { 123 - 124 - $joins = array(); 125 - 126 - if ($this->awaitingUser) { 127 - // Join the request table on the awaiting user's requests, so we can 128 - // filter out package and project requests which the user has resigned 129 - // from. 130 - $joins[] = qsprintf( 131 - $conn_r, 132 - 'LEFT JOIN %T awaiting ON req.commitPHID = awaiting.commitPHID AND 133 - awaiting.auditorPHID = %s', 134 - id(new PhabricatorRepositoryAuditRequest())->getTableName(), 135 - $this->awaitingUser->getPHID()); 136 - } 137 - 138 - if ($this->awaitingUser || $this->repositoryPHIDs) { 139 - // Join the commit table so we can get the commit author or repository id 140 - // into the result row and filter by it later. 141 - $joins[] = qsprintf( 142 - $conn_r, 143 - 'JOIN %T commit ON req.commitPHID = commit.phid', 144 - id(new PhabricatorRepositoryCommit())->getTableName()); 145 - } 146 - 147 - if ($this->repositoryPHIDs) { 148 - // Join in the repository table so we can filter by repository PHID 149 - $joins[] = qsprintf( 150 - $conn_r, 151 - 'JOIN %T repository ON repository.id = commit.repositoryID', 152 - id(new PhabricatorRepository())->getTableName()); 153 - } 154 - 155 - if ($joins) { 156 - return implode(' ', $joins); 157 - } else { 158 - return ''; 159 - } 160 - } 161 - 162 - private function buildWhereClause($conn_r) { 163 - $where = array(); 164 - 165 - if ($this->ids) { 166 - $where[] = qsprintf( 167 - $conn_r, 168 - 'req.id IN (%Ld)', 169 - $this->ids); 170 - } 171 - 172 - if ($this->commitPHIDs) { 173 - $where[] = qsprintf( 174 - $conn_r, 175 - 'req.commitPHID IN (%Ls)', 176 - $this->commitPHIDs); 177 - } 178 - 179 - if ($this->auditorPHIDs) { 180 - $where[] = qsprintf( 181 - $conn_r, 182 - 'req.auditorPHID IN (%Ls)', 183 - $this->auditorPHIDs); 184 - } 185 - 186 - if ($this->awaitingUser) { 187 - // Exclude package and project audits associated with commits where 188 - // the user is the author. 189 - $where[] = qsprintf( 190 - $conn_r, 191 - '(commit.authorPHID IS NULL OR commit.authorPHID != %s) 192 - OR (req.auditorPHID = %s)', 193 - $this->awaitingUser->getPHID(), 194 - $this->awaitingUser->getPHID()); 195 - } 196 - 197 - if ($this->repositoryPHIDs) { 198 - // Filter only for a single repository 199 - $where[] = qsprintf( 200 - $conn_r, 201 - 'repository.phid IN (%Ls)', 202 - $this->repositoryPHIDs); 203 - } 204 - 205 - $status = $this->status; 206 - switch ($status) { 207 - case self::STATUS_CONCERN: 208 - $where[] = qsprintf( 209 - $conn_r, 210 - 'req.auditStatus = %s', 211 - PhabricatorAuditStatusConstants::CONCERNED); 212 - break; 213 - case self::STATUS_OPEN: 214 - $where[] = qsprintf( 215 - $conn_r, 216 - 'req.auditStatus in (%Ls)', 217 - PhabricatorAuditStatusConstants::getOpenStatusConstants()); 218 - if ($this->awaitingUser) { 219 - $where[] = qsprintf( 220 - $conn_r, 221 - 'awaiting.auditStatus IS NULL OR awaiting.auditStatus != %s', 222 - PhabricatorAuditStatusConstants::RESIGNED); 223 - } 224 - break; 225 - case self::STATUS_ANY: 226 - break; 227 - default: 228 - $valid = array( 229 - self::STATUS_ANY, 230 - self::STATUS_OPEN, 231 - self::STATUS_CONCERN, 232 - ); 233 - throw new Exception( 234 - "Unknown audit status '{$status}'! Valid statuses are: ". 235 - implode(', ', $valid)); 236 - } 237 - 238 - if ($where) { 239 - $where = 'WHERE ('.implode(') AND (', $where).')'; 240 - } else { 241 - $where = ''; 242 - } 243 - 244 - return $where; 245 - } 246 - 247 - private function buildLimitClause($conn_r) { 248 - if ($this->limit && $this->offset) { 249 - return qsprintf($conn_r, 'LIMIT %d, %d', $this->offset, $this->limit); 250 - } else if ($this->limit) { 251 - return qsprintf($conn_r, 'LIMIT %d', $this->limit); 252 - } else if ($this->offset) { 253 - return qsprintf($conn_r, 'LIMIT %d, %d', $this->offset, PHP_INT_MAX); 254 - } else { 255 - return ''; 256 - } 257 - } 258 - 259 - private function buildOrderClause($conn_r) { 260 - return 'ORDER BY req.id DESC'; 261 - } 262 - 263 - }
+154
src/applications/audit/query/PhabricatorCommitSearchEngine.php
··· 1 + <?php 2 + 3 + final class PhabricatorCommitSearchEngine 4 + extends PhabricatorApplicationSearchEngine { 5 + 6 + public function buildSavedQueryFromRequest(AphrontRequest $request) { 7 + $saved = new PhabricatorSavedQuery(); 8 + 9 + $saved->setParameter( 10 + 'auditorPHIDs', 11 + $this->readPHIDsFromRequest($request, 'auditorPHIDs')); 12 + 13 + $saved->setParameter( 14 + 'commitAuthorPHIDs', 15 + $this->readUsersFromRequest($request, 'commitAuthorPHIDs')); 16 + 17 + $saved->setParameter( 18 + 'auditStatus', 19 + $request->getStr('auditStatus')); 20 + 21 + $saved->setParameter( 22 + 'repositoryPHIDs', 23 + $this->readPHIDsFromRequest($request, 'repositoryPHIDs')); 24 + 25 + // -- TODO - T4173 - file location 26 + 27 + return $saved; 28 + } 29 + 30 + public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) { 31 + $query = id(new DiffusionCommitQuery()) 32 + ->needAuditRequests(true) 33 + ->needCommitData(true); 34 + 35 + $auditor_phids = $saved->getParameter('auditorPHIDs', array()); 36 + if ($auditor_phids) { 37 + $query->withAuditorPHIDs($auditor_phids); 38 + } 39 + 40 + $commit_author_phids = $saved->getParameter('commitAuthorPHIDs', array()); 41 + if ($commit_author_phids) { 42 + $query->withAuthorPHIDs($commit_author_phids); 43 + } 44 + 45 + $audit_status = $saved->getParameter('auditStatus', null); 46 + if ($audit_status) { 47 + $query->withAuditStatus($audit_status); 48 + } 49 + 50 + $awaiting_user_phid = $saved->getParameter('awaitingUserPHID', null); 51 + if ($awaiting_user_phid) { 52 + // This is used only for the built-in "needs attention" filter, 53 + // so cheat and just use the already-loaded viewer rather than reloading 54 + // it. 55 + $query->withAuditAwaitingUser($this->requireViewer()); 56 + } 57 + 58 + return $query; 59 + } 60 + 61 + public function buildSearchForm( 62 + AphrontFormView $form, 63 + PhabricatorSavedQuery $saved) { 64 + 65 + $auditor_phids = $saved->getParameter('auditorPHIDs', array()); 66 + $commit_author_phids = $saved->getParameter( 67 + 'commitAuthorPHIDs', 68 + array()); 69 + $audit_status = $saved->getParameter('auditStatus', null); 70 + 71 + $phids = array_mergev( 72 + array( 73 + $auditor_phids, 74 + $commit_author_phids)); 75 + 76 + $handles = id(new PhabricatorHandleQuery()) 77 + ->setViewer($this->requireViewer()) 78 + ->withPHIDs($phids) 79 + ->execute(); 80 + 81 + $form 82 + ->appendChild( 83 + id(new AphrontFormTokenizerControl()) 84 + ->setDatasource('/typeahead/common/usersprojectsorpackages/') 85 + ->setName('auditorPHIDs') 86 + ->setLabel(pht('Auditors')) 87 + ->setValue(array_select_keys($handles, $auditor_phids))) 88 + ->appendChild( 89 + id(new AphrontFormTokenizerControl()) 90 + ->setDatasource('/typeahead/common/users/') 91 + ->setName('commitAuthorPHIDs') 92 + ->setLabel(pht('Commit Authors')) 93 + ->setValue(array_select_keys($handles, $commit_author_phids))) 94 + ->appendChild( 95 + id(new AphrontFormSelectControl()) 96 + ->setName('auditStatus') 97 + ->setLabel(pht('Audit Status')) 98 + ->setOptions($this->getAuditStatusOptions()) 99 + ->setValue($audit_status)); 100 + } 101 + 102 + protected function getURI($path) { 103 + return '/audit/'.$path; 104 + } 105 + 106 + public function getBuiltinQueryNames() { 107 + $names = array(); 108 + 109 + if ($this->requireViewer()->isLoggedIn()) { 110 + $names['need_attention'] = pht('Need Attention'); 111 + } 112 + $names['open'] = pht('Open Audits'); 113 + 114 + $names['all'] = pht('All Commits'); 115 + 116 + return $names; 117 + } 118 + 119 + public function buildSavedQueryFromBuiltin($query_key) { 120 + $query = $this->newSavedQuery(); 121 + $query->setQueryKey($query_key); 122 + $viewer = $this->requireViewer(); 123 + 124 + switch ($query_key) { 125 + case 'all': 126 + return $query; 127 + case 'open': 128 + $query->setParameter( 129 + 'auditStatus', 130 + DiffusionCommitQuery::AUDIT_STATUS_OPEN); 131 + return $query; 132 + case 'need_attention': 133 + $query->setParameter('awaitingUserPHID', $viewer->getPHID()); 134 + $query->setParameter( 135 + 'auditStatus', 136 + DiffusionCommitQuery::AUDIT_STATUS_OPEN); 137 + $query->setParameter( 138 + 'auditorPHIDs', 139 + PhabricatorAuditCommentEditor::loadAuditPHIDsForUser($viewer)); 140 + return $query; 141 + } 142 + 143 + return parent::buildSavedQueryFromBuiltin($query_key); 144 + } 145 + 146 + private function getAuditStatusOptions() { 147 + return array( 148 + DiffusionCommitQuery::AUDIT_STATUS_ANY => pht('Any'), 149 + DiffusionCommitQuery::AUDIT_STATUS_OPEN => pht('Open'), 150 + DiffusionCommitQuery::AUDIT_STATUS_CONCERN => pht('Concern Raised'), 151 + ); 152 + } 153 + 154 + }
-123
src/applications/audit/view/PhabricatorAuditCommitListView.php
··· 1 - <?php 2 - 3 - final class PhabricatorAuditCommitListView extends AphrontView { 4 - 5 - private $commits; 6 - private $handles; 7 - private $noDataString; 8 - 9 - public function setNoDataString($no_data_string) { 10 - $this->noDataString = $no_data_string; 11 - return $this; 12 - } 13 - 14 - public function setCommits(array $commits) { 15 - assert_instances_of($commits, 'PhabricatorRepositoryCommit'); 16 - $this->commits = mpull($commits, null, 'getPHID'); 17 - return $this; 18 - } 19 - 20 - public function setHandles(array $handles) { 21 - assert_instances_of($handles, 'PhabricatorObjectHandle'); 22 - $this->handles = $handles; 23 - return $this; 24 - } 25 - 26 - public function setAuthorityPHIDs(array $phids) { 27 - $this->authorityPHIDs = $phids; 28 - return $this; 29 - } 30 - 31 - public function getRequiredHandlePHIDs() { 32 - $phids = array(); 33 - foreach ($this->commits as $commit) { 34 - if ($commit->getAuthorPHID()) { 35 - $phids[$commit->getAuthorPHID()] = true; 36 - } 37 - $phids[$commit->getPHID()] = true; 38 - if ($commit->getAudits()) { 39 - foreach ($commit->getAudits() as $audit) { 40 - $phids[$audit->getActorPHID()] = true; 41 - } 42 - } 43 - } 44 - return array_keys($phids); 45 - } 46 - 47 - private function getHandle($phid) { 48 - $handle = idx($this->handles, $phid); 49 - if (!$handle) { 50 - throw new Exception("No handle for '{$phid}'!"); 51 - } 52 - return $handle; 53 - } 54 - 55 - private function getCommitDescription($phid) { 56 - if ($this->commits === null) { 57 - return null; 58 - } 59 - 60 - $commit = idx($this->commits, $phid); 61 - if (!$commit) { 62 - return null; 63 - } 64 - 65 - return $commit->getCommitData()->getSummary(); 66 - } 67 - 68 - public function render() { 69 - $list = new PHUIObjectItemListView(); 70 - $list->setCards(true); 71 - $list->setFlush(true); 72 - foreach ($this->commits as $commit) { 73 - $commit_phid = $commit->getPHID(); 74 - $commit_name = $this->getHandle($commit_phid)->getName(); 75 - $commit_link = $this->getHandle($commit_phid)->getURI(); 76 - $commit_desc = $this->getCommitDescription($commit_phid); 77 - 78 - $author_name = null; 79 - if ($commit->getAuthorPHID()) { 80 - $author_name = $this->getHandle($commit->getAuthorPHID())->renderLink(); 81 - } 82 - $auditors = array(); 83 - if ($commit->getAudits()) { 84 - foreach ($commit->getAudits() as $audit) { 85 - $actor_phid = $audit->getActorPHID(); 86 - $auditors[$actor_phid] = $this->getHandle($actor_phid)->renderLink(); 87 - } 88 - $auditors = phutil_implode_html(', ', $auditors); 89 - } 90 - $committed = phabricator_datetime($commit->getEpoch(), $this->user); 91 - $audit_status = $commit->getAuditStatus(); 92 - $commit_status = PhabricatorAuditCommitStatusConstants::getStatusName( 93 - $audit_status); 94 - $status_color = PhabricatorAuditCommitStatusConstants::getStatusColor( 95 - $audit_status); 96 - 97 - $item = id(new PHUIObjectItemView()) 98 - ->setBarColor($status_color) 99 - ->setObjectName($commit_name) 100 - ->setHeader($commit_desc) 101 - ->setHref($commit_link) 102 - ->addAttribute($commit_status) 103 - ->addIcon('none', $committed); 104 - 105 - if (!empty($auditors)) { 106 - $item->addAttribute(pht('Auditors: %s', $auditors)); 107 - } 108 - 109 - if ($author_name) { 110 - $item->addByline(pht('Author: %s', $author_name)); 111 - } 112 - 113 - $list->addItem($item); 114 - } 115 - 116 - if ($this->noDataString) { 117 - $list->setNoDataString($this->noDataString); 118 - } 119 - 120 - return $list->render(); 121 - } 122 - 123 - }
+61 -66
src/applications/audit/view/PhabricatorAuditListView.php
··· 2 2 3 3 final class PhabricatorAuditListView extends AphrontView { 4 4 5 - private $audits; 5 + private $commits; 6 6 private $handles; 7 7 private $authorityPHIDs = array(); 8 8 private $noDataString; 9 - private $commits; 10 - private $showCommits = true; 11 9 12 10 private $highlightedAudits; 13 11 14 - public function setAudits(array $audits) { 15 - assert_instances_of($audits, 'PhabricatorRepositoryAuditRequest'); 16 - $this->audits = $audits; 17 - return $this; 18 - } 19 - 20 12 public function setHandles(array $handles) { 21 13 assert_instances_of($handles, 'PhabricatorObjectHandle'); 22 14 $this->handles = $handles; ··· 37 29 return $this->noDataString; 38 30 } 39 31 32 + /** 33 + * These commits should have both commit data and audit requests attached. 34 + */ 40 35 public function setCommits(array $commits) { 41 36 assert_instances_of($commits, 'PhabricatorRepositoryCommit'); 42 37 $this->commits = mpull($commits, null, 'getPHID'); 43 38 return $this; 44 39 } 45 40 46 - public function setShowCommits($show_commits) { 47 - $this->showCommits = $show_commits; 48 - return $this; 41 + public function getCommits() { 42 + return $this->commits; 49 43 } 50 44 51 45 public function getRequiredHandlePHIDs() { 52 46 $phids = array(); 53 - foreach ($this->audits as $audit) { 54 - $phids[$audit->getCommitPHID()] = true; 55 - $phids[$audit->getAuditorPHID()] = true; 47 + $commits = $this->getCommits(); 48 + foreach ($commits as $commit) { 49 + $phids[$commit->getPHID()] = true; 50 + $phids[$commit->getAuthorPHID()] = true; 51 + $audits = $commit->getAudits(); 52 + foreach ($audits as $audit) { 53 + $phids[$audit->getAuditorPHID()] = true; 54 + } 56 55 } 57 56 return array_keys($phids); 58 57 } ··· 78 77 return $commit->getCommitData()->getSummary(); 79 78 } 80 79 81 - public function getHighlightedAudits() { 82 - if ($this->highlightedAudits === null) { 83 - $this->highlightedAudits = array(); 84 - 85 - $user = $this->user; 86 - $authority = array_fill_keys($this->authorityPHIDs, true); 87 - 88 - foreach ($this->audits as $audit) { 89 - $has_authority = !empty($authority[$audit->getAuditorPHID()]); 90 - if ($has_authority) { 91 - $commit_phid = $audit->getCommitPHID(); 92 - $commit_author = $this->commits[$commit_phid]->getAuthorPHID(); 93 - 94 - // You don't have authority over package and project audits on your 95 - // own commits. 96 - 97 - $auditor_is_user = ($audit->getAuditorPHID() == $user->getPHID()); 98 - $user_is_author = ($commit_author == $user->getPHID()); 80 + public function render() { 81 + $list = $this->buildList(); 82 + $list->setCards(true); 83 + $list->setFlush(true); 84 + return $list->render(); 85 + } 99 86 100 - if ($auditor_is_user || !$user_is_author) { 101 - $this->highlightedAudits[$audit->getID()] = $audit; 102 - } 103 - } 104 - } 87 + public function buildList() { 88 + $user = $this->getUser(); 89 + if (!$user) { 90 + throw new Exception('you must setUser() before buildList()!'); 105 91 } 106 - 107 - return $this->highlightedAudits; 108 - } 109 - 110 - public function render() { 111 92 $rowc = array(); 112 93 113 94 $list = new PHUIObjectItemListView(); 114 - $list->setCards(true); 115 - $list->setFlush(true); 116 - foreach ($this->audits as $audit) { 117 - $commit_phid = $audit->getCommitPHID(); 95 + $authority = array_fill_keys($this->authorityPHIDs, true); 96 + foreach ($this->commits as $commit) { 97 + $commit_phid = $commit->getPHID(); 98 + $commit_handle = $this->getHandle($commit_phid); 118 99 $committed = null; 119 100 120 - $commit_name = $this->getHandle($commit_phid)->getName(); 121 - $commit_link = $this->getHandle($commit_phid)->getURI(); 101 + $commit_name = $commit_handle->getName(); 102 + $commit_link = $commit_handle->getURI(); 122 103 $commit_desc = $this->getCommitDescription($commit_phid); 123 - $commit = idx($this->commits, $commit_phid); 124 - if ($commit && $this->user) { 125 - $committed = phabricator_datetime($commit->getEpoch(), $this->user); 104 + $committed = phabricator_datetime($commit->getEpoch(), $user); 105 + 106 + $audits = mpull($commit->getAudits(), null, 'getAuditorPHID'); 107 + $auditors = array(); 108 + $reasons = array(); 109 + foreach ($audits as $audit) { 110 + $auditor_phid = $audit->getAuditorPHID(); 111 + $auditors[$auditor_phid] = 112 + $this->getHandle($auditor_phid)->renderLink(); 126 113 } 114 + $auditors = phutil_implode_html(', ', $auditors); 127 115 128 - $reasons = $audit->getAuditReasons(); 129 - $reasons = phutil_implode_html(', ', $reasons); 130 - 131 - $status_code = $audit->getAuditStatus(); 132 - $status_text = 133 - PhabricatorAuditStatusConstants::getStatusName($status_code); 134 - $status_color = 135 - PhabricatorAuditStatusConstants::getStatusColor($status_code); 136 - 116 + $audit = idx($audits, $user->getPHID()); 117 + if ($audit) { 118 + $reasons = $audit->getAuditReasons(); 119 + $reasons = phutil_implode_html(', ', $reasons); 120 + $status_code = $audit->getAuditStatus(); 121 + $status_text = 122 + PhabricatorAuditStatusConstants::getStatusName($status_code); 123 + $status_color = 124 + PhabricatorAuditStatusConstants::getStatusColor($status_code); 125 + } else { 126 + $reasons = null; 127 + $status_text = null; 128 + $status_color = null; 129 + } 137 130 $author_name = $commit->getCommitData()->getAuthorName(); 138 131 139 - $auditor_handle = $this->getHandle($audit->getAuditorPHID()); 140 132 $item = id(new PHUIObjectItemView()) 141 133 ->setObjectName($commit_name) 142 134 ->setHeader($commit_desc) ··· 144 136 ->setBarColor($status_color) 145 137 ->addAttribute($status_text) 146 138 ->addAttribute($reasons) 147 - ->addAttribute(pht('Author: %s', $author_name)) 148 139 ->addIcon('none', $committed) 149 - ->addByline(pht('Auditor: %s', $auditor_handle->renderLink())); 140 + ->addByline(pht('Author: %s', $author_name)); 141 + 142 + if (!empty($auditors)) { 143 + $item->addAttribute(pht('Auditors: %s', $auditors)); 144 + } 150 145 151 - if (array_key_exists($audit->getID(), $this->getHighlightedAudits())) { 146 + if ($commit->getAuthorityAudits($user, $this->authorityPHIDs)) { 152 147 $item->setEffect('highlighted'); 153 148 } 154 149 ··· 159 154 $list->setNoDataString($this->noDataString); 160 155 } 161 156 162 - return $list->render(); 157 + return $list; 163 158 } 164 159 165 160 }
+15 -17
src/applications/diffusion/controller/DiffusionCommitController.php
··· 28 28 return $this->buildRawDiffResponse($drequest); 29 29 } 30 30 31 - $callsign = $drequest->getRepository()->getCallsign(); 31 + $repository = $drequest->getRepository(); 32 + $callsign = $repository->getCallsign(); 32 33 33 34 $content = array(); 34 - $repository = $drequest->getRepository(); 35 - $commit = $drequest->loadCommit(); 35 + 36 + $commit = id(new DiffusionCommitQuery()) 37 + ->setViewer($request->getUser()) 38 + ->withRepository($repository) 39 + ->withIdentifiers(array($drequest->getCommit())) 40 + ->needCommitData(true) 41 + ->needAuditRequests(true) 42 + ->executeOne(); 36 43 37 44 $crumbs = $this->buildCrumbs(array( 38 45 'commit' => true, ··· 63 70 )); 64 71 } 65 72 66 - $commit_data = $drequest->loadCommitData(); 67 - $commit->attachCommitData($commit_data); 68 73 69 74 $top_anchor = id(new PhabricatorAnchorView()) 70 75 ->setAnchorName('top') 71 76 ->setNavigationMarker(true); 72 77 73 - $audit_requests = id(new PhabricatorAuditQuery()) 74 - ->withCommitPHIDs(array($commit->getPHID())) 75 - ->execute(); 78 + $audit_requests = $commit->getAudits(); 76 79 $this->auditAuthorityPHIDs = 77 80 PhabricatorAuditCommentEditor::loadAuditPHIDsForUser($user); 78 81 82 + $commit_data = $commit->getCommitData(); 79 83 $is_foreign = $commit_data->getCommitDetail('foreign-svn-stub'); 80 84 $changesets = null; 81 85 if ($is_foreign) { ··· 179 183 180 184 $content[] = $this->buildMergesTable($commit); 181 185 182 - // TODO: This is silly, but the logic to figure out which audits are 183 - // highlighted currently lives in PhabricatorAuditListView. Refactor this 184 - // to be less goofy. 185 - $highlighted_audits = id(new PhabricatorAuditListView()) 186 - ->setAudits($audit_requests) 187 - ->setAuthorityPHIDs($this->auditAuthorityPHIDs) 188 - ->setUser($user) 189 - ->setCommits(array($commit->getPHID() => $commit)) 190 - ->getHighlightedAudits(); 186 + $highlighted_audits = $commit->getAuthorityAudits( 187 + $user, 188 + $this->auditAuthorityPHIDs); 191 189 192 190 $owners_paths = array(); 193 191 if ($highlighted_audits) {
+6 -5
src/applications/diffusion/doorkeeper/DiffusionDoorkeeperCommitFeedStoryPublisher.php
··· 46 46 } 47 47 48 48 public function willPublishStory($commit) { 49 - $requests = id(new PhabricatorAuditQuery()) 50 - ->withCommitPHIDs(array($commit->getPHID())) 51 - ->execute(); 49 + $requests = id(new DiffusionCommitQuery()) 50 + ->withPHIDs(array($commit->getPHID())) 51 + ->needAuditRequests(true) 52 + ->executeOne() 53 + ->getAudits(); 52 54 53 55 // TODO: This is messy and should be generalized, but we don't have a good 54 56 // query for it yet. Since we run in the daemons, just do the easiest thing 55 57 // we can for the moment. Figure out who all of the "active" (need to 56 - // audit) and "passive" (no action necessary) user are. 58 + // audit) and "passive" (no action necessary) users are. 57 59 58 60 $auditor_phids = mpull($requests, 'getAuditorPHID'); 59 61 $objects = id(new PhabricatorObjectQuery()) ··· 105 107 break; 106 108 } 107 109 } 108 - 109 110 110 111 111 112 // Remove "Active" users from the "Passive" list.
+210 -28
src/applications/diffusion/query/DiffusionCommitQuery.php
··· 4 4 extends PhabricatorCursorPagedPolicyAwareQuery { 5 5 6 6 private $ids; 7 - private $identifiers; 8 7 private $phids; 8 + private $authorPHIDs; 9 9 private $defaultRepository; 10 + private $identifiers; 11 + private $repositoryIDs; 10 12 private $identifierMap; 11 - private $repositoryIDs; 13 + 14 + private $needAuditRequests; 15 + private $auditIDs; 16 + private $auditorPHIDs; 17 + private $auditAwaitingUser; 18 + private $auditStatus; 19 + const AUDIT_STATUS_ANY = 'audit-status-any'; 20 + const AUDIT_STATUS_OPEN = 'audit-status-open'; 21 + const AUDIT_STATUS_CONCERN = 'audit-status-concern'; 22 + private $loadAuditIds; 12 23 13 24 private $needCommitData; 25 + 26 + public function withIDs(array $ids) { 27 + $this->ids = $ids; 28 + return $this; 29 + } 30 + 31 + public function withPHIDs(array $phids) { 32 + $this->phids = $phids; 33 + return $this; 34 + } 35 + 36 + public function withAuthorPHIDs(array $phids) { 37 + $this->authorPHIDs = $phids; 38 + return $this; 39 + } 14 40 15 41 /** 16 42 * Load commits by partial or full identifiers, e.g. "rXab82393", "rX1234", ··· 24 50 } 25 51 26 52 /** 53 + * Look up commits in a specific repository. This is a shorthand for calling 54 + * @{method:withDefaultRepository} and @{method:withRepositoryIDs}. 55 + */ 56 + public function withRepository(PhabricatorRepository $repository) { 57 + $this->withDefaultRepository($repository); 58 + $this->withRepositoryIDs(array($repository->getID())); 59 + return $this; 60 + } 61 + 62 + /** 27 63 * If a default repository is provided, ambiguous commit identifiers will 28 64 * be assumed to belong to the default repository. 29 65 * ··· 42 78 return $this; 43 79 } 44 80 45 - public function withIDs(array $ids) { 46 - $this->ids = $ids; 81 + public function needCommitData($need) { 82 + $this->needCommitData = $need; 47 83 return $this; 48 84 } 49 85 50 - public function withPHIDs(array $phids) { 51 - $this->phids = $phids; 86 + public function needAuditRequests($need) { 87 + $this->needAuditRequests = $need; 88 + return $this; 89 + } 90 + 91 + public function getAuditRequests() { 92 + return 93 + $this->needAuditRequests || 94 + $this->auditIDs || 95 + $this->auditorPHIDs || 96 + $this->auditAwaitingUser || 97 + $this->auditStatus; 98 + } 99 + 100 + public function withAuditIDs(array $ids) { 101 + $this->auditIDs = $ids; 52 102 return $this; 53 103 } 54 104 105 + public function withAuditorPHIDs(array $auditor_phids) { 106 + $this->auditorPHIDs = $auditor_phids; 107 + return $this; 108 + } 55 109 56 - /** 57 - * Look up commits in a specific repository. This is a shorthand for calling 58 - * @{method:withDefaultRepository} and @{method:withRepositoryIDs}. 59 - */ 60 - public function withRepository(PhabricatorRepository $repository) { 61 - $this->withDefaultRepository($repository); 62 - $this->withRepositoryIDs(array($repository->getID())); 110 + public function withAuditAwaitingUser(PhabricatorUser $user) { 111 + $this->auditAwaitingUser = $user; 63 112 return $this; 64 113 } 65 114 66 - public function needCommitData($need) { 67 - $this->needCommitData = $need; 115 + public function withAuditStatus($status) { 116 + $this->auditStatus = $status; 68 117 return $this; 69 118 } 70 119 ··· 74 123 "You must execute() the query before accessing the identifier map."); 75 124 } 76 125 return $this->identifierMap; 126 + } 127 + 128 + protected function getPagingColumn() { 129 + return 'commit.id'; 77 130 } 78 131 79 132 protected function willExecute() { ··· 88 141 89 142 $data = queryfx_all( 90 143 $conn_r, 91 - 'SELECT * FROM %T %Q %Q %Q', 144 + 'SELECT commit.* %Q FROM %T commit %Q %Q %Q %Q', 145 + $this->buildAuditSelect($conn_r), 92 146 $table->getTableName(), 147 + $this->buildJoinClause($conn_r), 93 148 $this->buildWhereClause($conn_r), 94 149 $this->buildOrderClause($conn_r), 95 150 $this->buildLimitClause($conn_r)); 96 151 152 + if ($this->getAuditRequests()) { 153 + $this->loadAuditIds = ipull($data, 'audit_id'); 154 + } 155 + 97 156 return $table->loadAllFromArray($data); 157 + } 158 + 159 + private function buildAuditSelect($conn_r) { 160 + if ($this->getAuditRequests()) { 161 + return qsprintf( 162 + $conn_r, 163 + ', audit.id as audit_id'); 164 + } 165 + 166 + return ''; 98 167 } 99 168 100 169 protected function willFilterPage(array $commits) { ··· 170 239 } 171 240 } 172 241 242 + if ($this->getAuditRequests()) { 243 + $requests = id(new PhabricatorRepositoryAuditRequest()) 244 + ->loadAllWhere('id IN (%Ld)', $this->loadAuditIds); 245 + 246 + $requests = mgroup($requests, 'getCommitPHID'); 247 + foreach ($commits as $commit) { 248 + $audit_requests = idx($requests, $commit->getPHID(), array()); 249 + $commit->attachAudits($audit_requests); 250 + foreach ($audit_requests as $audit_request) { 251 + $audit_request->attachCommit($commit); 252 + } 253 + } 254 + } 255 + 173 256 return $commits; 174 257 } 175 258 176 259 private function buildWhereClause(AphrontDatabaseConnection $conn_r) { 177 260 $where = array(); 178 261 262 + if ($this->ids) { 263 + $where[] = qsprintf( 264 + $conn_r, 265 + 'commit.id IN (%Ld)', 266 + $this->ids); 267 + } 268 + 269 + if ($this->phids) { 270 + $where[] = qsprintf( 271 + $conn_r, 272 + 'commit.phid IN (%Ls)', 273 + $this->phids); 274 + } 275 + 276 + if ($this->repositoryIDs) { 277 + $where[] = qsprintf( 278 + $conn_r, 279 + 'commit.repositoryID IN (%Ld)', 280 + $this->repositoryIDs); 281 + } 282 + 283 + if ($this->authorPHIDs) { 284 + $where[] = qsprintf( 285 + $conn_r, 286 + 'commit.authorPHID IN (%Ls)', 287 + $this->authorPHIDs); 288 + } 289 + 179 290 if ($this->identifiers) { 180 291 $min_unqualified = PhabricatorRepository::MINIMUM_UNQUALIFIED_HASH; 181 292 $min_qualified = PhabricatorRepository::MINIMUM_QUALIFIED_HASH; ··· 212 323 foreach ($bare as $identifier) { 213 324 $sql[] = qsprintf( 214 325 $conn_r, 215 - '(commitIdentifier LIKE %> AND LENGTH(commitIdentifier) = 40)', 326 + '(commit.commitIdentifier LIKE %> AND '. 327 + 'LENGTH(commit.commitIdentifier) = 40)', 216 328 $identifier); 217 329 } 218 330 ··· 236 348 } 237 349 $sql[] = qsprintf( 238 350 $conn_r, 239 - '(repositoryID = %d AND commitIdentifier = %s)', 351 + '(commit.repositoryID = %d AND commit.commitIdentifier = %s)', 240 352 $repo->getID(), 241 353 // NOTE: Because the 'commitIdentifier' column is a string, MySQL 242 354 // ignores the index if we hand it an integer. Hand it a string. ··· 248 360 } 249 361 $sql[] = qsprintf( 250 362 $conn_r, 251 - '(repositoryID = %d AND commitIdentifier LIKE %>)', 363 + '(commit.repositoryID = %d AND commit.commitIdentifier LIKE %>)', 252 364 $repo->getID(), 253 365 $ref['identifier']); 254 366 } ··· 266 378 $where[] = '('.implode(' OR ', $sql).')'; 267 379 } 268 380 269 - if ($this->ids) { 381 + if ($this->auditIDs) { 270 382 $where[] = qsprintf( 271 383 $conn_r, 272 - 'id IN (%Ld)', 273 - $this->ids); 384 + 'audit.id IN (%Ld)', 385 + $this->auditIDs); 274 386 } 275 387 276 - if ($this->phids) { 388 + if ($this->auditorPHIDs) { 277 389 $where[] = qsprintf( 278 390 $conn_r, 279 - 'phid IN (%Ls)', 280 - $this->phids); 391 + 'audit.auditorPHID IN (%Ls)', 392 + $this->auditorPHIDs); 281 393 } 282 394 283 - if ($this->repositoryIDs) { 395 + if ($this->auditAwaitingUser) { 396 + $awaiting_user_phid = $this->auditAwaitingUser->getPHID(); 397 + // Exclude package and project audits associated with commits where 398 + // the user is the author. 284 399 $where[] = qsprintf( 285 400 $conn_r, 286 - 'repositoryID IN (%Ld)', 287 - $this->repositoryIDs); 401 + '(commit.authorPHID IS NULL OR commit.authorPHID != %s) 402 + OR (audit.auditorPHID = %s)', 403 + $awaiting_user_phid, 404 + $awaiting_user_phid); 405 + } 406 + 407 + $status = $this->auditStatus; 408 + if ($status !== null) { 409 + switch ($status) { 410 + case self::AUDIT_STATUS_CONCERN: 411 + $where[] = qsprintf( 412 + $conn_r, 413 + 'audit.auditStatus = %s', 414 + PhabricatorAuditStatusConstants::CONCERNED); 415 + break; 416 + case self::AUDIT_STATUS_OPEN: 417 + $where[] = qsprintf( 418 + $conn_r, 419 + 'audit.auditStatus in (%Ls)', 420 + PhabricatorAuditStatusConstants::getOpenStatusConstants()); 421 + if ($this->auditAwaitingUser) { 422 + $where[] = qsprintf( 423 + $conn_r, 424 + 'awaiting.auditStatus IS NULL OR awaiting.auditStatus != %s', 425 + PhabricatorAuditStatusConstants::RESIGNED); 426 + } 427 + break; 428 + case self::AUDIT_STATUS_ANY: 429 + break; 430 + default: 431 + $valid = array( 432 + self::AUDIT_STATUS_ANY, 433 + self::AUDIT_STATUS_OPEN, 434 + self::AUDIT_STATUS_CONCERN, 435 + ); 436 + throw new Exception( 437 + "Unknown audit status '{$status}'! Valid statuses are: ". 438 + implode(', ', $valid)); 439 + } 288 440 } 289 441 290 442 $where[] = $this->buildPagingClause($conn_r); ··· 299 451 unset($this->identifierMap[$name]); 300 452 } 301 453 } 454 + } 455 + } 456 + 457 + private function buildJoinClause($conn_r) { 458 + $joins = array(); 459 + $audit_request = new PhabricatorRepositoryAuditRequest(); 460 + 461 + if ($this->getAuditRequests()) { 462 + $joins[] = qsprintf( 463 + $conn_r, 464 + 'JOIN %T audit ON commit.phid = audit.commitPHID', 465 + $audit_request->getTableName()); 466 + } 467 + 468 + if ($this->auditAwaitingUser) { 469 + // Join the request table on the awaiting user's requests, so we can 470 + // filter out package and project requests which the user has resigned 471 + // from. 472 + $joins[] = qsprintf( 473 + $conn_r, 474 + 'LEFT JOIN %T awaiting ON audit.commitPHID = awaiting.commitPHID AND 475 + awaiting.auditorPHID = %s', 476 + $audit_request->getTableName(), 477 + $this->auditAwaitingUser->getPHID()); 478 + } 479 + 480 + if ($joins) { 481 + return implode(' ', $joins); 482 + } else { 483 + return ''; 302 484 } 303 485 } 304 486
+8 -4
src/applications/diffusion/query/filecontent/DiffusionFileContentQuery.php
··· 97 97 98 98 $repository = $this->getRequest()->getRepository(); 99 99 100 - $commits = id(new PhabricatorAuditCommitQuery()) 101 - ->withIdentifiers( 102 - $repository->getID(), 103 - array_unique($line_rev_dict)) 100 + $commits = id(new DiffusionCommitQuery()) 101 + ->setViewer($this->getViewer()) 102 + ->withDefaultRepository($repository) 103 + ->withIdentifiers(array_unique($line_rev_dict)) 104 104 ->execute(); 105 105 106 106 foreach ($commits as $commit) { ··· 143 143 public function setViewer(PhabricatorUser $user) { 144 144 $this->viewer = $user; 145 145 return $this; 146 + } 147 + 148 + public function getViewer() { 149 + return $this->viewer; 146 150 } 147 151 148 152 protected function processRevList(array $rev_list) {
+21 -21
src/applications/home/controller/PhabricatorHomeMainController.php
··· 413 413 414 414 $phids = PhabricatorAuditCommentEditor::loadAuditPHIDsForUser($user); 415 415 416 - $query = new PhabricatorAuditQuery(); 417 - $query->withAuditorPHIDs($phids); 418 - $query->withStatus(PhabricatorAuditQuery::STATUS_OPEN); 419 - $query->withAwaitingUser($user); 420 - $query->needCommitData(true); 421 - $query->setLimit(10); 416 + $query = id(new DiffusionCommitQuery()) 417 + ->setViewer($user) 418 + ->withAuditorPHIDs($phids) 419 + ->withAuditStatus(DiffusionCommitQuery::AUDIT_STATUS_OPEN) 420 + ->withAuditAwaitingUser($user) 421 + ->needCommitData(true) 422 + ->setLimit(10); 422 423 423 - $audits = $query->execute(); 424 - $commits = $query->getCommits(); 424 + $commits = $query->execute(); 425 425 426 - if (!$audits) { 426 + if (!$commits) { 427 427 return $this->renderMinipanel( 428 428 'No Audits', 429 429 'No commits are waiting for you to audit them.'); 430 430 } 431 431 432 - $view = new PhabricatorAuditListView(); 433 - $view->setAudits($audits); 434 - $view->setCommits($commits); 435 - $view->setUser($user); 432 + $view = id(new PhabricatorAuditListView()) 433 + ->setCommits($commits) 434 + ->setUser($user); 436 435 437 436 $phids = $view->getRequiredHandlePHIDs(); 438 437 $handles = $this->loadViewerHandles($phids); ··· 454 453 455 454 $phids = array($user->getPHID()); 456 455 457 - $query = new PhabricatorAuditCommitQuery(); 458 - $query->withAuthorPHIDs($phids); 459 - $query->withStatus(PhabricatorAuditCommitQuery::STATUS_CONCERN); 460 - $query->needCommitData(true); 461 - $query->setLimit(10); 456 + $query = id(new DiffusionCommitQuery()) 457 + ->setViewer($user) 458 + ->withAuthorPHIDs($phids) 459 + ->withAuditStatus(DiffusionCommitQuery::AUDIT_STATUS_CONCERN) 460 + ->needCommitData(true) 461 + ->setLimit(10); 462 462 463 463 $commits = $query->execute(); 464 464 ··· 468 468 'No one has raised concerns with your commits.'); 469 469 } 470 470 471 - $view = new PhabricatorAuditCommitListView(); 472 - $view->setCommits($commits); 473 - $view->setUser($user); 471 + $view = id(new PhabricatorAuditListView()) 472 + ->setCommits($commits) 473 + ->setUser($user); 474 474 475 475 $phids = $view->getRequiredHandlePHIDs(); 476 476 $handles = $this->loadViewerHandles($phids);
+18 -18
src/applications/owners/controller/PhabricatorOwnersDetailController.php
··· 145 145 'phid' => $package->getPHID(), 146 146 )); 147 147 148 - $attention_query = id(new PhabricatorAuditCommitQuery()) 149 - ->withPackagePHIDs(array($package->getPHID())) 150 - ->withStatus(PhabricatorAuditCommitQuery::STATUS_CONCERN) 148 + $attention_commits = id(new DiffusionCommitQuery()) 149 + ->setViewer($request->getUser()) 150 + ->withAuditorPHIDs(array($package->getPHID())) 151 + ->withAuditStatus(DiffusionCommitQuery::AUDIT_STATUS_CONCERN) 151 152 ->needCommitData(true) 152 - ->needAudits(true) 153 - ->setLimit(10); 154 - $attention_commits = $attention_query->execute(); 153 + ->setLimit(10) 154 + ->execute(); 155 155 if ($attention_commits) { 156 - $view = new PhabricatorAuditCommitListView(); 157 - $view->setUser($user); 158 - $view->setCommits($attention_commits); 156 + $view = id(new PhabricatorAuditListView()) 157 + ->setUser($user) 158 + ->setCommits($attention_commits); 159 159 160 160 $commit_views[] = array( 161 161 'view' => $view, ··· 170 170 ); 171 171 } 172 172 173 - $all_query = id(new PhabricatorAuditCommitQuery()) 174 - ->withPackagePHIDs(array($package->getPHID())) 173 + $all_commits = id(new DiffusionCommitQuery()) 174 + ->setViewer($request->getUser()) 175 + ->withAuditorPHIDs(array($package->getPHID())) 175 176 ->needCommitData(true) 176 - ->needAudits(true) 177 - ->setLimit(100); 178 - $all_commits = $all_query->execute(); 177 + ->setLimit(100) 178 + ->execute(); 179 179 180 - $view = new PhabricatorAuditCommitListView(); 181 - $view->setUser($user); 182 - $view->setCommits($all_commits); 183 - $view->setNoDataString(pht('No commits in this package.')); 180 + $view = id(new PhabricatorAuditListView()) 181 + ->setUser($user) 182 + ->setCommits($all_commits) 183 + ->setNoDataString(pht('No commits in this package.')); 184 184 185 185 $commit_views[] = array( 186 186 'view' => $view,
+36 -1
src/applications/repository/storage/PhabricatorRepositoryAuditRequest.php
··· 1 1 <?php 2 2 3 - final class PhabricatorRepositoryAuditRequest extends PhabricatorRepositoryDAO { 3 + final class PhabricatorRepositoryAuditRequest 4 + extends PhabricatorRepositoryDAO 5 + implements PhabricatorPolicyInterface { 4 6 5 7 protected $auditorPHID; 6 8 protected $commitPHID; 7 9 protected $auditReasons = array(); 8 10 protected $auditStatus; 11 + 12 + private $commit = self::ATTACHABLE; 9 13 10 14 public function getConfiguration() { 11 15 return array( ··· 21 25 return (phid_get_type($this->getAuditorPHID()) == $user_type); 22 26 } 23 27 28 + public function attachCommit(PhabricatorRepositoryCommit $commit) { 29 + $this->commit = $commit; 30 + return $this; 31 + } 32 + 33 + public function getCommit() { 34 + return $this->assertAttached($this->commit); 35 + } 36 + 37 + 38 + /* -( PhabricatorPolicyInterface )----------------------------------------- */ 39 + 40 + 41 + public function getCapabilities() { 42 + return array( 43 + PhabricatorPolicyCapability::CAN_VIEW, 44 + ); 45 + } 46 + 47 + public function getPolicy($capability) { 48 + return $this->getCommit()->getPolicy($capability); 49 + } 50 + 51 + public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { 52 + return $this->getCommit()->hasAutomaticCapability($capability, $viewer); 53 + } 54 + 55 + public function describeAutomaticCapability($capability) { 56 + return pht( 57 + 'This audit is attached to a commit, and inherits its policies.'); 58 + } 24 59 }
+29 -3
src/applications/repository/storage/PhabricatorRepositoryCommit.php
··· 28 28 const IMPORTED_CLOSEABLE = 1024; 29 29 30 30 private $commitData = self::ATTACHABLE; 31 - private $audits; 31 + private $audits = self::ATTACHABLE; 32 32 private $repository = self::ATTACHABLE; 33 33 private $customFields = self::ATTACHABLE; 34 34 ··· 91 91 } 92 92 93 93 public function attachAudits(array $audits) { 94 - assert_instances_of($audits, 'PhabricatorAuditComment'); 94 + assert_instances_of($audits, 'PhabricatorRepositoryAuditRequest'); 95 95 $this->audits = $audits; 96 96 return $this; 97 97 } 98 98 99 99 public function getAudits() { 100 - return $this->audits; 100 + return $this->assertAttached($this->audits); 101 + } 102 + 103 + public function getAuthorityAudits( 104 + PhabricatorUser $user, 105 + array $authority_phids) { 106 + 107 + $authority = array_fill_keys($authority_phids, true); 108 + $audits = $this->getAudits(); 109 + $authority_audits = array(); 110 + foreach ($audits as $audit) { 111 + $has_authority = !empty($authority[$audit->getAuditorPHID()]); 112 + if ($has_authority) { 113 + $commit_author = $this->getAuthorPHID(); 114 + 115 + // You don't have authority over package and project audits on your 116 + // own commits. 117 + 118 + $auditor_is_user = ($audit->getAuditorPHID() == $user->getPHID()); 119 + $user_is_author = ($commit_author == $user->getPHID()); 120 + 121 + if ($auditor_is_user || !$user_is_author) { 122 + $authority_audits[$audit->getID()] = $audit; 123 + } 124 + } 125 + } 126 + return $authority_audits; 101 127 } 102 128 103 129 public function save() {