@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Don't re-mention users for comment edits

Summary:
Ref T11035. This only fixes half of the issue: comment editing has been fixed, but normal transactions which edit things like descriptions haven't yet.

The normal edits aren't fixed because the "oldValues" are populated too late. The code should start working once they get populated sooner, but I don't want to jump the gun on that since it'll probably have some spooky effects. I have some other transaction changes coming down the pipe which should provide a better context for testing "oldValue" population order.

Test Plan:
- Mentioned `@dog` in a comment.
- Removed `@dog` as a subscriber.
- Edited the comment, adding some unrelated text at the end (e.g., fixing a typo).
- Before change: `@dog` re-added as subscriber.
- After change: no re-add.

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T11035

Differential Revision: https://secure.phabricator.com/D16108

+167 -42
+4
src/__phutil_library_map__.php
··· 3591 3591 'PhabricatorTokensCurtainExtension' => 'applications/tokens/engineextension/PhabricatorTokensCurtainExtension.php', 3592 3592 'PhabricatorTokensSettingsPanel' => 'applications/settings/panel/PhabricatorTokensSettingsPanel.php', 3593 3593 'PhabricatorTooltipUIExample' => 'applications/uiexample/examples/PhabricatorTooltipUIExample.php', 3594 + 'PhabricatorTransactionChange' => 'applications/transactions/data/PhabricatorTransactionChange.php', 3595 + 'PhabricatorTransactionRemarkupChange' => 'applications/transactions/data/PhabricatorTransactionRemarkupChange.php', 3594 3596 'PhabricatorTransactions' => 'applications/transactions/constants/PhabricatorTransactions.php', 3595 3597 'PhabricatorTransactionsApplication' => 'applications/transactions/application/PhabricatorTransactionsApplication.php', 3596 3598 'PhabricatorTransactionsDestructionEngineExtension' => 'applications/transactions/engineextension/PhabricatorTransactionsDestructionEngineExtension.php', ··· 8397 8399 'PhabricatorTokensCurtainExtension' => 'PHUICurtainExtension', 8398 8400 'PhabricatorTokensSettingsPanel' => 'PhabricatorSettingsPanel', 8399 8401 'PhabricatorTooltipUIExample' => 'PhabricatorUIExample', 8402 + 'PhabricatorTransactionChange' => 'Phobject', 8403 + 'PhabricatorTransactionRemarkupChange' => 'PhabricatorTransactionChange', 8400 8404 'PhabricatorTransactions' => 'Phobject', 8401 8405 'PhabricatorTransactionsApplication' => 'PhabricatorApplication', 8402 8406 'PhabricatorTransactionsDestructionEngineExtension' => 'PhabricatorDestructionEngineExtension',
+2 -2
src/applications/audit/editor/PhabricatorAuditEditor.php
··· 542 542 protected function expandCustomRemarkupBlockTransactions( 543 543 PhabricatorLiskDAO $object, 544 544 array $xactions, 545 - $blocks, 545 + array $changes, 546 546 PhutilMarkupEngine $engine) { 547 547 548 548 // we are only really trying to find unmentionable phids here... ··· 563 563 return $result; 564 564 } 565 565 566 - $flat_blocks = array_mergev($blocks); 566 + $flat_blocks = mpull($changes, 'getNewValue'); 567 567 $huge_block = implode("\n\n", $flat_blocks); 568 568 $phid_map = array(); 569 569 $phid_map[] = $this->getUnmentionablePHIDMap();
+2 -2
src/applications/differential/editor/DifferentialTransactionEditor.php
··· 1303 1303 protected function expandCustomRemarkupBlockTransactions( 1304 1304 PhabricatorLiskDAO $object, 1305 1305 array $xactions, 1306 - $blocks, 1306 + array $changes, 1307 1307 PhutilMarkupEngine $engine) { 1308 1308 1309 - $flat_blocks = array_mergev($blocks); 1309 + $flat_blocks = mpull($changes, 'getNewValue'); 1310 1310 $huge_block = implode("\n\n", $flat_blocks); 1311 1311 1312 1312 $task_map = array();
+6 -4
src/applications/maniphest/storage/ManiphestTransaction.php
··· 54 54 return parent::shouldGenerateOldValue(); 55 55 } 56 56 57 - public function getRemarkupBlocks() { 58 - $blocks = parent::getRemarkupBlocks(); 57 + protected function newRemarkupChanges() { 58 + $changes = array(); 59 59 60 60 switch ($this->getTransactionType()) { 61 61 case self::TYPE_DESCRIPTION: 62 - $blocks[] = $this->getNewValue(); 62 + $changes[] = $this->newRemarkupChange() 63 + ->setOldValue($this->getOldValue()) 64 + ->setNewValue($this->getNewValue()); 63 65 break; 64 66 } 65 67 66 - return $blocks; 68 + return $changes; 67 69 } 68 70 69 71 public function getRequiredHandlePHIDs() {
+37
src/applications/transactions/data/PhabricatorTransactionChange.php
··· 1 + <?php 2 + 3 + abstract class PhabricatorTransactionChange extends Phobject { 4 + 5 + private $transaction; 6 + private $oldValue; 7 + private $newValue; 8 + 9 + final public function setTransaction( 10 + PhabricatorApplicationTransaction $xaction) { 11 + $this->transaction = $xaction; 12 + return $this; 13 + } 14 + 15 + final public function getTransaction() { 16 + return $this->transaction; 17 + } 18 + 19 + final public function setOldValue($old_value) { 20 + $this->oldValue = $old_value; 21 + return $this; 22 + } 23 + 24 + final public function getOldValue() { 25 + return $this->oldValue; 26 + } 27 + 28 + final public function setNewValue($new_value) { 29 + $this->newValue = $new_value; 30 + return $this; 31 + } 32 + 33 + final public function getNewValue() { 34 + return $this->newValue; 35 + } 36 + 37 + }
+4
src/applications/transactions/data/PhabricatorTransactionRemarkupChange.php
··· 1 + <?php 2 + 3 + final class PhabricatorTransactionRemarkupChange 4 + extends PhabricatorTransactionChange {}
+3
src/applications/transactions/editor/PhabricatorApplicationTransactionCommentEditor.php
··· 64 64 $comment->setTransactionPHID($xaction->getPHID()); 65 65 $comment->save(); 66 66 67 + $old_comment = $xaction->getComment(); 68 + $comment->attachOldComment($old_comment); 69 + 67 70 $xaction->setCommentVersion($new_version); 68 71 $xaction->setCommentPHID($comment->getPHID()); 69 72 $xaction->setViewPolicy($comment->getViewPolicy());
+49 -30
src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php
··· 1320 1320 private function buildSubscribeTransaction( 1321 1321 PhabricatorLiskDAO $object, 1322 1322 array $xactions, 1323 - array $blocks) { 1323 + array $changes) { 1324 1324 1325 1325 if (!($object instanceof PhabricatorSubscribableInterface)) { 1326 1326 return null; 1327 1327 } 1328 1328 1329 1329 if ($this->shouldEnableMentions($object, $xactions)) { 1330 - $texts = array_mergev($blocks); 1331 - $phids = PhabricatorMarkupEngine::extractPHIDsFromMentions( 1330 + // Identify newly mentioned users. We ignore users who were previously 1331 + // mentioned so that we don't re-subscribe users after an edit of text 1332 + // which mentions them. 1333 + $old_texts = mpull($changes, 'getOldValue'); 1334 + $new_texts = mpull($changes, 'getNewValue'); 1335 + 1336 + $old_phids = PhabricatorMarkupEngine::extractPHIDsFromMentions( 1332 1337 $this->getActor(), 1333 - $texts); 1338 + $old_texts); 1339 + 1340 + $new_phids = PhabricatorMarkupEngine::extractPHIDsFromMentions( 1341 + $this->getActor(), 1342 + $new_texts); 1343 + 1344 + $phids = array_diff($new_phids, $old_phids); 1334 1345 } else { 1335 1346 $phids = array(); 1336 1347 } ··· 1379 1390 $xaction->setNewValue(array('+' => $phids)); 1380 1391 1381 1392 return $xaction; 1382 - } 1383 - 1384 - protected function getRemarkupBlocksFromTransaction( 1385 - PhabricatorApplicationTransaction $transaction) { 1386 - return $transaction->getRemarkupBlocks(); 1387 1393 } 1388 1394 1389 1395 protected function mergeTransactions( ··· 1464 1470 1465 1471 $xactions = $this->applyImplicitCC($object, $xactions); 1466 1472 1467 - $blocks = array(); 1468 - foreach ($xactions as $key => $xaction) { 1469 - $blocks[$key] = $this->getRemarkupBlocksFromTransaction($xaction); 1470 - } 1473 + $changes = $this->getRemarkupChanges($xactions); 1471 1474 1472 1475 $subscribe_xaction = $this->buildSubscribeTransaction( 1473 1476 $object, 1474 1477 $xactions, 1475 - $blocks); 1478 + $changes); 1476 1479 if ($subscribe_xaction) { 1477 1480 $xactions[] = $subscribe_xaction; 1478 1481 } ··· 1484 1487 $block_xactions = $this->expandRemarkupBlockTransactions( 1485 1488 $object, 1486 1489 $xactions, 1487 - $blocks, 1490 + $changes, 1488 1491 $engine); 1489 1492 1490 1493 foreach ($block_xactions as $xaction) { ··· 1494 1497 return $xactions; 1495 1498 } 1496 1499 1500 + private function getRemarkupChanges(array $xactions) { 1501 + $changes = array(); 1502 + 1503 + foreach ($xactions as $key => $xaction) { 1504 + foreach ($this->getRemarkupChangesFromTransaction($xaction) as $change) { 1505 + $changes[] = $change; 1506 + } 1507 + } 1508 + 1509 + return $changes; 1510 + } 1511 + 1512 + private function getRemarkupChangesFromTransaction( 1513 + PhabricatorApplicationTransaction $transaction) { 1514 + return $transaction->getRemarkupChanges(); 1515 + } 1516 + 1497 1517 private function expandRemarkupBlockTransactions( 1498 1518 PhabricatorLiskDAO $object, 1499 1519 array $xactions, 1500 - $blocks, 1520 + array $changes, 1501 1521 PhutilMarkupEngine $engine) { 1502 1522 1503 1523 $block_xactions = $this->expandCustomRemarkupBlockTransactions( 1504 1524 $object, 1505 1525 $xactions, 1506 - $blocks, 1526 + $changes, 1507 1527 $engine); 1508 1528 1509 1529 $mentioned_phids = array(); 1510 1530 if ($this->shouldEnableMentions($object, $xactions)) { 1511 - foreach ($blocks as $key => $xaction_blocks) { 1512 - foreach ($xaction_blocks as $block) { 1513 - $engine->markupText($block); 1514 - $mentioned_phids += $engine->getTextMetadata( 1515 - PhabricatorObjectRemarkupRule::KEY_MENTIONED_OBJECTS, 1516 - array()); 1517 - } 1531 + foreach ($changes as $change) { 1532 + // Here, we don't care about processing only new mentions after an edit 1533 + // because there is no way for an object to ever "unmention" itself on 1534 + // another object, so we can ignore the old value. 1535 + $engine->markupText($change->getNewValue()); 1536 + 1537 + $mentioned_phids += $engine->getTextMetadata( 1538 + PhabricatorObjectRemarkupRule::KEY_MENTIONED_OBJECTS, 1539 + array()); 1518 1540 } 1519 1541 } 1520 1542 ··· 1559 1581 protected function expandCustomRemarkupBlockTransactions( 1560 1582 PhabricatorLiskDAO $object, 1561 1583 array $xactions, 1562 - $blocks, 1584 + array $changes, 1563 1585 PhutilMarkupEngine $engine) { 1564 1586 return array(); 1565 1587 } ··· 3096 3118 PhabricatorLiskDAO $object, 3097 3119 array $xactions) { 3098 3120 3099 - $blocks = array(); 3100 - foreach ($xactions as $xaction) { 3101 - $blocks[] = $this->getRemarkupBlocksFromTransaction($xaction); 3102 - } 3103 - $blocks = array_mergev($blocks); 3121 + $changes = $this->getRemarkupChanges($xactions); 3122 + $blocks = mpull($changes, 'getNewValue'); 3104 3123 3105 3124 $phids = array(); 3106 3125 if ($blocks) {
+44 -4
src/applications/transactions/storage/PhabricatorApplicationTransaction.php
··· 179 179 return $this->assertAttached($this->object); 180 180 } 181 181 182 + public function getRemarkupChanges() { 183 + $changes = $this->newRemarkupChanges(); 184 + assert_instances_of($changes, 'PhabricatorTransactionRemarkupChange'); 185 + 186 + // Convert older-style remarkup blocks into newer-style remarkup changes. 187 + // This builds changes that do not have the correct "old value", so rules 188 + // that operate differently against edits (like @user mentions) won't work 189 + // properly. 190 + foreach ($this->getRemarkupBlocks() as $block) { 191 + $changes[] = $this->newRemarkupChange() 192 + ->setOldValue(null) 193 + ->setNewValue($block); 194 + } 195 + 196 + $comment = $this->getComment(); 197 + if ($comment) { 198 + if ($comment->hasOldComment()) { 199 + $old_value = $comment->getOldComment()->getContent(); 200 + } else { 201 + $old_value = null; 202 + } 203 + 204 + $new_value = $comment->getContent(); 205 + 206 + $changes[] = $this->newRemarkupChange() 207 + ->setOldValue($old_value) 208 + ->setNewValue($new_value); 209 + } 210 + 211 + return $changes; 212 + } 213 + 214 + protected function newRemarkupChanges() { 215 + return array(); 216 + } 217 + 218 + protected function newRemarkupChange() { 219 + return id(new PhabricatorTransactionRemarkupChange()) 220 + ->setTransaction($this); 221 + } 222 + 223 + /** 224 + * @deprecated 225 + */ 182 226 public function getRemarkupBlocks() { 183 227 $blocks = array(); 184 228 ··· 193 237 } 194 238 } 195 239 break; 196 - } 197 - 198 - if ($this->getComment()) { 199 - $blocks[] = $this->getComment()->getContent(); 200 240 } 201 241 202 242 return $blocks;
+16
src/applications/transactions/storage/PhabricatorApplicationTransactionComment.php
··· 18 18 protected $contentSource; 19 19 protected $isDeleted = 0; 20 20 21 + private $oldComment = self::ATTACHABLE; 22 + 21 23 abstract public function getApplicationTransactionObject(); 22 24 23 25 public function generatePHID() { ··· 83 85 $this->setIsDeleted(0); 84 86 } 85 87 return $this; 88 + } 89 + 90 + public function attachOldComment( 91 + PhabricatorApplicationTransactionComment $old_comment) { 92 + $this->oldComment = $old_comment; 93 + return $this; 94 + } 95 + 96 + public function getOldComment() { 97 + return $this->assertAttached($this->oldComment); 98 + } 99 + 100 + public function hasOldComment() { 101 + return ($this->oldComment !== self::ATTACHABLE); 86 102 } 87 103 88 104