@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
at recaptime-dev/main 328 lines 9.2 kB view raw
1<?php 2 3final class PhabricatorProjectProfileController 4 extends PhabricatorProjectController { 5 6 public function shouldAllowPublic() { 7 return true; 8 } 9 10 public function handleRequest(AphrontRequest $request) { 11 $response = $this->loadProject(); 12 if ($response) { 13 return $response; 14 } 15 16 $viewer = $request->getUser(); 17 $project = $this->getProject(); 18 $id = $project->getID(); 19 $picture = $project->getProfileImageURI(); 20 $icon = $project->getDisplayIconIcon(); 21 $icon_name = $project->getDisplayIconName(); 22 $tag = id(new PHUITagView()) 23 ->setIcon($icon) 24 ->setName($icon_name) 25 ->addClass('project-view-header-tag') 26 ->setType(PHUITagView::TYPE_SHADE); 27 28 $header = id(new PHUIHeaderView()) 29 ->setHeader(array($project->getDisplayName(), $tag)) 30 ->setViewer($viewer) 31 ->setPolicyObject($project) 32 ->setProfileHeader(true); 33 34 if ($project->getStatus() == PhabricatorProjectStatus::STATUS_ACTIVE) { 35 $header->setStatus('fa-check', 'bluegrey', pht('Active')); 36 } else { 37 $header->setStatus('fa-ban', 'red', pht('Archived')); 38 } 39 40 $can_edit = PhabricatorPolicyFilter::hasCapability( 41 $viewer, 42 $project, 43 PhabricatorPolicyCapability::CAN_EDIT); 44 45 if ($can_edit) { 46 $header->setImageEditURL($this->getApplicationURI("picture/{$id}/")); 47 } 48 49 $properties = $this->buildPropertyListView($project); 50 51 $watch_action = $this->renderWatchAction($project); 52 $header->addActionLink($watch_action); 53 54 $subtype = $project->newSubtypeObject(); 55 if ($subtype && $subtype->hasTagView()) { 56 $subtype_tag = $subtype->newTagView(); 57 $header->addTag($subtype_tag); 58 } 59 60 $milestone_list = $this->buildMilestoneList($project); 61 $subproject_list = $this->buildSubprojectList($project); 62 63 $member_list = id(new PhabricatorProjectMemberListView()) 64 ->setViewer($viewer) 65 ->setProject($project) 66 ->setLimit(10) 67 ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) 68 ->setUserPHIDs($project->getMemberPHIDs()); 69 70 $watcher_list = id(new PhabricatorProjectWatcherListView()) 71 ->setViewer($viewer) 72 ->setProject($project) 73 ->setLimit(10) 74 ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) 75 ->setUserPHIDs($project->getWatcherPHIDs()); 76 77 $nav = $this->newNavigation( 78 $project, 79 PhabricatorProject::ITEM_PROFILE); 80 81 $query = id(new PhabricatorFeedQuery()) 82 ->setViewer($viewer) 83 ->withFilterPHIDs(array($project->getPHID())) 84 ->setLimit(50) 85 ->setReturnPartialResultsOnOverheat(true); 86 87 $stories = $query->execute(); 88 89 $overheated_view = null; 90 $is_overheated = $query->getIsOverheated(); 91 if ($is_overheated) { 92 $overheated_message = 93 PhabricatorApplicationSearchController::newOverheatedError( 94 (bool)$stories); 95 96 $overheated_view = id(new PHUIInfoView()) 97 ->setSeverity(PHUIInfoView::SEVERITY_WARNING) 98 ->setTitle(pht('Query Overheated')) 99 ->setErrors( 100 array( 101 $overheated_message, 102 )); 103 } 104 105 $view_all = id(new PHUIButtonView()) 106 ->setTag('a') 107 ->setIcon('fa-list-ul') 108 ->setText(pht('View All')) 109 ->setHref('/feed/?projectPHIDs='.$project->getPHID()); 110 111 $feed_header = id(new PHUIHeaderView()) 112 ->setHeader(pht('Recent Activity')) 113 ->addActionLink($view_all); 114 115 $feed = $this->renderStories($stories); 116 $feed = id(new PHUIObjectBoxView()) 117 ->setHeader($feed_header) 118 ->addClass('project-view-feed') 119 ->appendChild( 120 array( 121 $overheated_view, 122 $feed, 123 )); 124 125 require_celerity_resource('project-view-css'); 126 127 $home = id(new PHUITwoColumnView()) 128 ->setHeader($header) 129 ->addClass('project-view-home') 130 ->addClass('project-view-people-home') 131 ->setMainColumn( 132 array( 133 $properties, 134 $feed, 135 )) 136 ->setSideColumn( 137 array( 138 $milestone_list, 139 $subproject_list, 140 $member_list, 141 $watcher_list, 142 )); 143 144 $crumbs = $this->buildApplicationCrumbs(); 145 $crumbs->setBorder(true); 146 147 return $this->newPage() 148 ->setNavigation($nav) 149 ->setCrumbs($crumbs) 150 ->setTitle($project->getDisplayName()) 151 ->setPageObjectPHIDs(array($project->getPHID())) 152 ->appendChild($home); 153 } 154 155 private function buildPropertyListView( 156 PhabricatorProject $project) { 157 $request = $this->getRequest(); 158 $viewer = $request->getUser(); 159 160 $view = id(new PHUIPropertyListView()) 161 ->setViewer($viewer) 162 ->setObject($project); 163 164 $field_list = PhabricatorCustomField::getObjectFields( 165 $project, 166 PhabricatorCustomField::ROLE_VIEW); 167 $field_list->appendFieldsToPropertyList($project, $viewer, $view); 168 169 if (!$view->hasAnyProperties()) { 170 return null; 171 } 172 173 $header = id(new PHUIHeaderView()) 174 ->setHeader(pht('Details')); 175 176 $view = id(new PHUIObjectBoxView()) 177 ->setHeader($header) 178 ->appendChild($view) 179 ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) 180 ->addClass('project-view-properties'); 181 182 return $view; 183 } 184 185 /** 186 * @param array<PhabricatorFeedStory> $stories 187 */ 188 private function renderStories(array $stories) { 189 assert_instances_of($stories, PhabricatorFeedStory::class); 190 191 $builder = new PhabricatorFeedBuilder($stories); 192 $builder->setUser($this->getRequest()->getUser()); 193 $builder->setShowHovercards(true); 194 $view = $builder->buildView(); 195 196 return $view; 197 } 198 199 private function renderWatchAction(PhabricatorProject $project) { 200 $viewer = $this->getViewer(); 201 $id = $project->getID(); 202 203 if (!$viewer->isLoggedIn()) { 204 $is_watcher = false; 205 $is_ancestor = false; 206 } else { 207 $viewer_phid = $viewer->getPHID(); 208 $is_watcher = $project->isUserWatcher($viewer_phid); 209 $is_ancestor = $project->isUserAncestorWatcher($viewer_phid); 210 } 211 212 if ($is_ancestor && !$is_watcher) { 213 $watch_icon = 'fa-eye'; 214 $watch_text = pht('Watching Ancestor'); 215 $watch_href = "/project/watch/{$id}/?via=profile"; 216 $watch_disabled = true; 217 } else if (!$is_watcher) { 218 $watch_icon = 'fa-eye'; 219 $watch_text = pht('Watch Project'); 220 $watch_href = "/project/watch/{$id}/?via=profile"; 221 $watch_disabled = false; 222 } else { 223 $watch_icon = 'fa-eye-slash'; 224 $watch_text = pht('Unwatch Project'); 225 $watch_href = "/project/unwatch/{$id}/?via=profile"; 226 $watch_disabled = false; 227 } 228 229 return id(new PHUIButtonView()) 230 ->setTag('a') 231 ->setWorkflow(true) 232 ->setIcon($watch_icon) 233 ->setText($watch_text) 234 ->setHref($watch_href) 235 ->setDisabled($watch_disabled); 236 } 237 238 private function buildMilestoneList(PhabricatorProject $project) { 239 if (!$project->getHasMilestones()) { 240 return null; 241 } 242 243 $viewer = $this->getViewer(); 244 $id = $project->getID(); 245 246 $milestones = id(new PhabricatorProjectQuery()) 247 ->setViewer($viewer) 248 ->withParentProjectPHIDs(array($project->getPHID())) 249 ->needImages(true) 250 ->withIsMilestone(true) 251 ->withStatuses( 252 array( 253 PhabricatorProjectStatus::STATUS_ACTIVE, 254 )) 255 ->setOrderVector(array('milestoneNumber', 'id')) 256 ->execute(); 257 if (!$milestones) { 258 return null; 259 } 260 261 $milestone_list = id(new PhabricatorProjectListView()) 262 ->setViewer($viewer) 263 ->setProjects($milestones) 264 ->renderList(); 265 266 $view_all = id(new PHUIButtonView()) 267 ->setTag('a') 268 ->setIcon('fa-list-ul') 269 ->setText(pht('View All')) 270 ->setHref("/project/subprojects/{$id}/"); 271 272 $header = id(new PHUIHeaderView()) 273 ->setHeader(pht('Milestones')) 274 ->addActionLink($view_all); 275 276 return id(new PHUIObjectBoxView()) 277 ->setHeader($header) 278 ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) 279 ->setObjectList($milestone_list); 280 } 281 282 private function buildSubprojectList(PhabricatorProject $project) { 283 if (!$project->getHasSubprojects()) { 284 return null; 285 } 286 287 $viewer = $this->getViewer(); 288 $id = $project->getID(); 289 290 $limit = 25; 291 292 $subprojects = id(new PhabricatorProjectQuery()) 293 ->setViewer($viewer) 294 ->withParentProjectPHIDs(array($project->getPHID())) 295 ->needImages(true) 296 ->withStatuses( 297 array( 298 PhabricatorProjectStatus::STATUS_ACTIVE, 299 )) 300 ->withIsMilestone(false) 301 ->setLimit($limit) 302 ->execute(); 303 if (!$subprojects) { 304 return null; 305 } 306 307 $subproject_list = id(new PhabricatorProjectListView()) 308 ->setUser($viewer) 309 ->setProjects($subprojects) 310 ->renderList(); 311 312 $view_all = id(new PHUIButtonView()) 313 ->setTag('a') 314 ->setIcon('fa-list-ul') 315 ->setText(pht('View All')) 316 ->setHref("/project/subprojects/{$id}/"); 317 318 $header = id(new PHUIHeaderView()) 319 ->setHeader(pht('Subprojects')) 320 ->addActionLink($view_all); 321 322 return id(new PHUIObjectBoxView()) 323 ->setHeader($header) 324 ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) 325 ->setObjectList($subproject_list); 326 } 327 328}