public function handleRequest(AphrontRequest $request) { $viewer = $this->getViewer(); $document = id(new PhrictionDocumentQuery())->setViewer($viewer)->withIDs(array($request->getURIData('id')))->needContent(true)->requireCapabilities(array(PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT))->executeOne(); if (!$document) { return new Aphront404Response(); } $slug = $document->getSlug(); $cancel_uri = PhrictionDocument::getSlugURI($slug); $v_slug = $slug; $e_slug = null; $v_note = ''; $validation_exception = null; if ($request->isFormPost()) { $v_note = $request->getStr('description'); $v_slug = $request->getStr('slug'); $normal_slug = PhabricatorSlug::normalize($v_slug); // If what the user typed isn't what we're actually using, warn them // about it. if (strlen($v_slug)) { $no_slash_slug = rtrim($normal_slug, '/'); if ($normal_slug !== $v_slug && $no_slash_slug !== $v_slug) { return $this->newDialog()->setTitle(pht('Adjust Path'))->appendParagraph(pht('The path you entered (%s) is not a valid wiki document ' . 'path. Paths may not contain spaces or special characters.', phutil_tag('strong', array(), $v_slug)))->appendParagraph(pht('Would you like to use the path %s instead?', phutil_tag('strong', array(), $normal_slug)))->addHiddenInput('slug', $normal_slug)->addHiddenInput('description', $v_note)->addCancelButton($cancel_uri)->addSubmitButton(pht('Accept Path')); } } $editor = id(new PhrictionTransactionEditor())->setActor($viewer)->setContentSourceFromRequest($request)->setContinueOnNoEffect(true)->setDescription($v_note); $xactions = array(); $xactions[] = id(new PhrictionTransaction())->setTransactionType(PhrictionTransaction::TYPE_MOVE_TO)->setNewValue($document); $target_document = id(new PhrictionDocumentQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->withSlugs(array($normal_slug))->needContent(true)->requireCapabilities(array(PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT))->executeOne(); if (!$target_document) { $target_document = PhrictionDocument::initializeNewDocument($viewer, $v_slug); } try { $editor->applyTransactions($target_document, $xactions); $redir_uri = PhrictionDocument::getSlugURI($target_document->getSlug()); return id(new AphrontRedirectResponse())->setURI($redir_uri); } catch (PhabricatorApplicationTransactionValidationException $ex) { $validation_exception = $ex; $e_slug = $ex->getShortMessage(PhrictionTransaction::TYPE_MOVE_TO); } } $form = id(new AphrontFormView())->setUser($viewer)->appendChild(id(new AphrontFormStaticControl())->setLabel(pht('Title'))->setValue($document->getContent()->getTitle()))->appendChild(id(new AphrontFormTextControl())->setLabel(pht('Current Path'))->setDisabled(true)->setValue($slug))->appendChild(id(new AphrontFormTextControl())->setLabel(pht('New Path'))->setValue($v_slug)->setError($e_slug)->setName('slug'))->appendChild(id(new AphrontFormTextControl())->setLabel(pht('Edit Notes'))->setValue($v_note)->setName('description')); return $this->newDialog()->setTitle(pht('Move Document'))->setValidationException($validation_exception)->appendForm($form)->addSubmitButton(pht('Move Document'))->addCancelButton($cancel_uri); }
protected function execute(ConduitAPIRequest $request) { $slug = $request->getValue('slug'); if (!strlen($slug)) { throw new Exception(pht('No such document.')); } $doc = id(new PhrictionDocumentQuery())->setViewer($request->getUser())->withSlugs(array(PhabricatorSlug::normalize($slug)))->requireCapabilities(array(PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT))->executeOne(); if ($doc) { throw new Exception(pht('Document already exists!')); } $doc = PhrictionDocument::initializeNewDocument($request->getUser(), $slug); $xactions = array(); $xactions[] = id(new PhrictionTransaction())->setTransactionType(PhrictionTransaction::TYPE_TITLE)->setNewValue($request->getValue('title')); $xactions[] = id(new PhrictionTransaction())->setTransactionType(PhrictionTransaction::TYPE_CONTENT)->setNewValue($request->getValue('content')); $editor = id(new PhrictionTransactionEditor())->setActor($request->getUser())->setContentSourceFromConduitRequest($request)->setContinueOnNoEffect(true)->setDescription($request->getValue('description')); try { $editor->applyTransactions($doc, $xactions); } catch (PhabricatorApplicationTransactionValidationException $ex) { // TODO - some magical hotness via T5873 throw $ex; } return $this->buildDocumentInfoDictionary($doc); }
public function handleRequest(AphrontRequest $request) { $viewer = $request->getViewer(); $id = $request->getURIData('id'); $current_version = null; if ($id) { $document = id(new PhrictionDocumentQuery())->setViewer($viewer)->withIDs(array($id))->needContent(true)->requireCapabilities(array(PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT))->executeOne(); if (!$document) { return new Aphront404Response(); } $current_version = $document->getContent()->getVersion(); $revert = $request->getInt('revert'); if ($revert) { $content = id(new PhrictionContent())->loadOneWhere('documentID = %d AND version = %d', $document->getID(), $revert); if (!$content) { return new Aphront404Response(); } } else { $content = $document->getContent(); } } else { $slug = $request->getStr('slug'); $slug = PhabricatorSlug::normalize($slug); if (!$slug) { return new Aphront404Response(); } $document = id(new PhrictionDocumentQuery())->setViewer($viewer)->withSlugs(array($slug))->needContent(true)->executeOne(); if ($document) { $content = $document->getContent(); $current_version = $content->getVersion(); } else { $document = PhrictionDocument::initializeNewDocument($viewer, $slug); $content = $document->getContent(); } } if ($request->getBool('nodraft')) { $draft = null; $draft_key = null; } else { if ($document->getPHID()) { $draft_key = $document->getPHID() . ':' . $content->getVersion(); } else { $draft_key = 'phriction:' . $content->getSlug(); } $draft = id(new PhabricatorDraft())->loadOneWhere('authorPHID = %s AND draftKey = %s', $viewer->getPHID(), $draft_key); } if ($draft && strlen($draft->getDraft()) && $draft->getDraft() != $content->getContent()) { $content_text = $draft->getDraft(); $discard = phutil_tag('a', array('href' => $request->getRequestURI()->alter('nodraft', true)), pht('discard this draft')); $draft_note = new PHUIInfoView(); $draft_note->setSeverity(PHUIInfoView::SEVERITY_NOTICE); $draft_note->setTitle(pht('Recovered Draft')); $draft_note->appendChild(hsprintf('<p>%s</p>', pht('Showing a saved draft of your edits, you can %s.', $discard))); } else { $content_text = $content->getContent(); $draft_note = null; } require_celerity_resource('phriction-document-css'); $e_title = true; $e_content = true; $validation_exception = null; $notes = null; $title = $content->getTitle(); $overwrite = false; $v_cc = PhabricatorSubscribersQuery::loadSubscribersForPHID($document->getPHID()); if ($request->isFormPost()) { $title = $request->getStr('title'); $content_text = $request->getStr('content'); $notes = $request->getStr('description'); $current_version = $request->getInt('contentVersion'); $v_view = $request->getStr('viewPolicy'); $v_edit = $request->getStr('editPolicy'); $v_cc = $request->getArr('cc'); $xactions = array(); $xactions[] = id(new PhrictionTransaction())->setTransactionType(PhrictionTransaction::TYPE_TITLE)->setNewValue($title); $xactions[] = id(new PhrictionTransaction())->setTransactionType(PhrictionTransaction::TYPE_CONTENT)->setNewValue($content_text); $xactions[] = id(new PhrictionTransaction())->setTransactionType(PhabricatorTransactions::TYPE_VIEW_POLICY)->setNewValue($v_view); $xactions[] = id(new PhrictionTransaction())->setTransactionType(PhabricatorTransactions::TYPE_EDIT_POLICY)->setNewValue($v_edit); $xactions[] = id(new PhrictionTransaction())->setTransactionType(PhabricatorTransactions::TYPE_SUBSCRIBERS)->setNewValue(array('=' => $v_cc)); $editor = id(new PhrictionTransactionEditor())->setActor($viewer)->setContentSourceFromRequest($request)->setContinueOnNoEffect(true)->setDescription($notes)->setProcessContentVersionError(!$request->getBool('overwrite'))->setContentVersion($current_version); try { $editor->applyTransactions($document, $xactions); if ($draft) { $draft->delete(); } $uri = PhrictionDocument::getSlugURI($document->getSlug()); return id(new AphrontRedirectResponse())->setURI($uri); } catch (PhabricatorApplicationTransactionValidationException $ex) { $validation_exception = $ex; $e_title = nonempty($ex->getShortMessage(PhrictionTransaction::TYPE_TITLE), true); $e_content = nonempty($ex->getShortMessage(PhrictionTransaction::TYPE_CONTENT), true); // if we're not supposed to process the content version error, then // overwrite that content...! if (!$editor->getProcessContentVersionError()) { $overwrite = true; } $document->setViewPolicy($v_view); $document->setEditPolicy($v_edit); } } if ($document->getID()) { $panel_header = pht('Edit Document: %s', $content->getTitle()); $page_title = pht('Edit Document'); $header_icon = 'fa-pencil'; if ($overwrite) { $submit_button = pht('Overwrite Changes'); } else { $submit_button = pht('Save Changes'); } } else { $panel_header = pht('Create New Phriction Document'); $submit_button = pht('Create Document'); $page_title = pht('Create Document'); $header_icon = 'fa-plus-square'; } $uri = $document->getSlug(); $uri = PhrictionDocument::getSlugURI($uri); $uri = PhabricatorEnv::getProductionURI($uri); $cancel_uri = PhrictionDocument::getSlugURI($document->getSlug()); $policies = id(new PhabricatorPolicyQuery())->setViewer($viewer)->setObject($document)->execute(); $view_capability = PhabricatorPolicyCapability::CAN_VIEW; $edit_capability = PhabricatorPolicyCapability::CAN_EDIT; $form = id(new AphrontFormView())->setUser($viewer)->addHiddenInput('slug', $document->getSlug())->addHiddenInput('nodraft', $request->getBool('nodraft'))->addHiddenInput('contentVersion', $current_version)->addHiddenInput('overwrite', $overwrite)->appendChild(id(new AphrontFormTextControl())->setLabel(pht('Title'))->setValue($title)->setError($e_title)->setName('title'))->appendChild(id(new AphrontFormStaticControl())->setLabel(pht('URI'))->setValue($uri))->appendChild(id(new PhabricatorRemarkupControl())->setLabel(pht('Content'))->setValue($content_text)->setError($e_content)->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_TALL)->setName('content')->setID('document-textarea')->setUser($viewer))->appendControl(id(new AphrontFormTokenizerControl())->setLabel(pht('Subscribers'))->setName('cc')->setValue($v_cc)->setUser($viewer)->setDatasource(new PhabricatorMetaMTAMailableDatasource()))->appendChild(id(new AphrontFormPolicyControl())->setName('viewPolicy')->setPolicyObject($document)->setCapability($view_capability)->setPolicies($policies)->setCaption($document->describeAutomaticCapability($view_capability)))->appendChild(id(new AphrontFormPolicyControl())->setName('editPolicy')->setPolicyObject($document)->setCapability($edit_capability)->setPolicies($policies)->setCaption($document->describeAutomaticCapability($edit_capability)))->appendChild(id(new AphrontFormTextControl())->setLabel(pht('Edit Notes'))->setValue($notes)->setError(null)->setName('description'))->appendChild(id(new AphrontFormSubmitControl())->addCancelButton($cancel_uri)->setValue($submit_button)); $form_box = id(new PHUIObjectBoxView())->setHeaderText(pht('Document'))->setValidationException($validation_exception)->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)->setForm($form); $preview = id(new PHUIRemarkupPreviewPanel())->setHeader($content->getTitle())->setPreviewURI('/phriction/preview/' . $document->getSlug())->setControlID('document-textarea')->setPreviewType(PHUIRemarkupPreviewPanel::DOCUMENT); $crumbs = $this->buildApplicationCrumbs(); if ($document->getID()) { $crumbs->addTextCrumb($content->getTitle(), PhrictionDocument::getSlugURI($document->getSlug())); $crumbs->addTextCrumb(pht('Edit')); } else { $crumbs->addTextCrumb(pht('Create')); } $crumbs->setBorder(true); $header = id(new PHUIHeaderView())->setHeader($panel_header)->setHeaderIcon($header_icon); $view = id(new PHUITwoColumnView())->setHeader($header)->setFooter(array($draft_note, $form_box, $preview)); return $this->newPage()->setTitle($page_title)->setCrumbs($crumbs)->appendChild($view); }
public function handleRequest(AphrontRequest $request) { $viewer = $request->getViewer(); $this->slug = $request->getURIData('slug'); $slug = PhabricatorSlug::normalize($this->slug); if ($slug != $this->slug) { $uri = PhrictionDocument::getSlugURI($slug); // Canonicalize pages to their one true URI. return id(new AphrontRedirectResponse())->setURI($uri); } require_celerity_resource('phriction-document-css'); $document = id(new PhrictionDocumentQuery())->setViewer($viewer)->withSlugs(array($slug))->executeOne(); $version_note = null; $core_content = ''; $move_notice = ''; $properties = null; $content = null; if (!$document) { $document = PhrictionDocument::initializeNewDocument($viewer, $slug); $create_uri = '/phriction/edit/?slug=' . $slug; $notice = new PHUIInfoView(); $notice->setSeverity(PHUIInfoView::SEVERITY_WARNING); $notice->setTitle(pht('No content here!')); $notice->appendChild(pht('No document found at %s. You can <strong>' . '<a href="%s">create a new document here</a></strong>.', phutil_tag('tt', array(), $slug), $create_uri)); $core_content = $notice; $page_title = pht('Page Not Found'); } else { $version = $request->getInt('v'); if ($version) { $content = id(new PhrictionContent())->loadOneWhere('documentID = %d AND version = %d', $document->getID(), $version); if (!$content) { return new Aphront404Response(); } if ($content->getID() != $document->getContentID()) { $vdate = phabricator_datetime($content->getDateCreated(), $viewer); $version_note = new PHUIInfoView(); $version_note->setSeverity(PHUIInfoView::SEVERITY_NOTICE); $version_note->appendChild(pht('You are viewing an older version of this document, as it ' . 'appeared on %s.', $vdate)); } } else { $content = id(new PhrictionContent())->load($document->getContentID()); } $page_title = $content->getTitle(); $properties = $this->buildPropertyListView($document, $content, $slug); $doc_status = $document->getStatus(); $current_status = $content->getChangeType(); if ($current_status == PhrictionChangeType::CHANGE_EDIT || $current_status == PhrictionChangeType::CHANGE_MOVE_HERE) { $core_content = $content->renderContent($viewer); } else { if ($current_status == PhrictionChangeType::CHANGE_DELETE) { $notice = new PHUIInfoView(); $notice->setSeverity(PHUIInfoView::SEVERITY_NOTICE); $notice->setTitle(pht('Document Deleted')); $notice->appendChild(pht('This document has been deleted. You can edit it to put new ' . 'content here, or use history to revert to an earlier version.')); $core_content = $notice->render(); } else { if ($current_status == PhrictionChangeType::CHANGE_STUB) { $notice = new PHUIInfoView(); $notice->setSeverity(PHUIInfoView::SEVERITY_NOTICE); $notice->setTitle(pht('Empty Document')); $notice->appendChild(pht('This document is empty. You can edit it to put some proper ' . 'content here.')); $core_content = $notice->render(); } else { if ($current_status == PhrictionChangeType::CHANGE_MOVE_AWAY) { $new_doc_id = $content->getChangeRef(); $slug_uri = null; // If the new document exists and the viewer can see it, provide a link // to it. Otherwise, render a generic message. $new_docs = id(new PhrictionDocumentQuery())->setViewer($viewer)->withIDs(array($new_doc_id))->execute(); if ($new_docs) { $new_doc = head($new_docs); $slug_uri = PhrictionDocument::getSlugURI($new_doc->getSlug()); } $notice = id(new PHUIInfoView())->setSeverity(PHUIInfoView::SEVERITY_NOTICE); if ($slug_uri) { $notice->appendChild(phutil_tag('p', array(), pht('This document has been moved to %s. You can edit it to put ' . 'new content here, or use history to revert to an earlier ' . 'version.', phutil_tag('a', array('href' => $slug_uri), $slug_uri)))); } else { $notice->appendChild(phutil_tag('p', array(), pht('This document has been moved. You can edit it to put new ' . 'contne here, or use history to revert to an earlier ' . 'version.'))); } $core_content = $notice->render(); } else { throw new Exception(pht("Unknown document status '%s'!", $doc_status)); } } } } $move_notice = null; if ($current_status == PhrictionChangeType::CHANGE_MOVE_HERE) { $from_doc_id = $content->getChangeRef(); $slug_uri = null; // If the old document exists and is visible, provide a link to it. $from_docs = id(new PhrictionDocumentQuery())->setViewer($viewer)->withIDs(array($from_doc_id))->execute(); if ($from_docs) { $from_doc = head($from_docs); $slug_uri = PhrictionDocument::getSlugURI($from_doc->getSlug()); } $move_notice = id(new PHUIInfoView())->setSeverity(PHUIInfoView::SEVERITY_NOTICE); if ($slug_uri) { $move_notice->appendChild(pht('This document was moved from %s.', phutil_tag('a', array('href' => $slug_uri), $slug_uri))); } else { // Render this for consistency, even though it's a bit silly. $move_notice->appendChild(pht('This document was moved from elsewhere.')); } } } $children = $this->renderDocumentChildren($slug); $actions = $this->buildActionView($viewer, $document); $crumbs = $this->buildApplicationCrumbs(); $crumbs->setBorder(true); $crumb_views = $this->renderBreadcrumbs($slug); foreach ($crumb_views as $view) { $crumbs->addCrumb($view); } $action_button = id(new PHUIButtonView())->setTag('a')->setText(pht('Actions'))->setHref('#')->setIconFont('fa-bars')->addClass('phui-mobile-menu')->setDropdownMenu($actions); $header = id(new PHUIHeaderView())->setUser($viewer)->setPolicyObject($document)->setHeader($page_title)->addActionLink($action_button); if ($content) { $header->setEpoch($content->getDateCreated()); } $prop_list = null; if ($properties) { $prop_list = new PHUIPropertyGroupView(); $prop_list->addPropertyList($properties); } $page_content = id(new PHUIDocumentView())->setHeader($header)->appendChild(array($prop_list, $version_note, $move_notice, $core_content)); return $this->buildApplicationPage(array($crumbs->render(), $page_content, $children), array('pageObjects' => array($document->getPHID()), 'title' => $page_title)); }
protected function applyFinalEffects(PhabricatorLiskDAO $object, array $xactions) { $save_content = false; foreach ($xactions as $xaction) { switch ($xaction->getTransactionType()) { case PhrictionTransaction::TYPE_TITLE: case PhrictionTransaction::TYPE_CONTENT: case PhrictionTransaction::TYPE_DELETE: case PhrictionTransaction::TYPE_MOVE_AWAY: case PhrictionTransaction::TYPE_MOVE_TO: $save_content = true; break; default: break; } } if ($save_content) { $content = $this->getNewContent(); $content->setDocumentID($object->getID()); $content->save(); $object->setContentID($content->getID()); $object->save(); $object->attachContent($content); } if ($this->getIsNewObject() && !$this->getSkipAncestorCheck()) { // Stub out empty parent documents if they don't exist $ancestral_slugs = PhabricatorSlug::getAncestry($object->getSlug()); if ($ancestral_slugs) { $ancestors = id(new PhrictionDocumentQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->withSlugs($ancestral_slugs)->needContent(true)->execute(); $ancestors = mpull($ancestors, null, 'getSlug'); $stub_type = PhrictionChangeType::CHANGE_STUB; foreach ($ancestral_slugs as $slug) { $ancestor_doc = idx($ancestors, $slug); // We check for change type to prevent near-infinite recursion if (!$ancestor_doc && $content->getChangeType() != $stub_type) { $ancestor_doc = PhrictionDocument::initializeNewDocument($this->getActor(), $slug); $stub_xactions = array(); $stub_xactions[] = id(new PhrictionTransaction())->setTransactionType(PhrictionTransaction::TYPE_TITLE)->setNewValue(PhabricatorSlug::getDefaultTitle($slug))->setMetadataValue('stub:create:phid', $object->getPHID()); $stub_xactions[] = id(new PhrictionTransaction())->setTransactionType(PhrictionTransaction::TYPE_CONTENT)->setNewValue('')->setMetadataValue('stub:create:phid', $object->getPHID()); $stub_xactions[] = id(new PhrictionTransaction())->setTransactionType(PhabricatorTransactions::TYPE_VIEW_POLICY)->setNewValue($object->getViewPolicy()); $stub_xactions[] = id(new PhrictionTransaction())->setTransactionType(PhabricatorTransactions::TYPE_EDIT_POLICY)->setNewValue($object->getEditPolicy()); $sub_editor = id(new PhrictionTransactionEditor())->setActor($this->getActor())->setContentSource($this->getContentSource())->setContinueOnNoEffect($this->getContinueOnNoEffect())->setSkipAncestorCheck(true)->setDescription(pht('Empty Parent Document'))->applyTransactions($ancestor_doc, $stub_xactions); } } } } if ($this->moveAwayDocument !== null) { $move_away_xactions = array(); $move_away_xactions[] = id(new PhrictionTransaction())->setTransactionType(PhrictionTransaction::TYPE_MOVE_AWAY)->setNewValue($object); $sub_editor = id(new PhrictionTransactionEditor())->setActor($this->getActor())->setContentSource($this->getContentSource())->setContinueOnNoEffect($this->getContinueOnNoEffect())->setDescription($this->getDescription())->applyTransactions($this->moveAwayDocument, $move_away_xactions); } // Compute the content diff URI for the publishing phase. foreach ($xactions as $xaction) { switch ($xaction->getTransactionType()) { case PhrictionTransaction::TYPE_CONTENT: $uri = id(new PhutilURI('/phriction/diff/' . $object->getID() . '/'))->alter('l', $this->getOldContent()->getVersion())->alter('r', $this->getNewContent()->getVersion()); $this->contentDiffURI = (string) $uri; break 2; default: break; } } return $xactions; }