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:
parent
b96ab5aadf
commit
dcd7a316d2
11 changed files with 152 additions and 50 deletions
9
resources/sql/autopatches/20140218.differentialdraft.sql
Normal file
9
resources/sql/autopatches/20140218.differentialdraft.sql
Normal 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;
|
|
@ -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',
|
||||||
|
|
|
@ -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()));
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
51
src/applications/differential/storage/DifferentialDraft.php
Normal file
51
src/applications/differential/storage/DifferentialDraft.php
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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) {
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Reference in a new issue