public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); $document = id(new PhrictionDocumentQuery())->setViewer($user)->withIDs(array($this->id))->requireCapabilities(array(PhabricatorPolicyCapability::CAN_EDIT, PhabricatorPolicyCapability::CAN_VIEW))->executeOne(); if (!$document) { return new Aphront404Response(); } $e_text = null; $disallowed_states = array(PhrictionDocumentStatus::STATUS_DELETED => true, PhrictionDocumentStatus::STATUS_MOVED => true, PhrictionDocumentStatus::STATUS_STUB => true); if (isset($disallowed_states[$document->getStatus()])) { $e_text = pht('An already moved or deleted document can not be deleted'); } $document_uri = PhrictionDocument::getSlugURI($document->getSlug()); if (!$e_text && $request->isFormPost()) { $editor = id(PhrictionDocumentEditor::newForSlug($document->getSlug()))->setActor($user)->delete(); return id(new AphrontRedirectResponse())->setURI($document_uri); } if ($e_text) { $dialog = id(new AphrontDialogView())->setUser($user)->setTitle(pht('Can not delete document!'))->appendChild($e_text)->addCancelButton($document_uri); } else { $dialog = id(new AphrontDialogView())->setUser($user)->setTitle(pht('Delete Document?'))->appendChild(pht('Really delete this document? You can recover it later by ' . 'reverting to a previous version.'))->addSubmitButton(pht('Delete'))->addCancelButton($document_uri); } return id(new AphrontDialogResponse())->setDialog($dialog); }
protected function execute(ConduitAPIRequest $request) { $slug = $request->getValue('slug'); $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('No such document.')); } $editor = id(PhrictionDocumentEditor::newForSlug($slug))->setActor($request->getUser())->setTitle($request->getValue('title'))->setContent($request->getValue('content'))->setDescription($request->getvalue('description'))->save(); return $this->buildDocumentInfoDictionary($editor->getDocument()); }
public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); $document = id(new PhrictionDocument())->load($this->id); if (!$document) { return new Aphront404Response(); } $document_uri = PhrictionDocument::getSlugURI($document->getSlug()); if ($request->isFormPost()) { $editor = id(PhrictionDocumentEditor::newForSlug($document->getSlug()))->setUser($user)->delete(); return id(new AphrontRedirectResponse())->setURI($document_uri); } $dialog = id(new AphrontDialogView())->setUser($user)->setTitle('Delete document?')->appendChild('Really delete this document? You can recover it later by reverting ' . 'to a previous version.')->addSubmitButton('Delete')->addCancelButton($document_uri); return id(new AphrontDialogResponse())->setDialog($dialog); }
public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); if ($this->id) { $document = id(new PhrictionDocument())->load($this->id); if (!$document) { return new Aphront404Response(); } $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 = id(new PhrictionContent())->load($document->getContentID()); } } else { $slug = $request->getStr('slug'); $slug = PhabricatorSlug::normalize($slug); if (!$slug) { return new Aphront404Response(); } $document = id(new PhrictionDocument())->loadOneWhere('slug = %s', $slug); if ($document) { $content = id(new PhrictionContent())->load($document->getContentID()); } else { $document = new PhrictionDocument(); $document->setSlug($slug); $content = new PhrictionContent(); $content->setSlug($slug); $default_title = PhabricatorSlug::getDefaultTitle($slug); $content->setTitle($default_title); } } 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', $user->getPHID(), $draft_key); } require_celerity_resource('phriction-document-css'); $e_title = true; $errors = array(); if ($request->isFormPost()) { $title = $request->getStr('title'); if (!strlen($title)) { $e_title = 'Required'; $errors[] = 'Document title is required.'; } else { $e_title = null; } if (!count($errors)) { $editor = id(PhrictionDocumentEditor::newForSlug($document->getSlug()))->setUser($user)->setTitle($title)->setContent($request->getStr('content'))->setDescription($request->getStr('description')); $editor->save(); if ($draft) { $draft->delete(); } $uri = PhrictionDocument::getSlugURI($document->getSlug()); return id(new AphrontRedirectResponse())->setURI($uri); } } $error_view = null; if ($errors) { $error_view = id(new AphrontErrorView())->setTitle('Form Errors')->setErrors($errors); } if ($document->getID()) { $panel_header = 'Edit Phriction Document'; $submit_button = 'Save Changes'; $delete_button = phutil_render_tag('a', array('href' => '/phriction/delete/' . $document->getID() . '/', 'class' => 'grey button'), 'Delete Document'); } else { $panel_header = 'Create New Phriction Document'; $submit_button = 'Create Document'; $delete_button = null; } $uri = $document->getSlug(); $uri = PhrictionDocument::getSlugURI($uri); $uri = PhabricatorEnv::getProductionURI($uri); $remarkup_reference = phutil_render_tag('a', array('href' => PhabricatorEnv::getDoclink('article/Remarkup_Reference.html'), 'tabindex' => '-1', 'target' => '_blank'), 'Formatting Reference'); $cancel_uri = PhrictionDocument::getSlugURI($document->getSlug()); if ($draft && strlen($draft->getDraft()) && $draft->getDraft() != $content->getContent()) { $content_text = $draft->getDraft(); $discard = phutil_render_tag('a', array('href' => $request->getRequestURI()->alter('nodraft', true)), 'discard this draft'); $draft_note = new AphrontErrorView(); $draft_note->setSeverity(AphrontErrorView::SEVERITY_NOTICE); $draft_note->setTitle('Recovered Draft'); $draft_note->appendChild('<p>Showing a saved draft of your edits, you can ' . $discard . '.</p>'); } else { $content_text = $content->getContent(); $draft_note = null; } $form = id(new AphrontFormView())->setUser($user)->setAction($request->getRequestURI()->getPath())->addHiddenInput('slug', $document->getSlug())->addHiddenInput('nodraft', $request->getBool('nodraft'))->appendChild(id(new AphrontFormTextControl())->setLabel('Title')->setValue($content->getTitle())->setError($e_title)->setName('title'))->appendChild(id(new AphrontFormStaticControl())->setLabel('URI')->setValue($uri))->appendChild(id(new AphrontFormTextAreaControl())->setLabel('Content')->setValue($content_text)->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_TALL)->setName('content')->setID('document-textarea')->setEnableDragAndDropFileUploads(true)->setCaption($remarkup_reference))->appendChild(id(new AphrontFormTextControl())->setLabel('Edit Notes')->setValue($content->getDescription())->setError(null)->setName('description'))->appendChild(id(new AphrontFormSubmitControl())->addCancelButton($cancel_uri)->setValue($submit_button)); $panel = id(new AphrontPanelView())->setWidth(AphrontPanelView::WIDTH_WIDE)->setHeader($panel_header)->appendChild($form); if ($delete_button) { $panel->addButton($delete_button); } $preview_panel = '<div class="aphront-panel-preview aphront-panel-preview-wide"> <div class="phriction-document-preview-header"> Document Preview </div> <div id="document-preview"> <div class="aphront-panel-preview-loading-text"> Loading preview... </div> </div> </div>'; Javelin::initBehavior('phriction-document-preview', array('preview' => 'document-preview', 'textarea' => 'document-textarea', 'uri' => '/phriction/preview/?draftkey=' . $draft_key)); return $this->buildStandardPageResponse(array($draft_note, $error_view, $panel, $preview_panel), array('title' => 'Edit Document')); }
public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); if ($this->id) { $document = id(new PhrictionDocumentQuery())->setViewer($user)->withIDs(array($this->id))->requireCapabilities(array(PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT))->executeOne(); } else { $slug = PhabricatorSlug::normalize($request->getStr('slug')); if (!$slug) { return new Aphront404Response(); } $document = id(new PhrictionDocumentQuery())->setViewer($user)->withSlugs(array($slug))->requireCapabilities(array(PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT))->executeOne(); } if (!$document) { return new Aphront404Response(); } if (!isset($slug)) { $slug = $document->getSlug(); } $target_slug = PhabricatorSlug::normalize($request->getStr('new-slug', $slug)); $submit_uri = $request->getRequestURI()->getPath(); $cancel_uri = PhrictionDocument::getSlugURI($slug); $errors = array(); $error_view = null; $e_url = null; $disallowed_statuses = array(PhrictionDocumentStatus::STATUS_DELETED => true, PhrictionDocumentStatus::STATUS_MOVED => true, PhrictionDocumentStatus::STATUS_STUB => true); if (isset($disallowed_statuses[$document->getStatus()])) { $error_dialog = id(new AphrontDialogView())->setUser($user)->setTitle('Can not move page!')->appendChild(pht('An already moved or deleted document ' . 'can not be moved again.'))->addCancelButton($cancel_uri); return id(new AphrontDialogResponse())->setDialog($error_dialog); } $content = id(new PhrictionContent())->load($document->getContentID()); if ($request->isFormPost() && !count($errors)) { if (!count($errors)) { // First check if the target document exists // NOTE: We use the ominpotent user because we can't let users overwrite // documents even if they can't see them. $target_document = id(new PhrictionDocumentQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->withSlugs(array($target_slug))->executeOne(); // Considering to overwrite existing docs? Nuke this! if ($target_document && $target_document->getStatus() == PhrictionDocumentStatus::STATUS_EXISTS) { $errors[] = pht('Can not overwrite existing target document.'); $e_url = pht('Already exists.'); } } if (!count($errors)) { // I like to move it, move it! $from_editor = id(PhrictionDocumentEditor::newForSlug($slug))->setActor($user)->setTitle($content->getTitle())->setContent($content->getContent())->setDescription($content->getDescription()); $target_editor = id(PhrictionDocumentEditor::newForSlug($target_slug))->setActor($user)->setTitle($content->getTitle())->setContent($content->getContent())->setDescription($content->getDescription()); // Move it! $target_editor->moveHere($document->getID(), $document->getPHID()); // Retrieve the target doc directly from the editor // No need to load it per Sql again $target_document = $target_editor->getDocument(); $from_editor->moveAway($target_document->getID()); $redir_uri = PhrictionDocument::getSlugURI($target_document->getSlug()); return id(new AphrontRedirectResponse())->setURI($redir_uri); } } if ($errors) { $error_view = id(new AphrontErrorView())->setErrors($errors); } $form = id(new PHUIFormLayoutView())->setUser($user)->appendChild(id(new AphrontFormStaticControl())->setLabel(pht('Title'))->setValue($content->getTitle()))->appendChild(id(new AphrontFormTextControl())->setLabel(pht('New URI'))->setValue($target_slug)->setError($e_url)->setName('new-slug')->setCaption(pht('The new location of the document.')))->appendChild(id(new AphrontFormTextControl())->setLabel(pht('Edit Notes'))->setValue($content->getDescription())->setError(null)->setName('description')); $dialog = id(new AphrontDialogView())->setUser($user)->setTitle(pht('Move Document'))->appendChild($form)->setSubmitURI($submit_uri)->addSubmitButton(pht('Move Document'))->addCancelButton($cancel_uri); return id(new AphrontDialogResponse())->setDialog($dialog); }
public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); if ($this->id) { $document = id(new PhrictionDocument())->load($this->id); if (!$document) { return new Aphront404Response(); } $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 = id(new PhrictionContent())->load($document->getContentID()); } } else { $slug = $request->getStr('slug'); $slug = PhrictionDocument::normalizeSlug($slug); if (!$slug) { return new Aphront404Response(); } $document = id(new PhrictionDocument())->loadOneWhere('slug = %s', $slug); if ($document) { $content = id(new PhrictionContent())->load($document->getContentID()); } else { $document = new PhrictionDocument(); $document->setSlug($slug); $content = new PhrictionContent(); $content->setSlug($slug); $default_title = PhrictionDocument::getDefaultSlugTitle($slug); $content->setTitle($default_title); } } require_celerity_resource('phriction-document-css'); $e_title = true; $errors = array(); if ($request->isFormPost()) { $title = $request->getStr('title'); if (!strlen($title)) { $e_title = 'Required'; $errors[] = 'Document title is required.'; } else { $e_title = null; } if (!count($errors)) { $editor = id(PhrictionDocumentEditor::newForSlug($document->getSlug()))->setUser($user)->setTitle($title)->setContent($request->getStr('content'))->setDescription($request->getStr('description')); $editor->save(); $uri = PhrictionDocument::getSlugURI($document->getSlug()); return id(new AphrontRedirectResponse())->setURI($uri); } } $error_view = null; if ($errors) { $error_view = id(new AphrontErrorView())->setTitle('Form Errors')->setErrors($errors); } if ($document->getID()) { $panel_header = 'Edit Phriction Document'; $submit_button = 'Save Changes'; } else { $panel_header = 'Create New Phriction Document'; $submit_button = 'Create Document'; } $uri = $document->getSlug(); $uri = PhrictionDocument::getSlugURI($uri); $uri = PhabricatorEnv::getProductionURI($uri); $remarkup_reference = phutil_render_tag('a', array('href' => PhabricatorEnv::getDoclink('article/Remarkup_Reference.html')), 'Formatting Reference'); $cancel_uri = PhrictionDocument::getSlugURI($document->getSlug()); $form = id(new AphrontFormView())->setUser($user)->setAction($request->getRequestURI()->getPath())->addHiddenInput('slug', $document->getSlug())->appendChild(id(new AphrontFormTextControl())->setLabel('Title')->setValue($content->getTitle())->setError($e_title)->setName('title'))->appendChild(id(new AphrontFormTextControl())->setLabel('Description')->setValue($content->getDescription())->setError(null)->setName('description'))->appendChild(id(new AphrontFormStaticControl())->setLabel('URI')->setValue($uri))->appendChild(id(new AphrontFormTextAreaControl())->setLabel('Content')->setValue($content->getContent())->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_TALL)->setName('content')->setID('document-textarea')->setEnableDragAndDropFileUploads(true)->setCaption($remarkup_reference))->appendChild(id(new AphrontFormSubmitControl())->addCancelButton($cancel_uri)->setValue($submit_button)); $panel = id(new AphrontPanelView())->setWidth(AphrontPanelView::WIDTH_WIDE)->setHeader($panel_header)->appendChild($form); $preview_panel = '<div class="aphront-panel-preview aphront-panel-preview-wide"> <div class="phriction-document-preview-header"> Document Preview </div> <div id="document-preview"> <div class="aphront-panel-preview-loading-text"> Loading preview... </div> </div> </div>'; Javelin::initBehavior('phriction-document-preview', array('preview' => 'document-preview', 'textarea' => 'document-textarea', 'uri' => '/phriction/preview/')); return $this->buildStandardPageResponse(array($error_view, $panel, $preview_panel), array('title' => 'Edit Document')); }
public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); $current_version = null; if ($this->id) { $document = id(new PhrictionDocumentQuery())->setViewer($user)->withIDs(array($this->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($user)->withSlugs(array($slug))->needContent(true)->executeOne(); if ($document) { $content = $document->getContent(); $current_version = $content->getVersion(); } else { if (PhrictionDocument::isProjectSlug($slug)) { $project = id(new PhabricatorProjectQuery())->setViewer($user)->withPhrictionSlugs(array(PhrictionDocument::getProjectSlugIdentifier($slug)))->executeOne(); if (!$project) { return new Aphront404Response(); } } $document = new PhrictionDocument(); $document->setSlug($slug); $content = new PhrictionContent(); $content->setSlug($slug); $default_title = PhabricatorSlug::getDefaultTitle($slug); $content->setTitle($default_title); } } 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', $user->getPHID(), $draft_key); } require_celerity_resource('phriction-document-css'); $e_title = true; $notes = null; $errors = array(); if ($request->isFormPost()) { $overwrite = $request->getBool('overwrite'); if (!$overwrite) { $edit_version = $request->getStr('contentVersion'); if ($edit_version != $current_version) { $dialog = $this->newDialog()->setTitle(pht('Edit Conflict!'))->appendParagraph(pht('Another user made changes to this document after you began ' . 'editing it. Do you want to overwrite their changes?'))->appendParagraph(pht('If you choose to overwrite their changes, you should review ' . 'the document edit history to see what you overwrote, and ' . 'then make another edit to merge the changes if necessary.'))->addSubmitButton(pht('Overwrite Changes'))->addCancelButton($request->getRequestURI()); $dialog->addHiddenInput('overwrite', 'true'); foreach ($request->getPassthroughRequestData() as $key => $value) { $dialog->addHiddenInput($key, $value); } return $dialog; } } $title = $request->getStr('title'); $notes = $request->getStr('description'); if (!strlen($title)) { $e_title = pht('Required'); $errors[] = pht('Document title is required.'); } else { $e_title = null; } if ($document->getID()) { if ($content->getTitle() == $title && $content->getContent() == $request->getStr('content')) { $dialog = new AphrontDialogView(); $dialog->setUser($user); $dialog->setTitle(pht('No Edits')); $dialog->appendChild(phutil_tag('p', array(), pht('You did not make any changes to the document.'))); $dialog->addCancelButton($request->getRequestURI()); return id(new AphrontDialogResponse())->setDialog($dialog); } } else { if (!strlen($request->getStr('content'))) { // We trigger this only for new pages. For existing pages, deleting // all the content counts as deleting the page. $dialog = new AphrontDialogView(); $dialog->setUser($user); $dialog->setTitle(pht('Empty Page')); $dialog->appendChild(phutil_tag('p', array(), pht('You can not create an empty document.'))); $dialog->addCancelButton($request->getRequestURI()); return id(new AphrontDialogResponse())->setDialog($dialog); } } if (!count($errors)) { $editor = id(PhrictionDocumentEditor::newForSlug($document->getSlug()))->setActor($user)->setTitle($title)->setContent($request->getStr('content'))->setDescription($notes); $editor->save(); if ($draft) { $draft->delete(); } $uri = PhrictionDocument::getSlugURI($document->getSlug()); return id(new AphrontRedirectResponse())->setURI($uri); } } if ($document->getID()) { $panel_header = pht('Edit Phriction Document'); $submit_button = pht('Save Changes'); } else { $panel_header = pht('Create New Phriction Document'); $submit_button = pht('Create Document'); } $uri = $document->getSlug(); $uri = PhrictionDocument::getSlugURI($uri); $uri = PhabricatorEnv::getProductionURI($uri); $cancel_uri = PhrictionDocument::getSlugURI($document->getSlug()); 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 AphrontErrorView(); $draft_note->setSeverity(AphrontErrorView::SEVERITY_NOTICE); $draft_note->setTitle('Recovered Draft'); $draft_note->appendChild(hsprintf('<p>Showing a saved draft of your edits, you can %s.</p>', $discard)); } else { $content_text = $content->getContent(); $draft_note = null; } $form = id(new AphrontFormView())->setUser($user)->setWorkflow(true)->setAction($request->getRequestURI()->getPath())->addHiddenInput('slug', $document->getSlug())->addHiddenInput('nodraft', $request->getBool('nodraft'))->addHiddenInput('contentVersion', $current_version)->appendChild(id(new AphrontFormTextControl())->setLabel(pht('Title'))->setValue($content->getTitle())->setError($e_title)->setName('title'))->appendChild(id(new AphrontFormStaticControl())->setLabel(pht('URI'))->setValue($uri))->appendChild(id(new PhabricatorRemarkupControl())->setLabel(pht('Content'))->setValue($content_text)->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_TALL)->setName('content')->setID('document-textarea')->setUser($user))->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('Edit Document'))->setFormErrors($errors)->setForm($form); $preview = id(new PHUIRemarkupPreviewPanel())->setHeader(pht('Document Preview'))->setPreviewURI('/phriction/preview/')->setControlID('document-textarea')->setSkin('document'); $crumbs = $this->buildApplicationCrumbs(); if ($document->getID()) { $crumbs->addTextCrumb($content->getTitle(), PhrictionDocument::getSlugURI($document->getSlug())); $crumbs->addTextCrumb(pht('Edit')); } else { $crumbs->addTextCrumb(pht('Create')); } return $this->buildApplicationPage(array($crumbs, $draft_note, $form_box, $preview), array('title' => pht('Edit Document'))); }
protected function execute(ConduitAPIRequest $request) { $slug = $request->getValue('slug'); $editor = id(PhrictionDocumentEditor::newForSlug($slug))->setUser($request->getUser())->setTitle($request->getValue('title'))->setContent($request->getValue('content'))->setDescription($request->getvalue('description'))->save(); return $this->buildDocumentInfoDictionary($editor->getDocument()); }
protected function applyCustomExternalTransaction(PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction) { $old = $xaction->getOldValue(); $new = $xaction->getNewValue(); switch ($xaction->getTransactionType()) { case PhabricatorProjectTransaction::TYPE_NAME: // First, remove the old and new slugs. Removing the old slug is // important when changing the project's capitalization or puctuation. // Removing the new slug is important when changing the project's name // so that one of its secondary slugs is now the primary slug. if ($old !== null) { $this->removeSlug($object, $old); } $this->removeSlug($object, $new); $new_slug = id(new PhabricatorProjectSlug())->setSlug($object->getPrimarySlug())->setProjectPHID($object->getPHID())->save(); // TODO -- delete all of the below once we sever automagical project // to phriction stuff if ($xaction->getOldValue() === null) { // Project was just created, we don't need to move anything. return; } $clone_object = clone $object; $clone_object->setPhrictionSlug($xaction->getOldValue()); $old_slug = $clone_object->getFullPhrictionSlug(); $old_document = id(new PhrictionDocument())->loadOneWhere('slug = %s', $old_slug); if ($old_document && $old_document->getStatus() == PhrictionDocumentStatus::STATUS_EXISTS) { $content = id(new PhrictionContent())->load($old_document->getContentID()); $from_editor = id(PhrictionDocumentEditor::newForSlug($old_slug))->setActor($this->getActor())->setTitle($content->getTitle())->setContent($content->getContent())->setDescription($content->getDescription()); $target_editor = id(PhrictionDocumentEditor::newForSlug($object->getFullPhrictionSlug()))->setActor($this->getActor())->setTitle($content->getTitle())->setContent($content->getContent())->setDescription($content->getDescription())->moveHere($old_document->getID(), $old_document->getPHID()); $target_document = $target_editor->getDocument(); $from_editor->moveAway($target_document->getID()); } return; case PhabricatorProjectTransaction::TYPE_SLUGS: $old = $xaction->getOldValue(); $new = $xaction->getNewValue(); $add = array_diff($new, $old); $rem = array_diff($old, $new); if ($add) { $add_slug_template = id(new PhabricatorProjectSlug())->setProjectPHID($object->getPHID()); foreach ($add as $add_slug_str) { $add_slug = id(clone $add_slug_template)->setSlug($add_slug_str)->save(); } } if ($rem) { $rem_slugs = id(new PhabricatorProjectSlug())->loadAllWhere('slug IN (%Ls)', $rem); foreach ($rem_slugs as $rem_slug) { $rem_slug->delete(); } } return; case PhabricatorTransactions::TYPE_VIEW_POLICY: case PhabricatorTransactions::TYPE_EDIT_POLICY: case PhabricatorTransactions::TYPE_JOIN_POLICY: case PhabricatorProjectTransaction::TYPE_STATUS: case PhabricatorProjectTransaction::TYPE_IMAGE: case PhabricatorProjectTransaction::TYPE_ICON: case PhabricatorProjectTransaction::TYPE_COLOR: return; case PhabricatorTransactions::TYPE_EDGE: $edge_type = $xaction->getMetadataValue('edge:type'); switch ($edge_type) { case PhabricatorEdgeConfig::TYPE_PROJ_MEMBER: case PhabricatorEdgeConfig::TYPE_OBJECT_HAS_WATCHER: $old = $xaction->getOldValue(); $new = $xaction->getNewValue(); // When adding members or watchers, we add subscriptions. $add = array_keys(array_diff_key($new, $old)); // When removing members, we remove their subscription too. // When unwatching, we leave subscriptions, since it's fine to be // subscribed to a project but not be a member of it. if ($edge_type == PhabricatorEdgeConfig::TYPE_PROJ_MEMBER) { $rem = array_keys(array_diff_key($old, $new)); } else { $rem = array(); } // NOTE: The subscribe is "explicit" because there's no implicit // unsubscribe, so Join -> Leave -> Join doesn't resubscribe you // if we use an implicit subscribe, even though you never willfully // unsubscribed. Not sure if adding implicit unsubscribe (which // would not write the unsubscribe row) is justified to deal with // this, which is a fairly weird edge case and pretty arguable both // ways. // Subscriptions caused by watches should also clearly be explicit, // and that case is unambiguous. id(new PhabricatorSubscriptionsEditor())->setActor($this->requireActor())->setObject($object)->subscribeExplicit($add)->unsubscribe($rem)->save(); if ($rem) { // When removing members, also remove any watches on the project. $edge_editor = new PhabricatorEdgeEditor(); foreach ($rem as $rem_phid) { $edge_editor->removeEdge($object->getPHID(), PhabricatorEdgeConfig::TYPE_OBJECT_HAS_WATCHER, $rem_phid); } $edge_editor->save(); } break; } return; } return parent::applyCustomExternalTransaction($object, $xaction); }
private function updateDocument($document, $content, $new_content) { $is_new = false; if (!$document->getID()) { $is_new = true; } $new_content->setVersion($content->getVersion() + 1); $change_type = $new_content->getChangeType(); switch ($change_type) { case PhrictionChangeType::CHANGE_EDIT: $doc_status = PhrictionDocumentStatus::STATUS_EXISTS; $feed_action = $is_new ? PhrictionActionConstants::ACTION_CREATE : PhrictionActionConstants::ACTION_EDIT; break; case PhrictionChangeType::CHANGE_DELETE: $doc_status = PhrictionDocumentStatus::STATUS_DELETED; $feed_action = PhrictionActionConstants::ACTION_DELETE; if ($is_new) { throw new Exception("You can not delete a document which doesn't exist yet!"); } break; case PhrictionChangeType::CHANGE_STUB: $doc_status = PhrictionDocumentStatus::STATUS_STUB; $feed_action = null; break; case PhrictionChangeType::CHANGE_MOVE_AWAY: $doc_status = PhrictionDocumentStatus::STATUS_MOVED; $feed_action = null; break; case PhrictionChangeType::CHANGE_MOVE_HERE: $doc_status = PhrictionDocumentStatus::STATUS_EXISTS; $feed_action = PhrictionActionConstants::ACTION_MOVE_HERE; break; default: throw new Exception("Unsupported content change type '{$change_type}'!"); } $document->setStatus($doc_status); // TODO: This should be transactional. if ($is_new) { $document->save(); } $new_content->setDocumentID($document->getID()); $new_content->save(); $document->setContentID($new_content->getID()); $document->save(); $document->attachContent($new_content); id(new PhabricatorSearchIndexer())->queueDocumentForIndexing($document->getPHID()); // Stub out empty parent documents if they don't exist $ancestral_slugs = PhabricatorSlug::getAncestry($document->getSlug()); if ($ancestral_slugs) { $ancestors = id(new PhrictionDocument())->loadAllWhere('slug IN (%Ls)', $ancestral_slugs); $ancestors = mpull($ancestors, null, 'getSlug'); foreach ($ancestral_slugs as $slug) { // We check for change type to prevent near-infinite recursion if (!isset($ancestors[$slug]) && $new_content->getChangeType() != PhrictionChangeType::CHANGE_STUB) { id(PhrictionDocumentEditor::newForSlug($slug))->setActor($this->getActor())->setTitle(PhabricatorSlug::getDefaultTitle($slug))->setContent('')->setDescription(pht('Empty Parent Document'))->stub(); } } } $project_phid = null; $slug = $document->getSlug(); if (PhrictionDocument::isProjectSlug($slug)) { $project = id(new PhabricatorProjectQuery())->setViewer($this->requireActor())->withPhrictionSlugs(array(PhrictionDocument::getProjectSlugIdentifier($slug)))->executeOne(); if ($project) { $project_phid = $project->getPHID(); } } $related_phids = array($document->getPHID(), $this->getActor()->getPHID()); if ($project_phid) { $related_phids[] = $project_phid; } if ($this->fromDocumentPHID) { $related_phids[] = $this->fromDocumentPHID; } if ($feed_action) { $content_str = id(new PhutilUTF8StringTruncator())->setMaximumGlyphs(140)->truncateString($new_content->getContent()); id(new PhabricatorFeedStoryPublisher())->setRelatedPHIDs($related_phids)->setStoryAuthorPHID($this->getActor()->getPHID())->setStoryTime(time())->setStoryType(PhabricatorFeedStoryTypeConstants::STORY_PHRICTION)->setStoryData(array('phid' => $document->getPHID(), 'action' => $feed_action, 'content' => $content_str, 'project' => $project_phid, 'movedFromPHID' => $this->fromDocumentPHID))->publish(); } // TODO: Migrate to ApplicationTransactions fast, so we get rid of this code $subscribers = PhabricatorSubscribersQuery::loadSubscribersForPHID($document->getPHID()); $this->sendMailToSubscribers($subscribers, $content); return $this; }