@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 229 lines 6.8 kB view raw
1<?php 2 3final class PhabricatorProjectMembersViewController 4 extends PhabricatorProjectController { 5 6 public function handleRequest(AphrontRequest $request) { 7 $viewer = $request->getViewer(); 8 $id = $request->getURIData('id'); 9 10 $project = id(new PhabricatorProjectQuery()) 11 ->setViewer($viewer) 12 ->withIDs(array($id)) 13 ->needMembers(true) 14 ->needWatchers(true) 15 ->needImages(true) 16 ->executeOne(); 17 if (!$project) { 18 return new Aphront404Response(); 19 } 20 21 $this->setProject($project); 22 $title = pht('Members and Watchers'); 23 $curtain = $this->buildCurtainView($project); 24 25 $member_list = id(new PhabricatorProjectMemberListView()) 26 ->setViewer($viewer) 27 ->setProject($project) 28 ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) 29 ->setUserPHIDs($project->getMemberPHIDs()) 30 ->setShowNote(true); 31 32 $watcher_list = id(new PhabricatorProjectWatcherListView()) 33 ->setViewer($viewer) 34 ->setProject($project) 35 ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) 36 ->setUserPHIDs($project->getWatcherPHIDs()) 37 ->setShowNote(true); 38 39 $nav = $this->newNavigation( 40 $project, 41 PhabricatorProject::ITEM_MEMBERS); 42 43 $crumbs = $this->buildApplicationCrumbs(); 44 $crumbs->addTextCrumb(pht('Members')); 45 $crumbs->setBorder(true); 46 47 $header = id(new PHUIHeaderView()) 48 ->setHeader($title) 49 ->setHeaderIcon('fa-group'); 50 51 require_celerity_resource('project-view-css'); 52 53 $view = id(new PHUITwoColumnView()) 54 ->setHeader($header) 55 ->setCurtain($curtain) 56 ->addClass('project-view-home') 57 ->addClass('project-view-people-home') 58 ->setMainColumn(array( 59 $member_list, 60 $watcher_list, 61 )); 62 63 return $this->newPage() 64 ->setNavigation($nav) 65 ->setCrumbs($crumbs) 66 ->setTitle(array($project->getName(), $title)) 67 ->appendChild($view); 68 } 69 70 private function buildCurtainView(PhabricatorProject $project) { 71 $viewer = $this->getViewer(); 72 $id = $project->getID(); 73 74 $curtain = $this->newCurtainView(); 75 76 $is_locked = $project->getIsMembershipLocked(); 77 78 $can_edit = PhabricatorPolicyFilter::hasCapability( 79 $viewer, 80 $project, 81 PhabricatorPolicyCapability::CAN_EDIT); 82 83 $supports_edit = $project->supportsEditMembers(); 84 85 $can_join = $supports_edit && PhabricatorPolicyFilter::hasCapability( 86 $viewer, 87 $project, 88 PhabricatorPolicyCapability::CAN_JOIN); 89 90 $can_leave = $supports_edit && (!$is_locked || $can_edit); 91 92 $viewer_phid = $viewer->getPHID(); 93 94 if (!$project->isUserMember($viewer_phid)) { 95 $curtain->addAction( 96 id(new PhabricatorActionView()) 97 ->setHref('/project/update/'.$project->getID().'/join/') 98 ->setIcon('fa-plus') 99 ->setDisabled(!$can_join) 100 ->setWorkflow(true) 101 ->setName(pht('Join Project'))); 102 } else { 103 $curtain->addAction( 104 id(new PhabricatorActionView()) 105 ->setHref('/project/update/'.$project->getID().'/leave/') 106 ->setIcon('fa-times') 107 ->setDisabled(!$can_leave) 108 ->setWorkflow(true) 109 ->setName(pht('Leave Project'))); 110 } 111 112 if (!$project->isUserWatcher($viewer->getPHID())) { 113 $curtain->addAction( 114 id(new PhabricatorActionView()) 115 ->setWorkflow(true) 116 ->setHref('/project/watch/'.$project->getID().'/') 117 ->setIcon('fa-eye') 118 ->setName(pht('Watch Project'))); 119 } else { 120 $curtain->addAction( 121 id(new PhabricatorActionView()) 122 ->setWorkflow(true) 123 ->setHref('/project/unwatch/'.$project->getID().'/') 124 ->setIcon('fa-eye-slash') 125 ->setName(pht('Unwatch Project'))); 126 } 127 128 $can_silence = $project->isUserMember($viewer_phid); 129 $is_silenced = $this->isProjectSilenced($project); 130 131 if ($is_silenced) { 132 $silence_text = pht('Enable Mail'); 133 } else { 134 $silence_text = pht('Disable Mail'); 135 } 136 137 $curtain->addAction( 138 id(new PhabricatorActionView()) 139 ->setName($silence_text) 140 ->setIcon('fa-envelope-o') 141 ->setHref("/project/silence/{$id}/") 142 ->setWorkflow(true) 143 ->setDisabled(!$can_silence)); 144 145 $can_add = $can_edit && $supports_edit; 146 147 $curtain->addAction( 148 id(new PhabricatorActionView()) 149 ->setName(pht('Add Members')) 150 ->setIcon('fa-user-plus') 151 ->setHref("/project/members/{$id}/add/") 152 ->setWorkflow(true) 153 ->setDisabled(!$can_add)); 154 155 $can_lock = $can_edit && $supports_edit && $this->hasApplicationCapability( 156 ProjectCanLockProjectsCapability::CAPABILITY); 157 158 if ($is_locked) { 159 $lock_name = pht('Unlock Project'); 160 $lock_icon = 'fa-unlock'; 161 } else { 162 $lock_name = pht('Lock Project'); 163 $lock_icon = 'fa-lock'; 164 } 165 166 $curtain->addAction( 167 id(new PhabricatorActionView()) 168 ->setName($lock_name) 169 ->setIcon($lock_icon) 170 ->setHref($this->getApplicationURI("lock/{$id}/")) 171 ->setDisabled(!$can_lock) 172 ->setWorkflow(true)); 173 174 if ($project->isMilestone()) { 175 $icon_key = PhabricatorProjectIconSet::getMilestoneIconKey(); 176 $header = PhabricatorProjectIconSet::getIconName($icon_key); 177 $note = pht( 178 'Members of the parent project are members of this project.'); 179 $show_join = false; 180 } else if ($project->getHasSubprojects()) { 181 $header = pht('Parent Project'); 182 $note = pht( 183 'Members of all subprojects are members of this project.'); 184 $show_join = false; 185 } else if ($project->getIsMembershipLocked()) { 186 $header = pht('Locked Project'); 187 $note = pht( 188 'Users with access may join this project, but may not leave.'); 189 $show_join = true; 190 } else { 191 $header = pht('Normal Project'); 192 $note = pht('Users with access may join and leave this project.'); 193 $show_join = true; 194 } 195 196 $curtain->newPanel() 197 ->setHeaderText($header) 198 ->appendChild($note); 199 200 if ($show_join) { 201 $descriptions = PhabricatorPolicyQuery::renderPolicyDescriptions( 202 $viewer, 203 $project); 204 205 $curtain->newPanel() 206 ->setHeaderText(pht('Joinable By')) 207 ->appendChild($descriptions[PhabricatorPolicyCapability::CAN_JOIN]); 208 } 209 210 return $curtain; 211 } 212 213 private function isProjectSilenced(PhabricatorProject $project) { 214 $viewer = $this->getViewer(); 215 216 $viewer_phid = $viewer->getPHID(); 217 if (!$viewer_phid) { 218 return false; 219 } 220 221 $edge_type = PhabricatorProjectSilencedEdgeType::EDGECONST; 222 $silenced = PhabricatorEdgeQuery::loadDestinationPHIDs( 223 $project->getPHID(), 224 $edge_type); 225 $silenced = array_fuse($silenced); 226 return isset($silenced[$viewer_phid]); 227 } 228 229}