diff --git a/src/applications/phriction/controller/PhrictionDeleteController.php b/src/applications/phriction/controller/PhrictionDeleteController.php index 7a97c3abfc..5f773834fe 100644 --- a/src/applications/phriction/controller/PhrictionDeleteController.php +++ b/src/applications/phriction/controller/PhrictionDeleteController.php @@ -1,67 +1,77 @@ id = $data['id']; } public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); $document = id(new PhrictionDocumentQuery()) ->setViewer($user) ->withIDs(array($this->id)) + ->needContent(true) ->requireCapabilities( array( PhabricatorPolicyCapability::CAN_EDIT, PhabricatorPolicyCapability::CAN_VIEW, )) ->executeOne(); if (!$document) { return new Aphront404Response(); } $e_text = null; $disallowed_states = array( PhrictionDocumentStatus::STATUS_DELETED => true, // Silly PhrictionDocumentStatus::STATUS_MOVED => true, // Makes no sense PhrictionDocumentStatus::STATUS_STUB => true, // How could they? ); if (isset($disallowed_states[$document->getStatus()])) { - $e_text = pht('An already moved or deleted document can not be deleted'); + $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())) + $xactions = array(); + $xactions[] = id(new PhrictionTransaction()) + ->setTransactionType(PhrictionTransaction::TYPE_DELETE) + ->setNewValue(true); + + $editor = id(new PhrictionTransactionEditor()) ->setActor($user) - ->delete(); + ->setContentSourceFromRequest($request) + ->setContinueOnNoEffect(true) + ->applyTransactions($document, $xactions); + 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); } } diff --git a/src/applications/phriction/editor/PhrictionTransactionEditor.php b/src/applications/phriction/editor/PhrictionTransactionEditor.php index 546abc3979..4fef27449c 100644 --- a/src/applications/phriction/editor/PhrictionTransactionEditor.php +++ b/src/applications/phriction/editor/PhrictionTransactionEditor.php @@ -1,298 +1,309 @@ description = $description; return $this; } private function getDescription() { return $this->description; } private function setOldContent(PhrictionContent $content) { $this->oldContent = $content; return $this; } private function getOldContent() { return $this->oldContent; } private function setNewContent(PhrictionContent $content) { $this->newContent = $content; return $this; } private function getNewContent() { return $this->newContent; } public function getEditorApplicationClass() { return 'PhabricatorPhrictionApplication'; } public function getEditorObjectsDescription() { return pht('Phriction Documents'); } public function getTransactionTypes() { $types = parent::getTransactionTypes(); $types[] = PhabricatorTransactions::TYPE_COMMENT; $types[] = PhrictionTransaction::TYPE_TITLE; $types[] = PhrictionTransaction::TYPE_CONTENT; + $types[] = PhrictionTransaction::TYPE_DELETE; /* TODO $types[] = PhabricatorTransactions::TYPE_VIEW_POLICY; $types[] = PhabricatorTransactions::TYPE_EDIT_POLICY; */ return $types; } protected function getCustomTransactionOldValue( PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction) { switch ($xaction->getTransactionType()) { case PhrictionTransaction::TYPE_TITLE: if ($this->getIsNewObject()) { return null; } return $this->getOldContent()->getTitle(); case PhrictionTransaction::TYPE_CONTENT: if ($this->getIsNewObject()) { return null; } return $this->getOldContent()->getContent(); + case PhrictionTransaction::TYPE_DELETE: + return null; } } protected function getCustomTransactionNewValue( PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction) { switch ($xaction->getTransactionType()) { case PhrictionTransaction::TYPE_TITLE: case PhrictionTransaction::TYPE_CONTENT: + case PhrictionTransaction::TYPE_DELETE: return $xaction->getNewValue(); } } protected function shouldApplyInitialEffects( PhabricatorLiskDAO $object, array $xactions) { foreach ($xactions as $xaction) { switch ($xaction->getTransactionType()) { case PhrictionTransaction::TYPE_TITLE: case PhrictionTransaction::TYPE_CONTENT: + case PhrictionTransaction::TYPE_DELETE: return true; } } return parent::shouldApplyInitialEffects($object, $xactions); } protected function applyInitialEffects( PhabricatorLiskDAO $object, array $xactions) { $this->setOldContent($object->getContent()); $this->setNewContent($this->buildNewContentTemplate($object)); } protected function applyCustomInternalTransaction( PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction) { switch ($xaction->getTransactionType()) { case PhrictionTransaction::TYPE_TITLE: case PhrictionTransaction::TYPE_CONTENT: $object->setStatus(PhrictionDocumentStatus::STATUS_EXISTS); return; } } protected function applyCustomExternalTransaction( PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction) { switch ($xaction->getTransactionType()) { case PhrictionTransaction::TYPE_TITLE: $this->getNewContent()->setTitle($xaction->getNewValue()); break; case PhrictionTransaction::TYPE_CONTENT: $this->getNewContent()->setContent($xaction->getNewValue()); break; + case PhrictionTransaction::TYPE_DELETE: + $this->getNewContent()->setContent(''); + $this->getNewContent()->setChangeType( + PhrictionChangeType::CHANGE_DELETE); + break; default: break; } } 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: $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()) { // Stub out empty parent documents if they don't exist $ancestral_slugs = PhabricatorSlug::getAncestry($object->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]) && $content->getChangeType() != PhrictionChangeType::CHANGE_STUB) { id(PhrictionDocumentEditor::newForSlug($slug)) ->setActor($this->getActor()) ->setTitle(PhabricatorSlug::getDefaultTitle($slug)) ->setContent('') ->setDescription(pht('Empty Parent Document')) ->stub(); } } } } return $xactions; } protected function shouldSendMail( PhabricatorLiskDAO $object, array $xactions) { $xactions = mfilter($xactions, 'shouldHide', true); return $xactions; } protected function getMailSubjectPrefix() { return '[Phriction]'; } protected function getMailTo(PhabricatorLiskDAO $object) { return array( $object->getContent()->getAuthorPHID(), $this->getActingAsPHID(), ); } public function getMailTagsMap() { return array( PhrictionTransaction::MAILTAG_TITLE => pht("A document's title changes."), PhrictionTransaction::MAILTAG_CONTENT => pht("A document's content changes."), + PhrictionTransaction::MAILTAG_DELETE => + pht('A document is deleted.'), ); } protected function buildReplyHandler(PhabricatorLiskDAO $object) { return id(new PhrictionReplyHandler()) ->setMailReceiver($object); } protected function buildMailTemplate(PhabricatorLiskDAO $object) { $id = $object->getID(); $title = $object->getContent()->getTitle(); return id(new PhabricatorMetaMTAMail()) ->setSubject($title) ->addHeader('Thread-Topic', $object->getPHID()); } protected function buildMailBody( PhabricatorLiskDAO $object, array $xactions) { $body = parent::buildMailBody($object, $xactions); if ($this->getIsNewObject()) { $body->addTextSection( pht('DOCUMENT CONTENT'), $object->getContent()->getContent()); } $body->addLinkSection( pht('DOCUMENT DETAIL'), PhabricatorEnv::getProductionURI( PhrictionDocument::getSlugURI($object->getSlug()))); return $body; } protected function shouldPublishFeedStory( PhabricatorLiskDAO $object, array $xactions) { return $this->shouldSendMail($object, $xactions); } protected function getFeedRelatedPHIDs( PhabricatorLiskDAO $object, array $xactions) { $phids = parent::getFeedRelatedPHIDs($object, $xactions); // TODO - once the editor supports moves, we'll need to surface the // "from document phid" to related phids. return $phids; } protected function supportsSearch() { return true; } protected function shouldApplyHeraldRules( PhabricatorLiskDAO $object, array $xactions) { return false; } private function buildNewContentTemplate( PhrictionDocument $document) { - $new_content = new PhrictionContent(); - $new_content->setSlug($document->getSlug()); - $new_content->setAuthorPHID($this->getActor()->getPHID()); - $new_content->setChangeType(PhrictionChangeType::CHANGE_EDIT); - - $new_content->setTitle($this->getOldContent()->getTitle()); - $new_content->setContent($this->getOldContent()->getContent()); - + $new_content = id(new PhrictionContent()) + ->setSlug($document->getSlug()) + ->setAuthorPHID($this->getActor()->getPHID()) + ->setChangeType(PhrictionChangeType::CHANGE_EDIT) + ->setTitle($this->getOldContent()->getTitle()) + ->setContent($this->getOldContent()->getContent()); if (strlen($this->getDescription())) { $new_content->setDescription($this->getDescription()); } $new_content->setVersion($this->getOldContent()->getVersion() + 1); return $new_content; } } diff --git a/src/applications/phriction/storage/PhrictionTransaction.php b/src/applications/phriction/storage/PhrictionTransaction.php index afbd1e2f98..1d0fc12700 100644 --- a/src/applications/phriction/storage/PhrictionTransaction.php +++ b/src/applications/phriction/storage/PhrictionTransaction.php @@ -1,186 +1,210 @@ getTransactionType()) { case self::TYPE_CONTENT: $blocks[] = $this->getNewValue(); break; } return $blocks; } public function shouldHide() { switch ($this->getTransactionType()) { case self::TYPE_CONTENT: if ($this->getOldValue() === null) { return true; } else { return false; } break; } return parent::shouldHide(); } public function getActionStrength() { switch ($this->getTransactionType()) { case self::TYPE_TITLE: return 1.4; case self::TYPE_CONTENT: return 1.3; + case self::TYPE_DELETE: + return 1.5; } return parent::getActionStrength(); } public function getActionName() { $old = $this->getOldValue(); $new = $this->getNewValue(); switch ($this->getTransactionType()) { case self::TYPE_TITLE: if ($old === null) { return pht('Created'); } return pht('Retitled'); case self::TYPE_CONTENT: return pht('Edited'); + case self::TYPE_DELETE: + return pht('Deleted'); + } return parent::getActionName(); } public function getIcon() { $old = $this->getOldValue(); $new = $this->getNewValue(); switch ($this->getTransactionType()) { case self::TYPE_TITLE: case self::TYPE_CONTENT: return 'fa-pencil'; + case self::TYPE_DELETE: + return 'fa-times'; } return parent::getIcon(); } - public function getTitle() { $author_phid = $this->getAuthorPHID(); $old = $this->getOldValue(); $new = $this->getNewValue(); switch ($this->getTransactionType()) { case self::TYPE_TITLE: if ($old === null) { return pht( '%s created this document.', $this->renderHandleLink($author_phid)); } return pht( '%s changed the title from "%s" to "%s".', $this->renderHandleLink($author_phid), $old, $new); case self::TYPE_CONTENT: return pht( '%s edited the document content.', $this->renderHandleLink($author_phid)); + case self::TYPE_DELETE: + return pht( + '%s deleted this document.', + $this->renderHandleLink($author_phid)); + + } return parent::getTitle(); } public function getTitleForFeed(PhabricatorFeedStory $story) { $author_phid = $this->getAuthorPHID(); $object_phid = $this->getObjectPHID(); $old = $this->getOldValue(); $new = $this->getNewValue(); switch ($this->getTransactionType()) { case self::TYPE_TITLE: if ($old === null) { return pht( '%s created %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); } return pht( '%s renamed %s from "%s" to "%s".', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid), $old, $new); case self::TYPE_CONTENT: return pht( '%s edited the content of %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); + case self::TYPE_DELETE: + return pht( + '%s deleted %s.', + $this->renderHandleLink($author_phid), + $this->renderHandleLink($object_phid)); + } return parent::getTitleForFeed($story); } public function hasChangeDetails() { switch ($this->getTransactionType()) { case self::TYPE_CONTENT: return true; } return parent::hasChangeDetails(); } public function renderChangeDetails(PhabricatorUser $viewer) { return $this->renderTextCorpusChangeDetails( $viewer, $this->getOldValue(), $this->getNewValue()); } public function getMailTags() { $tags = array(); switch ($this->getTransactionType()) { case self::TYPE_TITLE: $tags[] = self::MAILTAG_TITLE; break; case self::TYPE_CONTENT: $tags[] = self::MAILTAG_CONTENT; break; + case self::TYPE_DELETE: + $tags[] = self::MAILTAG_DELETE; + break; + } return $tags; } }