@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<?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}