Changeset View
Changeset View
Standalone View
Standalone View
src/infrastructure/diff/PhabricatorInlineCommentController.php
Show All 33 Lines | protected function showComments(array $ids) { | ||||
throw new PhutilMethodNotImplementedException(); | throw new PhutilMethodNotImplementedException(); | ||||
} | } | ||||
private $changesetID; | private $changesetID; | ||||
private $isNewFile; | private $isNewFile; | ||||
private $isOnRight; | private $isOnRight; | ||||
private $lineNumber; | private $lineNumber; | ||||
private $lineLength; | private $lineLength; | ||||
private $commentText; | |||||
private $operation; | private $operation; | ||||
private $commentID; | private $commentID; | ||||
private $renderer; | private $renderer; | ||||
private $replyToCommentPHID; | private $replyToCommentPHID; | ||||
public function getCommentID() { | public function getCommentID() { | ||||
return $this->commentID; | return $this->commentID; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | abstract class PhabricatorInlineCommentController | ||||
public function getReplyToCommentPHID() { | public function getReplyToCommentPHID() { | ||||
return $this->replyToCommentPHID; | return $this->replyToCommentPHID; | ||||
} | } | ||||
public function processRequest() { | public function processRequest() { | ||||
$request = $this->getRequest(); | $request = $this->getRequest(); | ||||
$viewer = $this->getViewer(); | $viewer = $this->getViewer(); | ||||
if (!$request->validateCSRF()) { | |||||
return new Aphront404Response(); | |||||
} | |||||
$this->readRequestParameters(); | $this->readRequestParameters(); | ||||
$op = $this->getOperation(); | $op = $this->getOperation(); | ||||
switch ($op) { | switch ($op) { | ||||
case 'hide': | case 'hide': | ||||
case 'show': | case 'show': | ||||
if (!$request->validateCSRF()) { | |||||
return new Aphront404Response(); | |||||
} | |||||
$ids = $request->getStrList('ids'); | $ids = $request->getStrList('ids'); | ||||
if ($ids) { | if ($ids) { | ||||
if ($op == 'hide') { | if ($op == 'hide') { | ||||
$this->hideComments($ids); | $this->hideComments($ids); | ||||
} else { | } else { | ||||
$this->showComments($ids); | $this->showComments($ids); | ||||
} | } | ||||
} | } | ||||
return id(new AphrontAjaxResponse())->setContent(array()); | return id(new AphrontAjaxResponse())->setContent(array()); | ||||
case 'done': | case 'done': | ||||
if (!$request->validateCSRF()) { | |||||
return new Aphront404Response(); | |||||
} | |||||
$inline = $this->loadCommentForDone($this->getCommentID()); | $inline = $this->loadCommentForDone($this->getCommentID()); | ||||
$is_draft_state = false; | $is_draft_state = false; | ||||
$is_checked = false; | $is_checked = false; | ||||
switch ($inline->getFixedState()) { | switch ($inline->getFixedState()) { | ||||
case PhabricatorInlineComment::STATE_DRAFT: | case PhabricatorInlineComment::STATE_DRAFT: | ||||
$next_state = PhabricatorInlineComment::STATE_UNDONE; | $next_state = PhabricatorInlineComment::STATE_UNDONE; | ||||
break; | break; | ||||
Show All 19 Lines | switch ($op) { | ||||
->setContent( | ->setContent( | ||||
array( | array( | ||||
'isChecked' => $is_checked, | 'isChecked' => $is_checked, | ||||
'draftState' => $is_draft_state, | 'draftState' => $is_draft_state, | ||||
)); | )); | ||||
case 'delete': | case 'delete': | ||||
case 'undelete': | case 'undelete': | ||||
case 'refdelete': | case 'refdelete': | ||||
if (!$request->validateCSRF()) { | |||||
return new Aphront404Response(); | |||||
} | |||||
// NOTE: For normal deletes, we just process the delete immediately | // NOTE: For normal deletes, we just process the delete immediately | ||||
// and show an "Undo" action. For deletes by reference from the | // and show an "Undo" action. For deletes by reference from the | ||||
// preview ("refdelete"), we prompt first (because the "Undo" may | // preview ("refdelete"), we prompt first (because the "Undo" may | ||||
// not draw, or may not be easy to locate). | // not draw, or may not be easy to locate). | ||||
if ($op == 'refdelete') { | if ($op == 'refdelete') { | ||||
if (!$request->isFormPost()) { | if (!$request->isFormPost()) { | ||||
return $this->newDialog() | return $this->newDialog() | ||||
Show All 15 Lines | switch ($op) { | ||||
} else { | } else { | ||||
$inline->setIsDeleted(0); | $inline->setIsDeleted(0); | ||||
} | } | ||||
$this->saveComment($inline); | $this->saveComment($inline); | ||||
return $this->buildEmptyResponse(); | return $this->buildEmptyResponse(); | ||||
case 'edit': | case 'edit': | ||||
case 'save': | |||||
$inline = $this->loadCommentByIDForEdit($this->getCommentID()); | $inline = $this->loadCommentByIDForEdit($this->getCommentID()); | ||||
$text = $this->getCommentText(); | if ($op === 'save') { | ||||
$this->updateCommentContentState($inline); | |||||
if ($request->isFormPost()) { | $inline->setIsEditing(false); | ||||
if (strlen($text)) { | |||||
$inline | |||||
->setContent($text) | |||||
->setIsEditing(false); | |||||
if (!$inline->isVoidComment($viewer)) { | |||||
$this->saveComment($inline); | $this->saveComment($inline); | ||||
return $this->buildRenderedCommentResponse( | return $this->buildRenderedCommentResponse( | ||||
$inline, | $inline, | ||||
$this->getIsOnRight()); | $this->getIsOnRight()); | ||||
} else { | } else { | ||||
$inline->setIsDeleted(1); | $inline->setIsDeleted(1); | ||||
$this->saveComment($inline); | $this->saveComment($inline); | ||||
return $this->buildEmptyResponse(); | return $this->buildEmptyResponse(); | ||||
} | } | ||||
} else { | } else { | ||||
// NOTE: At time of writing, the "editing" state of inlines is | // NOTE: At time of writing, the "editing" state of inlines is | ||||
// preserved by simluating a click on "Edit" when the inline loads. | // preserved by simulating a click on "Edit" when the inline loads. | ||||
// In this case, we don't want to "saveComment()", because it | // In this case, we don't want to "saveComment()", because it | ||||
// recalculates object drafts and purges versioned drafts. | // recalculates object drafts and purges versioned drafts. | ||||
// The recalculation is merely unnecessary (state doesn't change) | // The recalculation is merely unnecessary (state doesn't change) | ||||
// but purging drafts means that loading a page and then closing it | // but purging drafts means that loading a page and then closing it | ||||
// discards your drafts. | // discards your drafts. | ||||
// To avoid the purge, only invoke "saveComment()" if we actually | // To avoid the purge, only invoke "saveComment()" if we actually | ||||
// have changes to apply. | // have changes to apply. | ||||
$is_dirty = false; | $is_dirty = false; | ||||
if (!$inline->getIsEditing()) { | if (!$inline->getIsEditing()) { | ||||
$inline->setIsEditing(true); | $inline->setIsEditing(true); | ||||
$is_dirty = true; | $is_dirty = true; | ||||
} | } | ||||
if (strlen($text)) { | if ($this->hasContentState()) { | ||||
$inline->setContent($text); | $this->updateCommentContentState($inline); | ||||
$is_dirty = true; | $is_dirty = true; | ||||
} else { | } else { | ||||
PhabricatorInlineComment::loadAndAttachVersionedDrafts( | PhabricatorInlineComment::loadAndAttachVersionedDrafts( | ||||
$viewer, | $viewer, | ||||
array($inline)); | array($inline)); | ||||
} | } | ||||
if ($is_dirty) { | if ($is_dirty) { | ||||
Show All 10 Lines | switch ($op) { | ||||
case 'cancel': | case 'cancel': | ||||
$inline = $this->loadCommentByIDForEdit($this->getCommentID()); | $inline = $this->loadCommentByIDForEdit($this->getCommentID()); | ||||
$inline->setIsEditing(false); | $inline->setIsEditing(false); | ||||
// If the user uses "Undo" to get into an edited state ("AB"), then | // If the user uses "Undo" to get into an edited state ("AB"), then | ||||
// clicks cancel to return to the previous state ("A"), we also want | // clicks cancel to return to the previous state ("A"), we also want | ||||
// to set the stored state back to "A". | // to set the stored state back to "A". | ||||
$text = $this->getCommentText(); | $this->updateCommentContentState($inline); | ||||
if (strlen($text)) { | |||||
$inline->setContent($text); | |||||
} | |||||
$content = $inline->getContent(); | if ($inline->isVoidComment($viewer)) { | ||||
if (!strlen($content)) { | |||||
$inline->setIsDeleted(1); | $inline->setIsDeleted(1); | ||||
} | } | ||||
$this->saveComment($inline); | $this->saveComment($inline); | ||||
return $this->buildEmptyResponse(); | return $this->buildEmptyResponse(); | ||||
case 'draft': | case 'draft': | ||||
$inline = $this->loadCommentByIDForEdit($this->getCommentID()); | $inline = $this->loadCommentByIDForEdit($this->getCommentID()); | ||||
$versioned_draft = PhabricatorVersionedDraft::loadOrCreateDraft( | $versioned_draft = PhabricatorVersionedDraft::loadOrCreateDraft( | ||||
$inline->getPHID(), | $inline->getPHID(), | ||||
$viewer->getPHID(), | $viewer->getPHID(), | ||||
$inline->getID()); | $inline->getID()); | ||||
$text = $this->getCommentText(); | $map = $this->getContentState(); | ||||
foreach ($map as $key => $value) { | |||||
$versioned_draft | $versioned_draft->setProperty($key, $value); | ||||
->setProperty('inline.text', $text) | } | ||||
->save(); | $versioned_draft->save(); | ||||
// We have to synchronize the draft engine after saving a versioned | // We have to synchronize the draft engine after saving a versioned | ||||
// draft, because taking an inline comment from "no text, no draft" | // draft, because taking an inline comment from "no text, no draft" | ||||
// to "no text, text in a draft" marks the container object as having | // to "no text, text in a draft" marks the container object as having | ||||
// a draft. | // a draft. | ||||
$draft_engine = $this->newDraftEngine(); | $draft_engine = $this->newDraftEngine(); | ||||
if ($draft_engine) { | if ($draft_engine) { | ||||
$draft_engine->synchronize(); | $draft_engine->synchronize(); | ||||
Show All 14 Lines | switch ($op) { | ||||
$length = $this->getLineLength(); | $length = $this->getLineLength(); | ||||
$inline = $this->createComment() | $inline = $this->createComment() | ||||
->setChangesetID($this->getChangesetID()) | ->setChangesetID($this->getChangesetID()) | ||||
->setAuthorPHID($viewer->getPHID()) | ->setAuthorPHID($viewer->getPHID()) | ||||
->setIsNewFile($is_new) | ->setIsNewFile($is_new) | ||||
->setLineNumber($number) | ->setLineNumber($number) | ||||
->setLineLength($length) | ->setLineLength($length) | ||||
->setContent((string)$this->getCommentText()) | |||||
->setReplyToCommentPHID($this->getReplyToCommentPHID()) | ->setReplyToCommentPHID($this->getReplyToCommentPHID()) | ||||
->setIsEditing(true) | ->setIsEditing(true) | ||||
->setStartOffset($request->getInt('startOffset')) | ->setStartOffset($request->getInt('startOffset')) | ||||
->setEndOffset($request->getInt('endOffset')); | ->setEndOffset($request->getInt('endOffset')) | ||||
->setContent(''); | |||||
$document_engine_key = $request->getStr('documentEngineKey'); | $document_engine_key = $request->getStr('documentEngineKey'); | ||||
if ($document_engine_key !== null) { | if ($document_engine_key !== null) { | ||||
$inline->setDocumentEngineKey($document_engine_key); | $inline->setDocumentEngineKey($document_engine_key); | ||||
} | } | ||||
// If you own this object, mark your own inlines as "Done" by default. | // If you own this object, mark your own inlines as "Done" by default. | ||||
$owner_phid = $this->loadObjectOwnerPHID($inline); | $owner_phid = $this->loadObjectOwnerPHID($inline); | ||||
if ($owner_phid) { | if ($owner_phid) { | ||||
if ($viewer->getPHID() == $owner_phid) { | if ($viewer->getPHID() == $owner_phid) { | ||||
$fixed_state = PhabricatorInlineComment::STATE_DRAFT; | $fixed_state = PhabricatorInlineComment::STATE_DRAFT; | ||||
$inline->setFixedState($fixed_state); | $inline->setFixedState($fixed_state); | ||||
} | } | ||||
} | } | ||||
if ($this->hasContentState()) { | |||||
$this->updateCommentContentState($inline); | |||||
} | |||||
$this->saveComment($inline); | $this->saveComment($inline); | ||||
$edit_dialog = $this->buildEditDialog($inline); | $edit_dialog = $this->buildEditDialog($inline); | ||||
if ($this->getOperation() == 'reply') { | if ($this->getOperation() == 'reply') { | ||||
$edit_dialog->setTitle(pht('Reply to Inline Comment')); | $edit_dialog->setTitle(pht('Reply to Inline Comment')); | ||||
} else { | } else { | ||||
$edit_dialog->setTitle(pht('New Inline Comment')); | $edit_dialog->setTitle(pht('New Inline Comment')); | ||||
Show All 11 Lines | private function readRequestParameters() { | ||||
// NOTE: This isn't necessarily a DifferentialChangeset ID, just an | // NOTE: This isn't necessarily a DifferentialChangeset ID, just an | ||||
// application identifier for the changeset. In Diffusion, it's a Path ID. | // application identifier for the changeset. In Diffusion, it's a Path ID. | ||||
$this->changesetID = $request->getInt('changesetID'); | $this->changesetID = $request->getInt('changesetID'); | ||||
$this->isNewFile = (int)$request->getBool('is_new'); | $this->isNewFile = (int)$request->getBool('is_new'); | ||||
$this->isOnRight = $request->getBool('on_right'); | $this->isOnRight = $request->getBool('on_right'); | ||||
$this->lineNumber = $request->getInt('number'); | $this->lineNumber = $request->getInt('number'); | ||||
$this->lineLength = $request->getInt('length'); | $this->lineLength = $request->getInt('length'); | ||||
$this->commentText = $request->getStr('text'); | |||||
$this->commentID = $request->getInt('id'); | $this->commentID = $request->getInt('id'); | ||||
$this->operation = $request->getStr('op'); | $this->operation = $request->getStr('op'); | ||||
$this->renderer = $request->getStr('renderer'); | $this->renderer = $request->getStr('renderer'); | ||||
$this->replyToCommentPHID = $request->getStr('replyToCommentPHID'); | $this->replyToCommentPHID = $request->getStr('replyToCommentPHID'); | ||||
if ($this->getReplyToCommentPHID()) { | if ($this->getReplyToCommentPHID()) { | ||||
$reply_phid = $this->getReplyToCommentPHID(); | $reply_phid = $this->getReplyToCommentPHID(); | ||||
$reply_comment = $this->loadCommentByPHID($reply_phid); | $reply_comment = $this->loadCommentByPHID($reply_phid); | ||||
▲ Show 20 Lines • Show All 147 Lines • ▼ Show 20 Lines | private function loadCommentByQuery( | ||||
if ($inline) { | if ($inline) { | ||||
$inline = $inline->newInlineCommentObject(); | $inline = $inline->newInlineCommentObject(); | ||||
} | } | ||||
return $inline; | return $inline; | ||||
} | } | ||||
private function hasContentState() { | |||||
$request = $this->getRequest(); | |||||
return (bool)$request->getBool('hasContentState'); | |||||
} | |||||
private function getContentState() { | |||||
$request = $this->getRequest(); | |||||
$comment_text = $request->getStr('text'); | |||||
return array( | |||||
'inline.text' => (string)$comment_text, | |||||
); | |||||
} | |||||
private function updateCommentContentState(PhabricatorInlineComment $inline) { | |||||
if (!$this->hasContentState()) { | |||||
throw new Exception( | |||||
pht( | |||||
'Attempting to update comment content state, but request has no '. | |||||
'content state.')); | |||||
} | |||||
$state = $this->getContentState(); | |||||
$text = $state['inline.text']; | |||||
$inline->setContent($text); | |||||
} | |||||
private function saveComment(PhabricatorInlineComment $inline) { | private function saveComment(PhabricatorInlineComment $inline) { | ||||
$viewer = $this->getViewer(); | $viewer = $this->getViewer(); | ||||
$draft_engine = $this->newDraftEngine(); | $draft_engine = $this->newDraftEngine(); | ||||
$inline->openTransaction(); | $inline->openTransaction(); | ||||
$inline->save(); | $inline->save(); | ||||
PhabricatorVersionedDraft::purgeDrafts( | PhabricatorVersionedDraft::purgeDrafts( | ||||
Show All 24 Lines |