1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-12-23 22:10:55 +01:00

Phriction Documents can be moved

Summary: Refs T1575

Test Plan:
created plenty of pages, did all kind of stuff with them, moved them around, verified expected behaviour.

{F34453}

{F34455}

Reviewers: epriestley, chad, btrahan

Reviewed By: epriestley

CC: aran, epriestley, Korvin

Maniphest Tasks: T1575

Differential Revision: https://secure.phabricator.com/D5198
This commit is contained in:
Anh Nhan Nguyen 2013-03-06 13:12:04 -08:00 committed by epriestley
parent cd99850cb8
commit 911d02e2d1
8 changed files with 274 additions and 21 deletions

View file

@ -1497,6 +1497,7 @@ phutil_register_library_map(array(
'PhrictionEditController' => 'applications/phriction/controller/PhrictionEditController.php',
'PhrictionHistoryController' => 'applications/phriction/controller/PhrictionHistoryController.php',
'PhrictionListController' => 'applications/phriction/controller/PhrictionListController.php',
'PhrictionMoveController' => 'applications/phriction/controller/PhrictionMoveController.php',
'PhrictionNewController' => 'applications/phriction/controller/PhrictionNewController.php',
'PhrictionRemarkupRule' => 'applications/phriction/remarkup/PhrictionRemarkupRule.php',
'PhrictionSearchIndexer' => 'applications/phriction/search/PhrictionSearchIndexer.php',
@ -3003,6 +3004,7 @@ phutil_register_library_map(array(
'PhrictionEditController' => 'PhrictionController',
'PhrictionHistoryController' => 'PhrictionController',
'PhrictionListController' => 'PhrictionController',
'PhrictionMoveController' => 'PhrictionController',
'PhrictionNewController' => 'PhrictionController',
'PhrictionRemarkupRule' => 'PhutilRemarkupRule',
'PhrictionSearchIndexer' => 'PhabricatorSearchDocumentIndexer',

View file

@ -43,7 +43,7 @@ final class PhabricatorApplicationPhriction extends PhabricatorApplication {
'edit/(?:(?P<id>[1-9]\d*)/)?' => 'PhrictionEditController',
'delete/(?P<id>[1-9]\d*)/' => 'PhrictionDeleteController',
'new/' => 'PhrictionNewController',
'move/(?P<id>[1-9]\d*)/' => 'PhrictionMoveController',
'move/(?:(?P<id>[1-9]\d*)/)?' => 'PhrictionMoveController',
'preview/' => 'PhrictionDocumentPreviewController',
'diff/(?P<id>[1-9]\d*)/' => 'PhrictionDiffController',

View file

@ -8,12 +8,16 @@ final class PhrictionActionConstants extends PhrictionConstants {
const ACTION_CREATE = 'create';
const ACTION_EDIT = 'edit';
const ACTION_DELETE = 'delete';
const ACTION_MOVE_AWAY = 'move to';
const ACTION_MOVE_HERE = 'move here';
public static function getActionPastTenseVerb($action) {
static $map = array(
self::ACTION_CREATE => 'created',
self::ACTION_EDIT => 'edited',
self::ACTION_DELETE => 'deleted',
self::ACTION_MOVE_AWAY => 'moved a document to',
self::ACTION_MOVE_HERE => 'moved a document from',
);
return idx($map, $action, "brazenly {$action}'d");

View file

@ -12,8 +12,9 @@ final class PhrictionDocumentStatus extends PhrictionConstants {
public static function getConduitConstant($const) {
static $map = array(
self::STATUS_EXISTS => 'exists',
self::STATUS_EXISTS => 'exists',
self::STATUS_DELETED => 'deleted',
self::STATUS_MOVED => 'moved',
self::STATUS_STUB => 'stubbed',
);

View file

@ -13,7 +13,6 @@ final class PhrictionDocumentController
}
public function processRequest() {
$request = $this->getRequest();
$user = $request->getUser();
@ -148,14 +147,43 @@ final class PhrictionDocumentController
pht('This document is empty. You can edit it to put some proper '.
'content here.'));
$core_content = $notice->render();
} else if ($doc_status == PhrictionDocumentStatus::STATUS_MOVED) {
$new_doc_id = $content->getChangeRef();
$new_doc = new PhrictionDocument();
$new_doc->load($new_doc_id);
$slug_uri = PhrictionDocument::getSlugURI($new_doc->getSlug());
$notice = new AphrontErrorView();
$notice->setSeverity(AphrontErrorView::SEVERITY_NOTICE);
$notice->setTitle(pht('Document Moved'));
$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))));
$core_content = $notice->render();
} else {
throw new Exception("Unknown document status '{$doc_status}'!");
}
$move_notice = null;
if ($content->getChangeType() == PhrictionChangeType::CHANGE_MOVE_HERE) {
$from_doc_id = $content->getChangeRef();
$from_doc = id(new PhrictionDocument())->load($from_doc_id);
$slug_uri = PhrictionDocument::getSlugURI($from_doc->getSlug());
$move_notice = id(new AphrontErrorView())
->setSeverity(AphrontErrorView::SEVERITY_NOTICE)
->appendChild(pht('This document was moved from %s',
phutil_tag('a', array('href' => $slug_uri), $slug_uri)))
->render();
}
$page_content = hsprintf(
'<div class="phriction-content">%s%s%s</div>',
'<div class="phriction-content">%s%s%s%s</div>',
$index_link,
$byline,
$move_notice,
$core_content);
}
@ -221,6 +249,13 @@ final class PhrictionDocumentController
->setHref('/phriction/edit/'.$document->getID().'/'));
if ($document->getStatus() == PhrictionDocumentStatus::STATUS_EXISTS) {
$action_view->addAction(
id(new PhabricatorActionView())
->setName(pht('Move Document'))
->setIcon('move')
->setHref('/phriction/move/'.$document->getID().'/')
->setWorkflow(true));
$action_view->addAction(
id(new PhabricatorActionView())
->setName(pht('Delete Document'))

View file

@ -115,9 +115,13 @@ final class PhrictionListController
case 'active':
$data = queryfx_all(
$conn,
'SELECT * FROM %T WHERE status != %d ORDER BY id DESC LIMIT %d, %d',
'SELECT * FROM %T WHERE status NOT IN (%Ld) ORDER BY id DESC '.
'LIMIT %d, %d',
$document_dao->getTableName(),
PhrictionDocumentStatus::STATUS_DELETED,
array(
PhrictionDocumentStatus::STATUS_DELETED,
PhrictionDocumentStatus::STATUS_MOVED,
),
$pager->getOffset(),
$pager->getPageSize() + 1);
break;

View file

@ -0,0 +1,188 @@
<?php
/**
* @group phriction
*/
final class PhrictionMoveController
extends PhrictionController {
private $id;
public function willProcessRequest(array $data) {
$this->id = idx($data, 'id');
}
public function processRequest() {
$request = $this->getRequest();
$user = $request->getUser();
$is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business');
if ($this->id) {
$document = id(new PhrictionDocument())->load($this->id);
} else {
$slug = PhabricatorSlug::normalize(
$request->getStr('slug'));
if (!$slug) {
return new Aphront404Response();
}
$document = id(new PhrictionDocument())->loadOneWhere(
'slug = %s',
$slug);
}
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;
$e_block = false;
$disallowed_statuses = array(
PhrictionDocumentStatus::STATUS_DELETED, // Stupid
PhrictionDocumentStatus::STATUS_MOVED, // Plain stupid
);
if (in_array($document->getStatus(), $disallowed_statuses)) {
$error_view = new AphrontErrorView();
$error_view->setSeverity(AphrontErrorView::SEVERITY_ERROR);
$error_view->appendChild(pht('An already moved or deleted document '.
'can not be moved again.'));
$error_dialog = new AphrontDialogView();
$error_dialog->setUser($user);
$error_dialog->setTitle("");
$error_dialog->appendChild($error_view);
$error_dialog->addCancelButton($cancel_uri, pht('I understand'));
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
$target_document = id(new PhrictionDocument())->loadOneWhere(
'slug = %s',
$target_slug);
// 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());
// 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())
->setTitle(pht('Form Errors'))
->setErrors($errors);
}
$descr_caption = $is_serious ? pht('A reason for the move.') :
pht('You better give a good reason for this.');
if ($request->isAjax()) {
$form = new AphrontFormLayoutView();
} else {
$form = new AphrontFormView();
$form->setAction($submit_uri)
// Append title so the user can verify that he's touching
// the right document
->appendChild(
id(new AphrontFormStaticControl())
->setLabel(pht('Title'))
->setValue($content->getTitle()));
}
$form
->setUser($user)
->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')
->setCaption($descr_caption));
if ($request->isAjax()) {
$dialog = new AphrontDialogView();
$dialog->setUser($user);
$dialog->setTitle(pht('Move Document'));
$dialog->appendChild($form);
$dialog->setSubmitURI($submit_uri);
$dialog->addSubmitButton(pht('Move Document'));
$dialog->addCancelButton($cancel_uri);
return id(new AphrontDialogResponse())->setDialog($dialog);
} else {
$form->appendChild(
id(new AphrontFormSubmitControl())
->addCancelButton($cancel_uri)
->setValue(pht('Move Document'))
->setDisabled($e_block));
$panel = id(new AphrontPanelView())
->setNoBackground()
->setHeader(pht('Move Phriction Document'))
->appendChild($form);
return $this->buildApplicationPage(
array(
$error_view,
$panel,
),
array(
'title' => pht('Move Document'),
'device' => true,
));
}
}
}

View file

@ -66,33 +66,44 @@ final class PhrictionDocumentEditor extends PhabricatorEditor {
return $this->document;
}
public function delete() {
$actor = $this->requireActor();
public function moveAway($new_doc_id) {
return $this->execute(
PhrictionChangeType::CHANGE_MOVE_AWAY, true, $new_doc_id);
}
// TODO: Should we do anything about deleting an already-deleted document?
// We currently allow it.
public function moveHere($old_doc_id) {
return $this->execute(
PhrictionChangeType::CHANGE_MOVE_HERE, false, $old_doc_id);
}
private function execute(
$change_type, $del_new_content = true, $doc_ref = null) {
$actor = $this->requireActor();
$document = $this->document;
$content = $this->content;
$new_content = $this->buildContentTemplate($document, $content);
$new_content->setChangeType($change_type);
$new_content->setChangeType(PhrictionChangeType::CHANGE_DELETE);
$new_content->setContent('');
if ($del_new_content) {
$new_content->setContent('');
}
if ($doc_ref) {
$new_content->setChangeRef($doc_ref);
}
return $this->updateDocument($document, $content, $new_content);
}
public function delete() {
return $this->execute(PhrictionChangeType::CHANGE_DELETE, true);
}
private function stub() {
$actor = $this->requireActor();
$document = $this->document;
$content = $this->content;
$new_content = $this->buildContentTemplate($document, $content);
$new_content->setChangeType(PhrictionChangeType::CHANGE_STUB);
$new_content->setContent('');
return $this->updateDocument($document, $content, $new_content);
return $this->execute(PhrictionChangeType::CHANGE_STUB, true);
}
public function save() {
@ -168,6 +179,14 @@ final class PhrictionDocumentEditor extends PhabricatorEditor {
$doc_status = PhrictionDocumentStatus::STATUS_STUB;
$feed_action = null;
break;
case PhrictionChangeType::CHANGE_MOVE_AWAY:
$doc_status = PhrictionDocumentStatus::STATUS_MOVED;
$feed_action = PhrictionActionConstants::ACTION_MOVE_AWAY;
break;
case PhrictionChangeType::CHANGE_MOVE_HERE:
$doc_status = PhrictionDocumentStatus::STATUS_EXISTS;
$feed_action = null;
break;
default:
throw new Exception(
"Unsupported content change type '{$change_type}'!");