1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-26 08:42:41 +01:00

Differential - add DifferentialDraft to track whether revisions have draft feedback or not

Summary: ...do it somewhat generically, so we could fairly easily add this to other applications. Fixes T3496. I got a wee bit lazy and decided not to migrate existing drafts. My excuses aside from laziness are doing it this way will let us see if anyone complains, we can always do a migration later if people do complain, and there's likely to be a lot of garbage data for older / bigger installs, and the migration didn't seem worth itgiven it would also likely be expensive in these cases.

Test Plan: made a draft inline comment on DX and observed DX had a note icon on Differential home page. made a draft comment on DX and observed DX had a note icon on Differential home page. deleted a draft inline comment and noted icon disappeared from Differential homepage. Submitted a draft comment + inline comment and noted icon disappeared.

Reviewers: epriestley

Reviewed By: epriestley

CC: Korvin, epriestley, aran

Maniphest Tasks: T3496

Differential Revision: https://secure.phabricator.com/D8275
This commit is contained in:
Bob Trahan 2014-02-18 16:25:16 -08:00
parent b96ab5aadf
commit dcd7a316d2
11 changed files with 152 additions and 50 deletions

View file

@ -0,0 +1,9 @@
CREATE TABLE {$NAMESPACE}_differential.differential_draft(
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
objectPHID VARCHAR(64) NOT NULL COLLATE utf8_bin,
authorPHID VARCHAR(64) NOT NULL COLLATE utf8_bin,
draftKey VARCHAR(64) NOT NULL COLLATE utf8_bin,
dateCreated INT UNSIGNED NOT NULL,
dateModified INT UNSIGNED NOT NULL,
UNIQUE KEY `key_unique` (objectPHID, authorPHID, draftKey)
) ENGINE=InnoDB, COLLATE utf8_general_ci;

View file

@ -378,6 +378,7 @@ phutil_register_library_map(array(
'DifferentialDiffViewController' => 'applications/differential/controller/DifferentialDiffViewController.php', 'DifferentialDiffViewController' => 'applications/differential/controller/DifferentialDiffViewController.php',
'DifferentialDiffViewPolicyFieldSpecification' => 'applications/differential/field/specification/DifferentialDiffViewPolicyFieldSpecification.php', 'DifferentialDiffViewPolicyFieldSpecification' => 'applications/differential/field/specification/DifferentialDiffViewPolicyFieldSpecification.php',
'DifferentialDoorkeeperRevisionFeedStoryPublisher' => 'applications/differential/doorkeeper/DifferentialDoorkeeperRevisionFeedStoryPublisher.php', 'DifferentialDoorkeeperRevisionFeedStoryPublisher' => 'applications/differential/doorkeeper/DifferentialDoorkeeperRevisionFeedStoryPublisher.php',
'DifferentialDraft' => 'applications/differential/storage/DifferentialDraft.php',
'DifferentialEditPolicyFieldSpecification' => 'applications/differential/field/specification/DifferentialEditPolicyFieldSpecification.php', 'DifferentialEditPolicyFieldSpecification' => 'applications/differential/field/specification/DifferentialEditPolicyFieldSpecification.php',
'DifferentialException' => 'applications/differential/exception/DifferentialException.php', 'DifferentialException' => 'applications/differential/exception/DifferentialException.php',
'DifferentialExceptionMail' => 'applications/differential/mail/DifferentialExceptionMail.php', 'DifferentialExceptionMail' => 'applications/differential/mail/DifferentialExceptionMail.php',
@ -2914,6 +2915,7 @@ phutil_register_library_map(array(
'DifferentialDiffViewController' => 'DifferentialController', 'DifferentialDiffViewController' => 'DifferentialController',
'DifferentialDiffViewPolicyFieldSpecification' => 'DifferentialFieldSpecification', 'DifferentialDiffViewPolicyFieldSpecification' => 'DifferentialFieldSpecification',
'DifferentialDoorkeeperRevisionFeedStoryPublisher' => 'DoorkeeperFeedStoryPublisher', 'DifferentialDoorkeeperRevisionFeedStoryPublisher' => 'DoorkeeperFeedStoryPublisher',
'DifferentialDraft' => 'DifferentialDAO',
'DifferentialEditPolicyFieldSpecification' => 'DifferentialFieldSpecification', 'DifferentialEditPolicyFieldSpecification' => 'DifferentialFieldSpecification',
'DifferentialException' => 'Exception', 'DifferentialException' => 'Exception',
'DifferentialExceptionMail' => 'DifferentialMail', 'DifferentialExceptionMail' => 'DifferentialMail',
@ -3957,7 +3959,7 @@ phutil_register_library_map(array(
'PhabricatorCalendarEventOverlapException' => 'Exception', 'PhabricatorCalendarEventOverlapException' => 'Exception',
'PhabricatorCalendarEventQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorCalendarEventQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorCalendarEventSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorCalendarEventSearchEngine' => 'PhabricatorApplicationSearchEngine',
'PhabricatorCalendarEventViewController' => 'PhabricatorDashboardController', 'PhabricatorCalendarEventViewController' => 'PhabricatorCalendarController',
'PhabricatorCalendarHoliday' => 'PhabricatorCalendarDAO', 'PhabricatorCalendarHoliday' => 'PhabricatorCalendarDAO',
'PhabricatorCalendarHolidayTestCase' => 'PhabricatorTestCase', 'PhabricatorCalendarHolidayTestCase' => 'PhabricatorTestCase',
'PhabricatorCalendarPHIDTypeEvent' => 'PhabricatorPHIDType', 'PhabricatorCalendarPHIDTypeEvent' => 'PhabricatorPHIDType',

View file

@ -119,12 +119,24 @@ final class DifferentialCommentPreviewController
$metadata['action'] = $action; $metadata['action'] = $action;
} }
id(new PhabricatorDraft()) $draft_key = 'differential-comment-'.$this->id;
$draft = id(new PhabricatorDraft())
->setAuthorPHID($viewer->getPHID()) ->setAuthorPHID($viewer->getPHID())
->setDraftKey('differential-comment-'.$this->id) ->setDraftKey($draft_key)
->setDraft($request->getStr('content')) ->setDraft($request->getStr('content'))
->setMetadata($metadata) ->setMetadata($metadata)
->replaceOrDelete(); ->replaceOrDelete();
if ($draft->isDeleted()) {
DifferentialDraft::deleteHasDraft(
$viewer->getPHID(),
$revision->getPHID(),
$draft_key);
} else {
DifferentialDraft::markHasDraft(
$viewer->getPHID(),
$revision->getPHID(),
$draft_key);
}
return id(new AphrontAjaxResponse()) return id(new AphrontAjaxResponse())
->setContent((string)phutil_implode_html('', $view->buildEvents())); ->setContent((string)phutil_implode_html('', $view->buildEvents()));

View file

@ -74,13 +74,15 @@ final class DifferentialCommentSaveController extends DifferentialController {
// TODO: Diff change detection? // TODO: Diff change detection?
$user = $request->getUser();
$draft = id(new PhabricatorDraft())->loadOneWhere( $draft = id(new PhabricatorDraft())->loadOneWhere(
'authorPHID = %s AND draftKey = %s', 'authorPHID = %s AND draftKey = %s',
$request->getUser()->getPHID(), $user->getPHID(),
'differential-comment-'.$revision->getID()); 'differential-comment-'.$revision->getID());
if ($draft) { if ($draft) {
$draft->delete(); $draft->delete();
} }
DifferentialDraft::deleteAllDrafts($user->getPHID(), $revision->getPHID());
return id(new AphrontRedirectResponse()) return id(new AphrontRedirectResponse())
->setURI('/D'.$revision->getID()); ->setURI('/D'.$revision->getID());

View file

@ -74,4 +74,23 @@ final class DifferentialInlineCommentEditController
return true; return true;
} }
protected function deleteComment(PhabricatorInlineCommentInterface $inline) {
$inline->openTransaction();
DifferentialDraft::deleteHasDraft(
$inline->getAuthorPHID(),
$inline->getRevisionPHID(),
$inline->getPHID());
$inline->delete();
$inline->saveTransaction();
}
protected function saveComment(PhabricatorInlineCommentInterface $inline) {
$inline->openTransaction();
$inline->save();
DifferentialDraft::markHasDraft(
$inline->getAuthorPHID(),
$inline->getRevisionPHID(),
$inline->getPHID());
$inline->saveTransaction();
}
} }

View file

@ -36,7 +36,6 @@ final class DifferentialRevisionQuery
private $responsibles = array(); private $responsibles = array();
private $branches = array(); private $branches = array();
private $arcanistProjectPHIDs = array(); private $arcanistProjectPHIDs = array();
private $draftRevisions = array();
private $repositoryPHIDs; private $repositoryPHIDs;
private $order = 'order-modified'; private $order = 'order-modified';
@ -468,39 +467,6 @@ final class DifferentialRevisionQuery
$table = new DifferentialRevision(); $table = new DifferentialRevision();
$conn_r = $table->establishConnection('r'); $conn_r = $table->establishConnection('r');
if ($this->draftAuthors) {
$this->draftRevisions = array();
$draft_key = 'differential-comment-';
$drafts = id(new PhabricatorDraft())->loadAllWhere(
'authorPHID IN (%Ls) AND draftKey LIKE %> AND draft != %s',
$this->draftAuthors,
$draft_key,
'');
$len = strlen($draft_key);
foreach ($drafts as $draft) {
$this->draftRevisions[] = substr($draft->getDraftKey(), $len);
}
// TODO: Restore this after drafts are sorted out. It's now very
// expensive to get revision IDs.
/*
$inlines = id(new DifferentialInlineCommentQuery())
->withDraftsByAuthors($this->draftAuthors)
->execute();
foreach ($inlines as $inline) {
$this->draftRevisions[] = $inline->getRevisionID();
}
*/
if (!$this->draftRevisions) {
return array();
}
}
$selects = array(); $selects = array();
// NOTE: If the query includes "responsiblePHIDs", we execute it as a // NOTE: If the query includes "responsiblePHIDs", we execute it as a
@ -632,6 +598,16 @@ final class DifferentialRevisionQuery
$this->reviewers); $this->reviewers);
} }
if ($this->draftAuthors) {
$differential_draft = new DifferentialDraft();
$joins[] = qsprintf(
$conn_r,
'JOIN %T has_draft ON has_draft.objectPHID = r.phid '.
'AND has_draft.authorPHID IN (%Ls)',
$differential_draft->getTableName(),
$this->draftAuthors);
}
$joins = implode(' ', $joins); $joins = implode(' ', $joins);
return $joins; return $joins;
@ -665,13 +641,6 @@ final class DifferentialRevisionQuery
$this->authors); $this->authors);
} }
if ($this->draftRevisions) {
$where[] = qsprintf(
$conn_r,
'r.id IN (%Ld)',
$this->draftRevisions);
}
if ($this->revIDs) { if ($this->revIDs) {
$where[] = qsprintf( $where[] = qsprintf(
$conn_r, $conn_r,

View file

@ -0,0 +1,51 @@
<?php
final class DifferentialDraft extends DifferentialDAO {
protected $objectPHID;
protected $authorPHID;
protected $draftKey;
public static function markHasDraft(
$author_phid,
$object_phid,
$draft_key) {
try {
id(new DifferentialDraft())
->setObjectPHID($object_phid)
->setAuthorPHID($author_phid)
->setDraftKey($draft_key)
->save();
} catch (AphrontQueryDuplicateKeyException $ex) {
// no worries
}
}
public static function deleteHasDraft(
$author_phid,
$object_phid,
$draft_key) {
$draft = id(new DifferentialDraft())->loadOneWhere(
'objectPHID = %s AND authorPHID = %s AND draftKey = %s',
$object_phid,
$author_phid,
$draft_key);
if ($draft) {
$draft->delete();
}
}
public static function deleteAllDrafts(
$author_phid,
$object_phid) {
$drafts = id(new DifferentialDraft())->loadAllWhere(
'objectPHID = %s AND authorPHID = %s',
$object_phid,
$author_phid);
foreach ($drafts as $draft) {
$draft->delete();
}
}
}

View file

@ -28,6 +28,13 @@ final class DifferentialInlineComment
return $this->proxy; return $this->proxy;
} }
public function openTransaction() {
$this->proxy->openTransaction();
}
public function saveTransaction() {
$this->proxy->saveTransaction();
}
public function save() { public function save() {
$this->getTransactionCommentForSave()->save(); $this->getTransactionCommentForSave()->save();
@ -45,6 +52,10 @@ final class DifferentialInlineComment
return $this->proxy->getID(); return $this->proxy->getID();
} }
public function getPHID() {
return $this->proxy->getPHID();
}
public static function newFromModernComment( public static function newFromModernComment(
DifferentialTransactionComment $comment) { DifferentialTransactionComment $comment) {
@ -141,6 +152,10 @@ final class DifferentialInlineComment
return $this; return $this;
} }
public function getRevisionPHID() {
return $this->proxy->getRevisionPHID();
}
// Although these are purely transitional, they're also *extra* dumb. // Although these are purely transitional, they're also *extra* dumb.
public function setRevisionID($revision_id) { public function setRevisionID($revision_id) {

View file

@ -76,4 +76,12 @@ final class DiffusionInlineCommentController
return true; return true;
} }
protected function deleteComment(PhabricatorInlineCommentInterface $inline) {
return $inline->delete();
}
protected function saveComment(PhabricatorInlineCommentInterface $inline) {
return $inline->save();
}
} }

View file

@ -7,6 +7,8 @@ final class PhabricatorDraft extends PhabricatorDraftDAO {
protected $draft; protected $draft;
protected $metadata = array(); protected $metadata = array();
private $deleted = false;
public function getConfiguration() { public function getConfiguration() {
return array( return array(
self::CONFIG_SERIALIZATION => array( self::CONFIG_SERIALIZATION => array(
@ -23,11 +25,20 @@ final class PhabricatorDraft extends PhabricatorDraftDAO {
$this->getTableName(), $this->getTableName(),
$this->authorPHID, $this->authorPHID,
$this->draftKey); $this->draftKey);
$this->deleted = true;
return $this; return $this;
} }
return parent::replace(); return parent::replace();
} }
protected function didDelete() {
$this->deleted = true;
}
public function isDeleted() {
return $this->deleted;
}
public static function newFromUserAndKey(PhabricatorUser $user, $key) { public static function newFromUserAndKey(PhabricatorUser $user, $key) {
if ($user->getPHID() && strlen($key)) { if ($user->getPHID() && strlen($key)) {
$draft = id(new PhabricatorDraft())->loadOneWhere( $draft = id(new PhabricatorDraft())->loadOneWhere(

View file

@ -6,6 +6,10 @@ abstract class PhabricatorInlineCommentController
abstract protected function createComment(); abstract protected function createComment();
abstract protected function loadComment($id); abstract protected function loadComment($id);
abstract protected function loadCommentForEdit($id); abstract protected function loadCommentForEdit($id);
abstract protected function deleteComment(
PhabricatorInlineCommentInterface $inline);
abstract protected function saveComment(
PhabricatorInlineCommentInterface $inline);
private $changesetID; private $changesetID;
private $isNewFile; private $isNewFile;
@ -60,7 +64,7 @@ abstract class PhabricatorInlineCommentController
$inline = $this->loadCommentForEdit($this->getCommentID()); $inline = $this->loadCommentForEdit($this->getCommentID());
if ($request->isFormPost()) { if ($request->isFormPost()) {
$inline->delete(); $this->deleteComment($inline);
return $this->buildEmptyResponse(); return $this->buildEmptyResponse();
} }
@ -86,12 +90,12 @@ abstract class PhabricatorInlineCommentController
if ($request->isFormPost()) { if ($request->isFormPost()) {
if (strlen($text)) { if (strlen($text)) {
$inline->setContent($text); $inline->setContent($text);
$inline->save(); $this->saveComment($inline);
return $this->buildRenderedCommentResponse( return $this->buildRenderedCommentResponse(
$inline, $inline,
$this->getIsOnRight()); $this->getIsOnRight());
} else { } else {
$inline->delete(); $this->deleteComment($inline);
return $this->buildEmptyResponse(); return $this->buildEmptyResponse();
} }
} }
@ -122,8 +126,8 @@ abstract class PhabricatorInlineCommentController
->setLineNumber($this->getLineNumber()) ->setLineNumber($this->getLineNumber())
->setLineLength($this->getLineLength()) ->setLineLength($this->getLineLength())
->setIsNewFile($this->getIsNewFile()) ->setIsNewFile($this->getIsNewFile())
->setContent($text) ->setContent($text);
->save(); $this->saveComment($inline);
return $this->buildRenderedCommentResponse( return $this->buildRenderedCommentResponse(
$inline, $inline,