@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 PhrictionEditController
4 extends PhrictionController {
5
6 public function handleRequest(AphrontRequest $request) {
7 $viewer = $request->getViewer();
8 $id = $request->getURIData('id');
9
10 $max_version = null;
11 if ($id) {
12 $is_new = false;
13 $document = id(new PhrictionDocumentQuery())
14 ->setViewer($viewer)
15 ->withIDs(array($id))
16 ->needContent(true)
17 ->requireCapabilities(
18 array(
19 PhabricatorPolicyCapability::CAN_VIEW,
20 PhabricatorPolicyCapability::CAN_EDIT,
21 ))
22 ->executeOne();
23 if (!$document) {
24 return new Aphront404Response();
25 }
26
27 $max_version = $document->getMaxVersion();
28
29 $revert = $request->getInt('revert');
30 if ($revert) {
31 $content = id(new PhrictionContentQuery())
32 ->setViewer($viewer)
33 ->withDocumentPHIDs(array($document->getPHID()))
34 ->withVersions(array($revert))
35 ->executeOne();
36 if (!$content) {
37 return new Aphront404Response();
38 }
39 } else {
40 $content = id(new PhrictionContentQuery())
41 ->setViewer($viewer)
42 ->withDocumentPHIDs(array($document->getPHID()))
43 ->setLimit(1)
44 ->executeOne();
45 }
46 } else {
47 $slug = $request->getStr('slug');
48 $slug = PhabricatorSlug::normalize($slug);
49 if (!$slug) {
50 return new Aphront404Response();
51 }
52
53 $document = id(new PhrictionDocumentQuery())
54 ->setViewer($viewer)
55 ->withSlugs(array($slug))
56 ->needContent(true)
57 ->executeOne();
58
59 if ($document) {
60 $content = id(new PhrictionContentQuery())
61 ->setViewer($viewer)
62 ->withDocumentPHIDs(array($document->getPHID()))
63 ->setLimit(1)
64 ->executeOne();
65
66 $max_version = $document->getMaxVersion();
67 $is_new = false;
68 } else {
69 $document = PhrictionDocument::initializeNewDocument($viewer, $slug);
70 $content = $document->getContent();
71 $is_new = true;
72 }
73 }
74
75 require_celerity_resource('phriction-document-css');
76
77 $e_title = true;
78 $e_content = true;
79 $validation_exception = null;
80 $notes = null;
81 $title = $content->getTitle();
82 $overwrite = false;
83 $v_cc = PhabricatorSubscribersQuery::loadSubscribersForPHID(
84 $document->getPHID());
85
86 if ($is_new) {
87 $v_projects = array();
88 } else {
89 $v_projects = PhabricatorEdgeQuery::loadDestinationPHIDs(
90 $document->getPHID(),
91 PhabricatorProjectObjectHasProjectEdgeType::EDGECONST);
92 $v_projects = array_reverse($v_projects);
93 }
94
95 $v_space = $document->getSpacePHID();
96
97 $content_text = $content->getContent();
98 $is_draft_mode = ($document->getContent()->getVersion() != $max_version);
99
100 $default_view = $document->getViewPolicy();
101 $default_edit = $document->getEditPolicy();
102 $default_space = $document->getSpacePHID();
103
104 if ($request->isFormPost()) {
105 if ($is_new) {
106 $save_as_draft = false;
107 } else {
108 $save_as_draft = ($is_draft_mode || $request->getExists('draft'));
109 }
110
111 $title = $request->getStr('title');
112 $content_text = $request->getStr('content');
113 $notes = $request->getStr('description');
114 $max_version = $request->getInt('contentVersion');
115 $v_view = $request->getStr('viewPolicy');
116 $v_edit = $request->getStr('editPolicy');
117 $v_cc = $request->getArr('cc');
118 $v_projects = $request->getArr('projects');
119 $v_space = $request->getStr('spacePHID');
120
121 if ($save_as_draft) {
122 $edit_type = PhrictionDocumentDraftTransaction::TRANSACTIONTYPE;
123 } else {
124 $edit_type = PhrictionDocumentContentTransaction::TRANSACTIONTYPE;
125 }
126
127 $xactions = array();
128
129 if ($is_new) {
130 $xactions[] = id(new PhrictionTransaction())
131 ->setTransactionType(PhabricatorTransactions::TYPE_CREATE);
132 }
133
134 $xactions[] = id(new PhrictionTransaction())
135 ->setTransactionType(PhrictionDocumentTitleTransaction::TRANSACTIONTYPE)
136 ->setNewValue($title);
137 $content_xaction = id(new PhrictionTransaction())
138 ->setTransactionType($edit_type)
139 ->setNewValue($content_text);
140
141 $content_metadata = $request->getStr('content_metadata');
142 if ($content_metadata) {
143 $content_metadata = phutil_json_decode($content_metadata);
144 $attached_file_phids = idx(
145 $content_metadata,
146 'attachedFilePHIDs',
147 array());
148
149 if ($attached_file_phids) {
150 $metadata_object = array(
151 'remarkup.control' => array(
152 'attachedFilePHIDs' => $attached_file_phids,
153 ),
154 );
155
156 $content_xaction->setMetadata($metadata_object);
157 }
158 }
159
160 $xactions[] = $content_xaction;
161
162 $xactions[] = id(new PhrictionTransaction())
163 ->setTransactionType(PhabricatorTransactions::TYPE_VIEW_POLICY)
164 ->setNewValue($v_view)
165 ->setIsDefaultTransaction($is_new && ($v_view === $default_view));
166 $xactions[] = id(new PhrictionTransaction())
167 ->setTransactionType(PhabricatorTransactions::TYPE_EDIT_POLICY)
168 ->setNewValue($v_edit)
169 ->setIsDefaultTransaction($is_new && ($v_edit === $default_edit));
170 $xactions[] = id(new PhrictionTransaction())
171 ->setTransactionType(PhabricatorTransactions::TYPE_SPACE)
172 ->setNewValue($v_space)
173 ->setIsDefaultTransaction($is_new && ($v_space === $default_space));
174 $xactions[] = id(new PhrictionTransaction())
175 ->setTransactionType(PhabricatorTransactions::TYPE_SUBSCRIBERS)
176 ->setNewValue(array('=' => $v_cc));
177
178 $proj_edge_type = PhabricatorProjectObjectHasProjectEdgeType::EDGECONST;
179 $xactions[] = id(new PhrictionTransaction())
180 ->setTransactionType(PhabricatorTransactions::TYPE_EDGE)
181 ->setMetadataValue('edge:type', $proj_edge_type)
182 ->setNewValue(array('=' => array_fuse($v_projects)));
183
184 $editor = id(new PhrictionTransactionEditor())
185 ->setActor($viewer)
186 ->setContentSourceFromRequest($request)
187 ->setContinueOnNoEffect(true)
188 ->setDescription($notes)
189 ->setProcessContentVersionError(!$request->getBool('overwrite'))
190 ->setContentVersion($max_version);
191
192 try {
193 $editor->applyTransactions($document, $xactions);
194
195 $uri = PhrictionDocument::getSlugURI($document->getSlug());
196 $uri = new PhutilURI($uri);
197
198 // If the user clicked "Save as Draft", take them to the draft, not
199 // to the current published page.
200 if ($save_as_draft) {
201 $uri = $uri->alter('v', $document->getMaxVersion());
202 }
203
204 return id(new AphrontRedirectResponse())->setURI($uri);
205 } catch (PhabricatorApplicationTransactionValidationException $ex) {
206 $validation_exception = $ex;
207 $e_title = nonempty(
208 $ex->getShortMessage(
209 PhrictionDocumentTitleTransaction::TRANSACTIONTYPE),
210 true);
211 $e_content = nonempty(
212 $ex->getShortMessage(
213 PhrictionDocumentContentTransaction::TRANSACTIONTYPE),
214 true);
215
216 // if we're not supposed to process the content version error, then
217 // overwrite that content...!
218 if (!$editor->getProcessContentVersionError()) {
219 $overwrite = true;
220 }
221
222 $document->setViewPolicy($v_view);
223 $document->setEditPolicy($v_edit);
224 $document->setSpacePHID($v_space);
225 }
226 }
227
228 if ($document->getID()) {
229 $page_title = pht('Edit Document: %s', $content->getTitle());
230 if ($overwrite) {
231 $submit_button = pht('Overwrite Changes');
232 } else {
233 $submit_button = pht('Save and Publish');
234 }
235 } else {
236 $submit_button = pht('Create Document');
237 $page_title = pht('Create Document');
238 }
239
240 $uri = $document->getSlug();
241 $uri = PhrictionDocument::getSlugURI($uri);
242 $uri = PhabricatorEnv::getProductionURI($uri);
243
244 $cancel_uri = PhrictionDocument::getSlugURI($document->getSlug());
245
246 $policies = id(new PhabricatorPolicyQuery())
247 ->setViewer($viewer)
248 ->setObject($document)
249 ->execute();
250 $view_capability = PhabricatorPolicyCapability::CAN_VIEW;
251 $edit_capability = PhabricatorPolicyCapability::CAN_EDIT;
252
253 $form = id(new AphrontFormView())
254 ->setUser($viewer)
255 ->addHiddenInput('slug', $document->getSlug())
256 ->addHiddenInput('contentVersion', $max_version)
257 ->addHiddenInput('overwrite', $overwrite)
258 ->appendChild(
259 id(new AphrontFormTextControl())
260 ->setLabel(pht('Title'))
261 ->setValue($title)
262 ->setError($e_title)
263 ->setName('title'))
264 ->appendChild(
265 id(new AphrontFormStaticControl())
266 ->setLabel(pht('URI'))
267 ->setValue($uri))
268 ->appendChild(
269 id(new PhabricatorRemarkupControl())
270 ->setLabel(pht('Content'))
271 ->setValue($content_text)
272 ->setError($e_content)
273 ->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_TALL)
274 ->setName('content')
275 ->setID('document-textarea')
276 ->setUser($viewer))
277 ->appendControl(
278 id(new AphrontFormTokenizerControl())
279 ->setLabel(pht('Project Tags'))
280 ->setName('projects')
281 ->setValue($v_projects)
282 ->setDatasource(new PhabricatorProjectDatasource()))
283 ->appendControl(
284 id(new AphrontFormTokenizerControl())
285 ->setLabel(pht('Subscribers'))
286 ->setName('cc')
287 ->setValue($v_cc)
288 ->setUser($viewer)
289 ->setDatasource(new PhabricatorMetaMTAMailableDatasource()))
290 ->appendChild(
291 id(new AphrontFormPolicyControl())
292 ->setViewer($viewer)
293 ->setName('viewPolicy')
294 ->setSpacePHID($v_space)
295 ->setPolicyObject($document)
296 ->setCapability($view_capability)
297 ->setPolicies($policies))
298 ->appendChild(
299 id(new AphrontFormPolicyControl())
300 ->setName('editPolicy')
301 ->setPolicyObject($document)
302 ->setCapability($edit_capability)
303 ->setPolicies($policies))
304 ->appendChild(
305 id(new AphrontFormTextControl())
306 ->setLabel(pht('Edit Notes'))
307 ->setValue($notes)
308 ->setError(null)
309 ->setName('description'));
310
311 if ($is_draft_mode) {
312 $form->appendControl(
313 id(new AphrontFormSubmitControl())
314 ->addCancelButton($cancel_uri)
315 ->setValue(pht('Save Draft')));
316 } else {
317 $submit = new AphrontFormSubmitControl();
318
319 if (!$is_new) {
320 $draft_button = id(new PHUIButtonView())
321 ->setTag('input')
322 ->setName('draft')
323 ->setText(pht('Save as Draft'))
324 ->setColor(PHUIButtonView::GREEN);
325 $submit->addButton($draft_button);
326 }
327
328 $submit
329 ->addCancelButton($cancel_uri)
330 ->setValue($submit_button);
331
332 $form->appendControl($submit);
333 }
334
335 $form_box = id(new PHUIObjectBoxView())
336 ->setHeaderText($page_title)
337 ->setValidationException($validation_exception)
338 ->setBackground(PHUIObjectBoxView::WHITE_CONFIG)
339 ->setForm($form);
340
341 $preview_uri = '/phriction/preview/';
342 $preview_uri = new PhutilURI(
343 $preview_uri,
344 array(
345 'slug' => $document->getSlug(),
346 ));
347 $preview_uri = phutil_string_cast($preview_uri);
348
349 $preview = id(new PHUIRemarkupPreviewPanel())
350 ->setHeader($content->getTitle())
351 ->setPreviewURI($preview_uri)
352 ->setControlID('document-textarea')
353 ->setPreviewType(PHUIRemarkupPreviewPanel::DOCUMENT);
354
355 $crumbs = $this->buildApplicationCrumbs();
356 if ($document->getID()) {
357 $crumbs->addTextCrumb(
358 $content->getTitle(),
359 PhrictionDocument::getSlugURI($document->getSlug()));
360 $crumbs->addTextCrumb(pht('Edit'));
361 } else {
362 $crumbs->addTextCrumb(pht('Create'));
363 }
364 $crumbs->setBorder(true);
365
366 $view = id(new PHUITwoColumnView())
367 ->setFooter(
368 array(
369 $form_box,
370 $preview,
371 ));
372
373 return $this->newPage()
374 ->setTitle($page_title)
375 ->setCrumbs($crumbs)
376 ->appendChild($view);
377 }
378
379}