@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.

Support edge transactions in ApplicationTransactions

Summary: Fixes T2655. Adds generic support for edge edits (e.g., membership or attached objects).

Test Plan: See next diff.

Reviewers: chad, btrahan

Reviewed By: btrahan

CC: aran

Maniphest Tasks: T2655

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

+234 -4
+24
resources/sql/patches/20130310.xactionmeta.sql
··· 1 + ALTER TABLE `{$NAMESPACE}_file`.`macro_transaction` 2 + ADD metadata LONGTEXT NOT NULL COLLATE utf8_bin; 3 + UPDATE `{$NAMESPACE}_file`.macro_transaction SET metadata = '{}' 4 + WHERE metadata = ''; 5 + 6 + ALTER TABLE `{$NAMESPACE}_pholio`.`pholio_transaction` 7 + ADD metadata LONGTEXT NOT NULL COLLATE utf8_bin; 8 + UPDATE `{$NAMESPACE}_pholio`.pholio_transaction SET metadata = '{}' 9 + WHERE metadata = ''; 10 + 11 + ALTER TABLE `{$NAMESPACE}_config`.`config_transaction` 12 + ADD metadata LONGTEXT NOT NULL COLLATE utf8_bin; 13 + UPDATE `{$NAMESPACE}_config`.config_transaction SET metadata = '{}' 14 + WHERE metadata = ''; 15 + 16 + ALTER TABLE `{$NAMESPACE}_conpherence`.`conpherence_transaction` 17 + ADD metadata LONGTEXT NOT NULL COLLATE utf8_bin; 18 + UPDATE `{$NAMESPACE}_conpherence`.conpherence_transaction SET metadata = '{}' 19 + WHERE metadata = ''; 20 + 21 + ALTER TABLE `{$NAMESPACE}_phlux`.`phlux_transaction` 22 + ADD metadata LONGTEXT NOT NULL COLLATE utf8_bin; 23 + UPDATE `{$NAMESPACE}_phlux`.phlux_transaction SET metadata = '{}' 24 + WHERE metadata = '';
+1 -1
src/applications/conpherence/editor/ConpherenceEditor.php
··· 192 192 return $v; 193 193 case ConpherenceTransactionType::TYPE_FILES: 194 194 case ConpherenceTransactionType::TYPE_PARTICIPANTS: 195 - return $this->mergePHIDTransactions($u, $v); 195 + return $this->mergePHIDOrEdgeTransactions($u, $v); 196 196 } 197 197 198 198 return parent::mergeTransactions($u, $v);
+1
src/applications/transactions/constants/PhabricatorTransactions.php
··· 6 6 const TYPE_SUBSCRIBERS = 'core:subscribers'; 7 7 const TYPE_VIEW_POLICY = 'core:view-policy'; 8 8 const TYPE_EDIT_POLICY = 'core:edit-policy'; 9 + const TYPE_EDGE = 'core:edge'; 9 10 10 11 const COLOR_RED = 'red'; 11 12 const COLOR_ORANGE = 'orange';
+174 -3
src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php
··· 101 101 return $object->getViewPolicy(); 102 102 case PhabricatorTransactions::TYPE_EDIT_POLICY: 103 103 return $object->getEditPolicy(); 104 + case PhabricatorTransactions::TYPE_EDGE: 105 + $edge_type = $xaction->getMetadataValue('edge:type'); 106 + if (!$edge_type) { 107 + throw new Exception("Edge transaction has no 'edge:type'!"); 108 + } 109 + 110 + $old_edges = array(); 111 + if ($object->getPHID()) { 112 + $edge_src = $object->getPHID(); 113 + 114 + $old_edges = id(new PhabricatorEdgeQuery()) 115 + ->setViewer($this->getActor()) 116 + ->withSourcePHIDs(array($edge_src)) 117 + ->withEdgeTypes(array($edge_type)) 118 + ->needEdgeData(true) 119 + ->execute(); 120 + 121 + $old_edges = $old_edges[$edge_src][$edge_type]; 122 + } 123 + return $old_edges; 104 124 default: 105 125 return $this->getCustomTransactionOldValue($object, $xaction); 106 126 } ··· 115 135 case PhabricatorTransactions::TYPE_VIEW_POLICY: 116 136 case PhabricatorTransactions::TYPE_EDIT_POLICY: 117 137 return $xaction->getNewValue(); 138 + case PhabricatorTransactions::TYPE_EDGE: 139 + return $this->getEdgeTransactionNewValue($xaction); 118 140 default: 119 141 return $this->getCustomTransactionNewValue($object, $xaction); 120 142 } ··· 180 202 181 203 $subeditor->save(); 182 204 break; 205 + case PhabricatorTransactions::TYPE_EDGE: 206 + $old = $xaction->getOldValue(); 207 + $new = $xaction->getNewValue(); 208 + $src = $object->getPHID(); 209 + $type = $xaction->getMetadataValue('edge:type'); 210 + 211 + foreach ($new as $dst_phid => $edge) { 212 + $new[$dst_phid]['src'] = $src; 213 + } 214 + 215 + $editor = id(new PhabricatorEdgeEditor()) 216 + ->setActor($this->getActor()); 217 + 218 + foreach ($old as $dst_phid => $edge) { 219 + if (!empty($new[$dst_phid])) { 220 + if ($old[$dst_phid]['data'] === $new[$dst_phid]['data']) { 221 + continue; 222 + } 223 + } 224 + $editor->removeEdge($src, $type, $dst_phid); 225 + } 226 + 227 + foreach ($new as $dst_phid => $edge) { 228 + if (!empty($old[$dst_phid])) { 229 + if ($old[$dst_phid]['data'] === $new[$dst_phid]['data']) { 230 + continue; 231 + } 232 + } 233 + 234 + $data = array( 235 + 'data' => $edge['data'], 236 + ); 237 + 238 + $editor->addEdge($src, $type, $dst_phid, $data); 239 + } 240 + 241 + $editor->save(); 242 + break; 183 243 } 244 + 184 245 return $this->applyCustomExternalTransaction($object, $xaction); 185 246 } 186 247 ··· 460 521 461 522 switch ($type) { 462 523 case PhabricatorTransactions::TYPE_SUBSCRIBERS: 463 - return $this->mergePHIDTransactions($u, $v); 524 + return $this->mergePHIDOrEdgeTransactions($u, $v); 525 + case PhabricatorTransactions::TYPE_EDGE: 526 + $u_type = $u->getMetadataValue('edge:type'); 527 + $v_type = $v->getMetadataValue('edge:type'); 528 + if ($u_type == $v_type) { 529 + return $this->mergePHIDOrEdgeTransactions($u, $v); 530 + } 531 + return null; 464 532 } 465 533 466 534 // By default, do not merge the transactions. ··· 516 584 return array_values($result); 517 585 } 518 586 519 - protected function mergePHIDTransactions( 587 + protected function mergePHIDOrEdgeTransactions( 520 588 PhabricatorApplicationTransaction $u, 521 589 PhabricatorApplicationTransaction $v) { 522 590 ··· 529 597 return $u; 530 598 } 531 599 532 - 533 600 protected function getPHIDTransactionNewValue( 534 601 PhabricatorApplicationTransaction $xaction) { 535 602 ··· 576 643 } 577 644 578 645 return array_values($result); 646 + } 647 + 648 + protected function getEdgeTransactionNewValue( 649 + PhabricatorApplicationTransaction $xaction) { 650 + 651 + $new = $xaction->getNewValue(); 652 + $new_add = idx($new, '+', array()); 653 + unset($new['+']); 654 + $new_rem = idx($new, '-', array()); 655 + unset($new['-']); 656 + $new_set = idx($new, '=', null); 657 + unset($new['=']); 658 + 659 + if ($new) { 660 + throw new Exception( 661 + "Invalid 'new' value for Edge transaction. Value should contain only ". 662 + "keys '+' (add edges), '-' (remove edges) and '=' (set edges)."); 663 + } 664 + 665 + $old = $xaction->getOldValue(); 666 + 667 + $lists = array($new_set, $new_add, $new_rem); 668 + foreach ($lists as $list) { 669 + $this->checkEdgeList($list); 670 + } 671 + 672 + $result = array(); 673 + foreach ($old as $dst_phid => $edge) { 674 + if ($new_set !== null && empty($new_set[$dst_phid])) { 675 + continue; 676 + } 677 + $result[$dst_phid] = $this->normalizeEdgeTransactionValue( 678 + $xaction, 679 + $edge); 680 + } 681 + 682 + if ($new_set !== null) { 683 + foreach ($new_set as $dst_phid => $edge) { 684 + $result[$dst_phid] = $this->normalizeEdgeTransactionValue( 685 + $xaction, 686 + $edge); 687 + } 688 + } 689 + 690 + foreach ($new_add as $dst_phid => $edge) { 691 + $result[$dst_phid] = $this->normalizeEdgeTransactionValue( 692 + $xaction, 693 + $edge); 694 + } 695 + 696 + foreach ($new_rem as $dst_phid => $edge) { 697 + unset($result[$dst_phid]); 698 + } 699 + 700 + return $result; 701 + } 702 + 703 + private function checkEdgeList($list) { 704 + if (!$list) { 705 + return; 706 + } 707 + foreach ($list as $key => $item) { 708 + if (phid_get_type($key) === PhabricatorPHIDConstants::PHID_TYPE_UNKNOWN) { 709 + throw new Exception( 710 + "Edge transactions must have destination PHIDs as in edge ". 711 + "lists (found key '{$key}')."); 712 + } 713 + if (!is_array($item) && $item !== $key) { 714 + throw new Exception( 715 + "Edge transactions must have PHIDs or edge specs as values ". 716 + "(found value '{$item}')."); 717 + } 718 + } 719 + } 720 + 721 + protected function normalizeEdgeTransactionValue( 722 + PhabricatorApplicationTransaction $xaction, 723 + $edge) { 724 + 725 + if (!is_array($edge)) { 726 + $edge = array( 727 + 'dst' => $edge, 728 + ); 729 + } 730 + 731 + $edge_type = $xaction->getMetadataValue('edge:type'); 732 + 733 + if (empty($edge['type'])) { 734 + $edge['type'] = $edge_type; 735 + } else { 736 + if ($edge['type'] != $edge_type) { 737 + $this_type = $edge['type']; 738 + throw new Exception( 739 + "Edge transaction includes edge of type '{$this_type}', but ". 740 + "transaction is of type '{$edge_type}'. Each edge transaction must ". 741 + "alter edges of only one type."); 742 + } 743 + } 744 + 745 + if (!isset($edge['data'])) { 746 + $edge['data'] = null; 747 + } 748 + 749 + return $edge; 579 750 } 580 751 581 752 protected function sortTransactions(array $xactions) {
+30
src/applications/transactions/storage/PhabricatorApplicationTransaction.php
··· 18 18 protected $transactionType; 19 19 protected $oldValue; 20 20 protected $newValue; 21 + protected $metadata = array(); 21 22 22 23 protected $contentSource; 23 24 ··· 36 37 return new PhabricatorApplicationTransactionView(); 37 38 } 38 39 40 + public function getMetadataValue($key, $default = null) { 41 + return idx($this->metadata, $key, $default); 42 + } 43 + 44 + public function setMetadataValue($key, $value) { 45 + $this->metadata[$key] = $value; 46 + return $this; 47 + } 48 + 39 49 public function generatePHID() { 40 50 $type = PhabricatorPHIDConstants::PHID_TYPE_XACT; 41 51 $subtype = $this->getApplicationTransactionType(); ··· 49 59 self::CONFIG_SERIALIZATION => array( 50 60 'oldValue' => self::SERIALIZATION_JSON, 51 61 'newValue' => self::SERIALIZATION_JSON, 62 + 'metadata' => self::SERIALIZATION_JSON, 52 63 ), 53 64 ) + parent::getConfiguration(); 54 65 } ··· 107 118 case PhabricatorTransactions::TYPE_SUBSCRIBERS: 108 119 $phids[] = $old; 109 120 $phids[] = $new; 121 + break; 122 + case PhabricatorTransactions::TYPE_EDGE: 123 + $phids[] = ipull($old, 'dst'); 124 + $phids[] = ipull($new, 'dst'); 110 125 break; 111 126 } 112 127 ··· 160 175 case PhabricatorTransactions::TYPE_VIEW_POLICY: 161 176 case PhabricatorTransactions::TYPE_EDIT_POLICY: 162 177 return 'lock'; 178 + case PhabricatorTransactions::TYPE_EDGE: 179 + return 'link'; 163 180 } 164 181 165 182 return null; ··· 201 218 return pht( 202 219 'All users are already subscribed to this %s.', 203 220 $this->getApplicationObjectTypeName()); 221 + case PhabricatorTransactions::TYPE_EDGE: 222 + return pht('Edges already exist; transaction has no effect.'); 204 223 } 205 224 206 225 return pht('Transaction has no effect.'); ··· 259 278 $this->renderHandleList($rem)); 260 279 } 261 280 break; 281 + case PhabricatorTransactions::TYPE_EDGE: 282 + $type = $this->getMetadata('edge:type'); 283 + return pht( 284 + '%s edited edges of type %s.', 285 + $this->renderHandleLink($author_phid), 286 + $type); 262 287 default: 263 288 return pht( 264 289 '%s edited this %s.', ··· 293 318 case PhabricatorTransactions::TYPE_SUBSCRIBERS: 294 319 return pht( 295 320 '%s updated subscribers of %s.', 321 + $this->renderHandleLink($author_phid), 322 + $this->renderHandleLink($object_phid)); 323 + case PhabricatorTransactions::TYPE_EDGE: 324 + return pht( 325 + '%s updated edges of %s.', 296 326 $this->renderHandleLink($author_phid), 297 327 $this->renderHandleLink($object_phid)); 298 328 }
+4
src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php
··· 1194 1194 'type' => 'sql', 1195 1195 'name' => $this->getPatchPath('20130317.phrictionedge.sql'), 1196 1196 ), 1197 + '20130310.xactionmeta.sql' => array( 1198 + 'type' => 'sql', 1199 + 'name' => $this->getPatchPath('20130310.xactionmeta.sql'), 1200 + ), 1197 1201 ); 1198 1202 } 1199 1203