@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 upstream/main 367 lines 11 kB view raw
1<?php 2 3final class PhamePostViewController 4 extends PhameLiveController { 5 6 public function handleRequest(AphrontRequest $request) { 7 $response = $this->setupLiveEnvironment(); 8 if ($response) { 9 return $response; 10 } 11 12 $viewer = $request->getViewer(); 13 $moved = $request->getStr('moved'); 14 15 $post = $this->getPost(); 16 $blog = $this->getBlog(); 17 18 $is_live = $this->getIsLive(); 19 $is_external = $this->getIsExternal(); 20 21 $header = id(new PHUIHeaderView()) 22 ->addClass('phame-header-bar') 23 ->setUser($viewer); 24 25 $hero = $this->buildPhamePostHeader($post); 26 27 if (!$is_external && $viewer->isLoggedIn()) { 28 $actions = $this->renderActions($post); 29 $header->setPolicyObject($post); 30 $header->setActionList($actions); 31 } 32 33 $document = id(new PHUIDocumentView()) 34 ->setHeader($header); 35 36 if ($moved) { 37 $document->appendChild( 38 id(new PHUIInfoView()) 39 ->setSeverity(PHUIInfoView::SEVERITY_NOTICE) 40 ->appendChild(pht('Post moved successfully.'))); 41 } 42 43 if ($post->isDraft()) { 44 $document->appendChild( 45 id(new PHUIInfoView()) 46 ->setSeverity(PHUIInfoView::SEVERITY_NOTICE) 47 ->setTitle(pht('Draft Post')) 48 ->appendChild( 49 pht( 50 'This is a draft, and is only visible to you and other users '. 51 'who can edit %s. Use "Publish" to publish this post.', 52 $viewer->renderHandle($post->getBlogPHID())))); 53 } 54 55 if ($post->isArchived()) { 56 $document->appendChild( 57 id(new PHUIInfoView()) 58 ->setSeverity(PHUIInfoView::SEVERITY_ERROR) 59 ->setTitle(pht('Archived Post')) 60 ->appendChild( 61 pht( 62 'This post has been archived, and is only visible to you and '. 63 'other users who can edit %s.', 64 $viewer->renderHandle($post->getBlogPHID())))); 65 } 66 67 if (!$post->getBlog()) { 68 $document->appendChild( 69 id(new PHUIInfoView()) 70 ->setSeverity(PHUIInfoView::SEVERITY_WARNING) 71 ->setTitle(pht('Not On A Blog')) 72 ->appendChild( 73 pht('This post is not associated with a blog (the blog may have '. 74 'been deleted). Use "Move Post" to move it to a new blog.'))); 75 } 76 77 $engine = id(new PhabricatorMarkupEngine()) 78 ->setViewer($viewer) 79 ->addObject($post, PhamePost::MARKUP_FIELD_BODY) 80 ->process(); 81 82 $document->appendChild( 83 phutil_tag( 84 'div', 85 array( 86 'class' => 'phabricator-remarkup', 87 ), 88 $engine->getOutput($post, PhamePost::MARKUP_FIELD_BODY))); 89 90 $blogger = id(new PhabricatorPeopleQuery()) 91 ->setViewer($viewer) 92 ->withPHIDs(array($post->getBloggerPHID())) 93 ->needProfileImage(true) 94 ->executeOne(); 95 $blogger_profile = $blogger->loadUserProfile(); 96 97 98 $author_uri = '/p/'.$blogger->getUsername().'/'; 99 $author_uri = PhabricatorEnv::getURI($author_uri); 100 101 $author = phutil_tag( 102 'a', 103 array( 104 'href' => $author_uri, 105 ), 106 $blogger->getUsername()); 107 108 $date = phabricator_datetime($post->getDatePublished(), $viewer); 109 if ($post->isDraft()) { 110 $subtitle = pht('Unpublished draft by %s.', $author); 111 } else if ($post->isArchived()) { 112 $subtitle = pht('Archived post by %s.', $author); 113 } else { 114 $subtitle = pht('Written by %s on %s.', $author, $date); 115 } 116 117 $user_icon = $blogger_profile->getIcon(); 118 $user_icon = PhabricatorPeopleIconSet::getIconIcon($user_icon); 119 $user_icon = id(new PHUIIconView())->setIcon($user_icon); 120 121 $about = id(new PhameDescriptionView()) 122 ->setTitle($subtitle) 123 ->setDescription( 124 array( 125 $user_icon, 126 ' ', 127 $blogger_profile->getDisplayTitle(), 128 )) 129 ->setImage($blogger->getProfileImageURI()) 130 ->setImageHref($author_uri); 131 132 $monogram = $post->getMonogram(); 133 $timeline = $this->buildTransactionTimeline( 134 $post, 135 id(new PhamePostTransactionQuery()) 136 ->withTransactionTypes(array(PhabricatorTransactions::TYPE_COMMENT))); 137 $timeline->setQuoteRef($monogram); 138 139 if ($is_external || !$viewer->isLoggedIn()) { 140 $add_comment = null; 141 } else { 142 $add_comment = $this->buildCommentForm($post, $timeline); 143 $add_comment = phutil_tag_div('mlb mlt phame-comment-view', $add_comment); 144 } 145 146 $timeline = phutil_tag_div('phui-document-view-pro-box', $timeline); 147 148 list($prev, $next) = $this->loadAdjacentPosts($post); 149 150 $properties = id(new PHUIPropertyListView()) 151 ->setUser($viewer) 152 ->setObject($post); 153 154 $is_live = $this->getIsLive(); 155 $is_external = $this->getIsExternal(); 156 $next_view = new PhameNextPostView(); 157 if ($next) { 158 $next_view->setNext($next->getTitle(), 159 $next->getBestURI($is_live, $is_external)); 160 } 161 if ($prev) { 162 $next_view->setPrevious($prev->getTitle(), 163 $prev->getBestURI($is_live, $is_external)); 164 } 165 166 $monogram = $post->getMonogram(); 167 168 $document->setFoot($next_view); 169 $crumbs = $this->buildApplicationCrumbs(); 170 $properties = phutil_tag_div('phui-document-view-pro-box', $properties); 171 172 // Public viewers like search engines will not see the monogram 173 $title = $viewer->isLoggedIn() 174 ? pht('%s %s', $monogram, $post->getTitle()) 175 : $post->getTitle(); 176 177 $page = $this->newPage() 178 ->setTitle($title) 179 ->setPageObjectPHIDs(array($post->getPHID())) 180 ->setCrumbs($crumbs) 181 ->appendChild( 182 array( 183 $hero, 184 $document, 185 $about, 186 $properties, 187 $timeline, 188 $add_comment, 189 )); 190 191 if ($is_live) { 192 $page 193 ->setShowChrome(false) 194 ->setShowFooter(false); 195 } 196 197 return $page; 198 } 199 200 private function renderActions(PhamePost $post) { 201 $viewer = $this->getViewer(); 202 203 $actions = id(new PhabricatorActionListView()) 204 ->setObject($post) 205 ->setUser($viewer); 206 207 $can_edit = PhabricatorPolicyFilter::hasCapability( 208 $viewer, 209 $post, 210 PhabricatorPolicyCapability::CAN_EDIT); 211 212 $id = $post->getID(); 213 214 $actions->addAction( 215 id(new PhabricatorActionView()) 216 ->setIcon('fa-pencil') 217 ->setHref($this->getApplicationURI('post/edit/'.$id.'/')) 218 ->setName(pht('Edit Post')) 219 ->setDisabled(!$can_edit)); 220 221 $actions->addAction( 222 id(new PhabricatorActionView()) 223 ->setIcon('fa-camera-retro') 224 ->setHref($this->getApplicationURI('post/header/'.$id.'/')) 225 ->setName(pht('Edit Header Image')) 226 ->setDisabled(!$can_edit)); 227 228 $actions->addAction( 229 id(new PhabricatorActionView()) 230 ->setIcon('fa-arrows') 231 ->setHref($this->getApplicationURI('post/move/'.$id.'/')) 232 ->setName(pht('Move Post')) 233 ->setDisabled(!$can_edit) 234 ->setWorkflow(true)); 235 236 $actions->addAction( 237 id(new PhabricatorActionView()) 238 ->setIcon('fa-history') 239 ->setHref($this->getApplicationURI('post/history/'.$id.'/')) 240 ->setName(pht('View History'))); 241 242 if ($post->isDraft()) { 243 $actions->addAction( 244 id(new PhabricatorActionView()) 245 ->setIcon('fa-eye') 246 ->setHref($this->getApplicationURI('post/publish/'.$id.'/')) 247 ->setName(pht('Publish')) 248 ->setDisabled(!$can_edit) 249 ->setWorkflow(true)); 250 $actions->addAction( 251 id(new PhabricatorActionView()) 252 ->setIcon('fa-ban') 253 ->setHref($this->getApplicationURI('post/archive/'.$id.'/')) 254 ->setName(pht('Archive')) 255 ->setDisabled(!$can_edit) 256 ->setWorkflow(true)); 257 } else if ($post->isArchived()) { 258 $actions->addAction( 259 id(new PhabricatorActionView()) 260 ->setIcon('fa-eye') 261 ->setHref($this->getApplicationURI('post/publish/'.$id.'/')) 262 ->setName(pht('Publish')) 263 ->setDisabled(!$can_edit) 264 ->setWorkflow(true)); 265 } else { 266 $actions->addAction( 267 id(new PhabricatorActionView()) 268 ->setIcon('fa-eye-slash') 269 ->setHref($this->getApplicationURI('post/unpublish/'.$id.'/')) 270 ->setName(pht('Unpublish')) 271 ->setDisabled(!$can_edit) 272 ->setWorkflow(true)); 273 $actions->addAction( 274 id(new PhabricatorActionView()) 275 ->setIcon('fa-ban') 276 ->setHref($this->getApplicationURI('post/archive/'.$id.'/')) 277 ->setName(pht('Archive')) 278 ->setDisabled(!$can_edit) 279 ->setWorkflow(true)); 280 } 281 282 if ($post->isDraft()) { 283 $live_name = pht('Preview'); 284 } else { 285 $live_name = pht('View Live'); 286 } 287 288 if (!$post->isArchived()) { 289 $actions->addAction( 290 id(new PhabricatorActionView()) 291 ->setUser($viewer) 292 ->setIcon('fa-globe') 293 ->setHref($post->getLiveURI()) 294 ->setName($live_name)); 295 } 296 297 return $actions; 298 } 299 300 private function buildCommentForm(PhamePost $post, $timeline) { 301 $viewer = $this->getViewer(); 302 303 $box = id(new PhamePostEditEngine()) 304 ->setViewer($viewer) 305 ->buildEditEngineCommentView($post) 306 ->setTransactionTimeline($timeline); 307 308 return phutil_tag_div('phui-document-view-pro-box', $box); 309 } 310 311 private function loadAdjacentPosts(PhamePost $post) { 312 $viewer = $this->getViewer(); 313 314 $pager = id(new AphrontCursorPagerView()) 315 ->setPageSize(1); 316 317 $prev_pager = id(clone $pager) 318 ->setAfterID($post->getID()); 319 320 $next_pager = id(clone $pager) 321 ->setBeforeID($post->getID()); 322 323 $query = id(new PhamePostQuery()) 324 ->setViewer($viewer) 325 ->withVisibility(array(PhameConstants::VISIBILITY_PUBLISHED)) 326 ->withBlogPHIDs(array($post->getBlog()->getPHID())) 327 ->setLimit(1); 328 329 $prev = id(clone $query) 330 ->executeWithCursorPager($prev_pager); 331 332 $next = id(clone $query) 333 ->executeWithCursorPager($next_pager); 334 335 return array(head($prev), head($next)); 336 } 337 338 private function buildPhamePostHeader( 339 PhamePost $post) { 340 341 $image = null; 342 if ($post->getHeaderImagePHID()) { 343 $image = phutil_tag( 344 'div', 345 array( 346 'class' => 'phame-header-hero', 347 ), 348 phutil_tag( 349 'img', 350 array( 351 'src' => $post->getHeaderImageURI(), 352 'class' => 'phame-header-image', 353 ))); 354 } 355 356 $title = phutil_tag_div('phame-header-title', $post->getTitle()); 357 $subtitle = null; 358 if ($post->getSubtitle()) { 359 $subtitle = phutil_tag_div('phame-header-subtitle', $post->getSubtitle()); 360 } 361 362 return phutil_tag_div( 363 'phame-mega-header', array($image, $title, $subtitle)); 364 365 } 366 367}