PhrictionEditController.php 11.9 KB
Newer Older
1 2
<?php

3
final class PhrictionEditController
4 5
  extends PhrictionController {

6 7 8
  public function handleRequest(AphrontRequest $request) {
    $viewer = $request->getViewer();
    $id = $request->getURIData('id');
9

10
    $max_version = null;
11
    if ($id) {
12
      $is_new = false;
13
      $document = id(new PhrictionDocumentQuery())
14 15
        ->setViewer($viewer)
        ->withIDs(array($id))
16
        ->needContent(true)
17 18 19 20 21 22
        ->requireCapabilities(
          array(
            PhabricatorPolicyCapability::CAN_VIEW,
            PhabricatorPolicyCapability::CAN_EDIT,
          ))
        ->executeOne();
23 24 25
      if (!$document) {
        return new Aphront404Response();
      }
epriestley's avatar
epriestley committed
26

27
      $max_version = $document->getMaxVersion();
28

epriestley's avatar
epriestley committed
29 30
      $revert = $request->getInt('revert');
      if ($revert) {
31 32 33 34 35
        $content = id(new PhrictionContentQuery())
          ->setViewer($viewer)
          ->withDocumentPHIDs(array($document->getPHID()))
          ->withVersions(array($revert))
          ->executeOne();
epriestley's avatar
epriestley committed
36 37 38 39
        if (!$content) {
          return new Aphront404Response();
        }
      } else {
40 41 42 43 44
        $content = id(new PhrictionContentQuery())
          ->setViewer($viewer)
          ->withDocumentPHIDs(array($document->getPHID()))
          ->setLimit(1)
          ->executeOne();
epriestley's avatar
epriestley committed
45
      }
46 47
    } else {
      $slug = $request->getStr('slug');
Bob Trahan's avatar
Bob Trahan committed
48
      $slug = PhabricatorSlug::normalize($slug);
49 50 51 52
      if (!$slug) {
        return new Aphront404Response();
      }

53
      $document = id(new PhrictionDocumentQuery())
54
        ->setViewer($viewer)
55 56 57
        ->withSlugs(array($slug))
        ->needContent(true)
        ->executeOne();
58 59

      if ($document) {
60 61 62 63 64 65 66
        $content = id(new PhrictionContentQuery())
          ->setViewer($viewer)
          ->withDocumentPHIDs(array($document->getPHID()))
          ->setLimit(1)
          ->executeOne();

        $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 76
    require_celerity_resource('phriction-document-css');

77
    $e_title = true;
78 79
    $e_content = true;
    $validation_exception = null;
80
    $notes = null;
81 82
    $title = $content->getTitle();
    $overwrite = false;
Chad Little's avatar
Chad Little committed
83 84
    $v_cc = PhabricatorSubscribersQuery::loadSubscribersForPHID(
      $document->getPHID());
85

86 87 88 89 90 91 92 93 94
    if ($is_new) {
      $v_projects = array();
    } else {
      $v_projects = PhabricatorEdgeQuery::loadDestinationPHIDs(
        $document->getPHID(),
        PhabricatorProjectObjectHasProjectEdgeType::EDGECONST);
      $v_projects = array_reverse($v_projects);
    }

epriestley's avatar
epriestley committed
95 96
    $v_space = $document->getSpacePHID();

97
    $content_text = $content->getContent();
98
    $is_draft_mode = ($document->getContent()->getVersion() != $max_version);
99

100 101 102 103
    $default_view = $document->getViewPolicy();
    $default_edit = $document->getEditPolicy();
    $default_space = $document->getSpacePHID();

104
    if ($request->isFormPost()) {
105 106 107 108 109
      if ($is_new) {
        $save_as_draft = false;
      } else {
        $save_as_draft = ($is_draft_mode || $request->getExists('draft'));
      }
110

111
      $title = $request->getStr('title');
112
      $content_text = $request->getStr('content');
113
      $notes = $request->getStr('description');
114
      $max_version = $request->getInt('contentVersion');
115 116
      $v_view = $request->getStr('viewPolicy');
      $v_edit = $request->getStr('editPolicy');
117 118
      $v_cc = $request->getArr('cc');
      $v_projects = $request->getArr('projects');
epriestley's avatar
epriestley committed
119
      $v_space = $request->getStr('spacePHID');
120

121 122 123 124 125 126
      if ($save_as_draft) {
        $edit_type = PhrictionDocumentDraftTransaction::TRANSACTIONTYPE;
      } else {
        $edit_type = PhrictionDocumentContentTransaction::TRANSACTIONTYPE;
      }

127
      $xactions = array();
128

129 130 131 132 133
      if ($is_new) {
        $xactions[] = id(new PhrictionTransaction())
          ->setTransactionType(PhabricatorTransactions::TYPE_CREATE);
      }

134
      $xactions[] = id(new PhrictionTransaction())
135
        ->setTransactionType(PhrictionDocumentTitleTransaction::TRANSACTIONTYPE)
136 137
        ->setNewValue($title);
      $xactions[] = id(new PhrictionTransaction())
138
        ->setTransactionType($edit_type)
139
        ->setNewValue($content_text);
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
      if ($v_view) {
        $xactions[] = id(new PhrictionTransaction())
          ->setTransactionType(PhabricatorTransactions::TYPE_VIEW_POLICY)
          ->setNewValue($v_view)
          ->setIsDefaultTransaction($is_new && ($v_view === $default_view));
      }
      if ($v_edit) {
        $xactions[] = id(new PhrictionTransaction())
          ->setTransactionType(PhabricatorTransactions::TYPE_EDIT_POLICY)
          ->setNewValue($v_edit)
          ->setIsDefaultTransaction($is_new && ($v_edit === $default_edit));
      }
      if ($v_space) {
        $xactions[] = id(new PhrictionTransaction())
          ->setTransactionType(PhabricatorTransactions::TYPE_SPACE)
          ->setNewValue($v_space)
          ->setIsDefaultTransaction($is_new && ($v_space === $default_space));
      }
Chad Little's avatar
Chad Little committed
158 159 160
      $xactions[] = id(new PhrictionTransaction())
        ->setTransactionType(PhabricatorTransactions::TYPE_SUBSCRIBERS)
        ->setNewValue(array('=' => $v_cc));
161

162 163 164 165 166 167
      $proj_edge_type = PhabricatorProjectObjectHasProjectEdgeType::EDGECONST;
      $xactions[] = id(new PhrictionTransaction())
        ->setTransactionType(PhabricatorTransactions::TYPE_EDGE)
        ->setMetadataValue('edge:type', $proj_edge_type)
        ->setNewValue(array('=' => array_fuse($v_projects)));

168
      $editor = id(new PhrictionTransactionEditor())
169
        ->setActor($viewer)
170 171 172 173
        ->setContentSourceFromRequest($request)
        ->setContinueOnNoEffect(true)
        ->setDescription($notes)
        ->setProcessContentVersionError(!$request->getBool('overwrite'))
174
        ->setContentVersion($max_version);
175 176 177

      try {
        $editor->applyTransactions($document, $xactions);
178

179
        $uri = PhrictionDocument::getSlugURI($document->getSlug());
180 181 182 183 184 185 186 187
        $uri = new PhutilURI($uri);

        // If the user clicked "Save as Draft", take them to the draft, not
        // to the current published page.
        if ($save_as_draft) {
          $uri = $uri->alter('v', $document->getMaxVersion());
        }

188
        return id(new AphrontRedirectResponse())->setURI($uri);
189 190
      } catch (PhabricatorApplicationTransactionValidationException $ex) {
        $validation_exception = $ex;
191
        $e_title = nonempty(
192 193
          $ex->getShortMessage(
            PhrictionDocumentTitleTransaction::TRANSACTIONTYPE),
194 195
          true);
        $e_content = nonempty(
196 197
          $ex->getShortMessage(
            PhrictionDocumentContentTransaction::TRANSACTIONTYPE),
198
          true);
199 200 201 202 203 204 205

        // if we're not supposed to process the content version error, then
        // overwrite that content...!
        if (!$editor->getProcessContentVersionError()) {
          $overwrite = true;
        }

206 207
        $document->setViewPolicy($v_view);
        $document->setEditPolicy($v_edit);
epriestley's avatar
epriestley committed
208
        $document->setSpacePHID($v_space);
209 210 211 212
      }
    }

    if ($document->getID()) {
213
      $page_title = pht('Edit Document: %s', $content->getTitle());
214 215 216
      if ($overwrite) {
        $submit_button = pht('Overwrite Changes');
      } else {
217
        $submit_button = pht('Save and Publish');
218
      }
219
    } else {
Chad Little's avatar
Chad Little committed
220
      $submit_button = pht('Create Document');
221
      $page_title = pht('Create Document');
222 223 224 225 226 227
    }

    $uri = $document->getSlug();
    $uri = PhrictionDocument::getSlugURI($uri);
    $uri = PhabricatorEnv::getProductionURI($uri);

228 229
    $cancel_uri = PhrictionDocument::getSlugURI($document->getSlug());

230
    $policies = id(new PhabricatorPolicyQuery())
231
      ->setViewer($viewer)
232 233 234 235
      ->setObject($document)
      ->execute();
    $view_capability = PhabricatorPolicyCapability::CAN_VIEW;
    $edit_capability = PhabricatorPolicyCapability::CAN_EDIT;
236

237
    $form = id(new AphrontFormView())
238
      ->setUser($viewer)
239
      ->addHiddenInput('slug', $document->getSlug())
240
      ->addHiddenInput('contentVersion', $max_version)
241
      ->addHiddenInput('overwrite', $overwrite)
242 243
      ->appendChild(
        id(new AphrontFormTextControl())
Chad Little's avatar
Chad Little committed
244
          ->setLabel(pht('Title'))
245
          ->setValue($title)
246 247 248 249
          ->setError($e_title)
          ->setName('title'))
      ->appendChild(
        id(new AphrontFormStaticControl())
Chad Little's avatar
Chad Little committed
250
          ->setLabel(pht('URI'))
251 252
          ->setValue($uri))
      ->appendChild(
253
        id(new PhabricatorRemarkupControl())
Chad Little's avatar
Chad Little committed
254
          ->setLabel(pht('Content'))
255
          ->setValue($content_text)
256
          ->setError($e_content)
257
          ->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_TALL)
258
          ->setName('content')
259
          ->setID('document-textarea')
260
          ->setUser($viewer))
261 262
      ->appendControl(
        id(new AphrontFormTokenizerControl())
Luke081515's avatar
Luke081515 committed
263
          ->setLabel(pht('Tags'))
264 265 266
          ->setName('projects')
          ->setValue($v_projects)
          ->setDatasource(new PhabricatorProjectDatasource()))
Chad Little's avatar
Chad Little committed
267 268 269 270 271 272 273
      ->appendControl(
        id(new AphrontFormTokenizerControl())
          ->setLabel(pht('Subscribers'))
          ->setName('cc')
          ->setValue($v_cc)
          ->setUser($viewer)
          ->setDatasource(new PhabricatorMetaMTAMailableDatasource()))
274 275
      ->appendChild(
        id(new AphrontFormTextControl())
Chad Little's avatar
Chad Little committed
276
          ->setLabel(pht('Edit Notes'))
277
          ->setValue($notes)
278
          ->setError(null)
279 280
          ->setName('description'));

281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304
    // We don't allow the view/edit policy to be changed on the root document;
    // partly because doing so is bad, but mostly because it's in a space
    // which is only visible to admins. As some people changing it would not
    // be able to actually view the space that it was in, any edit would reset
    // the space back to whatever sorted first in the list that the user had
    // access to, and then no-one can edit the wiki.
    if ($document->getSlug() != '/' || $viewer->getIsAdmin()) {
      $form
        ->appendChild(
          id(new AphrontFormPolicyControl())
            ->setViewer($viewer)
            ->setName('viewPolicy')
            ->setSpacePHID($v_space)
            ->setPolicyObject($document)
            ->setCapability($view_capability)
            ->setPolicies($policies))
        ->appendChild(
          id(new AphrontFormPolicyControl())
            ->setName('editPolicy')
            ->setPolicyObject($document)
            ->setCapability($edit_capability)
            ->setPolicies($policies));
    }

305 306
    if ($is_draft_mode) {
      $form->appendControl(
307
        id(new AphrontFormSubmitControl())
308 309 310
          ->addCancelButton($cancel_uri)
          ->setValue(pht('Save Draft')));
    } else {
311 312 313 314 315 316 317 318 319 320
      $submit = id(new AphrontFormSubmitControl());

      if (!$is_new) {
        $draft_button = id(new PHUIButtonView())
          ->setTag('input')
          ->setName('draft')
          ->setText(pht('Save as Draft'))
          ->setColor(PHUIButtonView::GREEN);
        $submit->addButton($draft_button);
      }
321

322 323 324 325 326
      $submit
        ->addCancelButton($cancel_uri)
        ->setValue($submit_button);

      $form->appendControl($submit);
327
    }
328

329
    $form_box = id(new PHUIObjectBoxView())
330
      ->setHeaderText($page_title)
331
      ->setValidationException($validation_exception)
332
      ->setBackground(PHUIObjectBoxView::WHITE_CONFIG)
Chad Little's avatar
Chad Little committed
333
      ->setForm($form);
334

335
    $preview = id(new PHUIRemarkupPreviewPanel())
336
      ->setHeader($content->getTitle())
337
      ->setPreviewURI('/phriction/preview/'.$document->getSlug())
338
      ->setControlID('document-textarea')
339
      ->setPreviewType(PHUIRemarkupPreviewPanel::DOCUMENT);
340

341 342
    $crumbs = $this->buildApplicationCrumbs();
    if ($document->getID()) {
343 344 345 346
      $crumbs->addTextCrumb(
        $content->getTitle(),
        PhrictionDocument::getSlugURI($document->getSlug()));
      $crumbs->addTextCrumb(pht('Edit'));
347
    } else {
348
      $crumbs->addTextCrumb(pht('Create'));
349
    }
350
    $crumbs->setBorder(true);
351

352
    $view = id(new PHUITwoColumnView())
353 354 355 356 357
      ->setFooter(
        array(
          $form_box,
          $preview,
        ));
358 359 360 361 362

    return $this->newPage()
      ->setTitle($page_title)
      ->setCrumbs($crumbs)
      ->appendChild($view);
363 364 365
  }

}