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

Make repository identity email address association case-insensitive

Summary:
Ref T13444. Currently, identities for a particular email address are queried with "LIKE" against a binary column, which makes the query case-sensitive.

- Extract the email address into a separate "sort255" column.
- Add a key for it.
- Make the query a standard "IN (%Ls)" query.
- Deal with weird cases where an email address is 10000 bytes long or full of binary junk.

Test Plan:
- Ran migration, inspected database for general sanity.
- Ran query script in T13444, saw it return the same hits for "git@" and "GIT@".

Subscribers: PHID-OPKG-gm6ozazyms6q6i22gyam

Maniphest Tasks: T13444

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

+82 -15
+2
resources/sql/autopatches/20191113.identity.01.email.sql
··· 1 + ALTER TABLE {$NAMESPACE}_repository.repository_identity 2 + ADD emailAddress VARCHAR(255) COLLATE {$COLLATE_SORT};
+26
resources/sql/autopatches/20191113.identity.02.populate.php
··· 1 + <?php 2 + 3 + $table = new PhabricatorRepositoryIdentity(); 4 + $conn = $table->establishConnection('w'); 5 + 6 + $iterator = new LiskRawMigrationIterator($conn, $table->getTableName()); 7 + foreach ($iterator as $row) { 8 + $name = $row['identityNameRaw']; 9 + $name = phutil_utf8ize($name); 10 + 11 + $email = new PhutilEmailAddress($name); 12 + $address = $email->getAddress(); 13 + 14 + try { 15 + queryfx( 16 + $conn, 17 + 'UPDATE %R SET emailAddress = %ns WHERE id = %d', 18 + $table, 19 + $address, 20 + $row['id']); 21 + } catch (Exception $ex) { 22 + // We may occasionally run into issues with binary or very long addresses. 23 + // Just skip over them. 24 + continue; 25 + } 26 + }
+9 -6
src/applications/diffusion/controller/DiffusionIdentityViewController.php
··· 22 22 $header = id(new PHUIHeaderView()) 23 23 ->setUser($viewer) 24 24 ->setHeader($identity->getIdentityShortName()) 25 - ->setHeaderIcon('fa-globe') 26 - ->setPolicyObject($identity); 25 + ->setHeaderIcon('fa-globe'); 27 26 28 27 $crumbs = $this->buildApplicationCrumbs(); 29 - $crumbs->addTextCrumb($identity->getID()); 28 + $crumbs->addTextCrumb($identity->getObjectName()); 30 29 $crumbs->setBorder(true); 31 30 32 31 $timeline = $this->buildTransactionTimeline( ··· 83 82 $viewer = $this->getViewer(); 84 83 85 84 $properties = id(new PHUIPropertyListView()) 86 - ->setUser($viewer); 85 + ->setViewer($viewer); 86 + 87 + $properties->addProperty( 88 + pht('Email Address'), 89 + $identity->getEmailAddress()); 87 90 88 91 $effective_phid = $identity->getCurrentEffectiveUserPHID(); 89 92 $automatic_phid = $identity->getAutomaticGuessedUserPHID(); ··· 109 112 pht('Automatically Detected User'), 110 113 $this->buildPropertyValue($automatic_phid)); 111 114 $properties->addProperty( 112 - pht('Manually Set User'), 115 + pht('Assigned To'), 113 116 $this->buildPropertyValue($manual_phid)); 114 117 115 118 $header = id(new PHUIHeaderView()) ··· 127 130 if ($value == DiffusionIdentityUnassignedDatasource::FUNCTION_TOKEN) { 128 131 return phutil_tag('em', array(), pht('Explicitly Unassigned')); 129 132 } else if (!$value) { 130 - return null; 133 + return phutil_tag('em', array(), pht('None')); 131 134 } else { 132 135 return $viewer->renderHandle($value); 133 136 }
+8
src/applications/diffusion/controller/DiffusionRepositoryListController.php
··· 17 17 ->setName(pht('Browse Commits')) 18 18 ->setHref($this->getApplicationURI('commit/')); 19 19 20 + $items[] = id(new PHUIListItemView()) 21 + ->setType(PHUIListItemView::TYPE_LABEL) 22 + ->setName(pht('Identities')); 23 + 24 + $items[] = id(new PHUIListItemView()) 25 + ->setName(pht('Browse Identities')) 26 + ->setHref($this->getApplicationURI('identity/')); 27 + 20 28 return id(new PhabricatorRepositorySearchEngine()) 21 29 ->setController($this) 22 30 ->setNavigationItems($items)
+6 -7
src/applications/repository/query/PhabricatorRepositoryIdentityQuery.php
··· 6 6 private $ids; 7 7 private $phids; 8 8 private $identityNames; 9 - private $emailAddress; 9 + private $emailAddresses; 10 10 private $assigneePHIDs; 11 11 private $identityNameLike; 12 12 private $hasEffectivePHID; ··· 31 31 return $this; 32 32 } 33 33 34 - public function withEmailAddress($address) { 35 - $this->emailAddress = $address; 34 + public function withEmailAddresses(array $addresses) { 35 + $this->emailAddresses = $addresses; 36 36 return $this; 37 37 } 38 38 ··· 106 106 $name_hashes); 107 107 } 108 108 109 - if ($this->emailAddress !== null) { 110 - $identity_style = "<{$this->emailAddress}>"; 109 + if ($this->emailAddresses !== null) { 111 110 $where[] = qsprintf( 112 111 $conn, 113 - 'repository_identity.identityNameRaw LIKE %<', 114 - $identity_style); 112 + 'repository_identity.emailAddress IN (%Ls)', 113 + $this->emailAddresses); 115 114 } 116 115 117 116 if ($this->identityNameLike != null) {
+30 -1
src/applications/repository/storage/PhabricatorRepositoryIdentity.php
··· 13 13 protected $automaticGuessedUserPHID; 14 14 protected $manuallySetUserPHID; 15 15 protected $currentEffectiveUserPHID; 16 + protected $emailAddress; 16 17 17 18 protected function getConfiguration() { 18 19 return array( ··· 26 27 'automaticGuessedUserPHID' => 'phid?', 27 28 'manuallySetUserPHID' => 'phid?', 28 29 'currentEffectiveUserPHID' => 'phid?', 30 + 'emailAddress' => 'sort255?', 29 31 ), 30 32 self::CONFIG_KEY_SCHEMA => array( 31 33 'key_identity' => array( 32 34 'columns' => array('identityNameHash'), 33 35 'unique' => true, 36 + ), 37 + 'key_email' => array( 38 + 'columns' => array('emailAddress(64)'), 34 39 ), 35 40 ), 36 41 ) + parent::getConfiguration(); ··· 69 74 return $this->getIdentityName(); 70 75 } 71 76 77 + public function getObjectName() { 78 + return pht('Identity %d', $this->getID()); 79 + } 80 + 72 81 public function getURI() { 73 82 return '/diffusion/identity/view/'.$this->getID().'/'; 74 83 } ··· 92 101 $this->currentEffectiveUserPHID = $this->automaticGuessedUserPHID; 93 102 } 94 103 104 + $email_address = $this->getIdentityEmailAddress(); 105 + 106 + // Raw identities are unrestricted binary data, and may consequently 107 + // have arbitrarily long, binary email address information. We can't 108 + // store this kind of information in the "emailAddress" column, which 109 + // has column type "sort255". 110 + 111 + // This kind of address almost certainly not legitimate and users can 112 + // manually set the target of the identity, so just discard it rather 113 + // than trying especially hard to make it work. 114 + 115 + $byte_limit = $this->getColumnMaximumByteLength('emailAddress'); 116 + $email_address = phutil_utf8ize($email_address); 117 + if (strlen($email_address) > $byte_limit) { 118 + $email_address = null; 119 + } 120 + 121 + $this->setEmailAddress($email_address); 122 + 95 123 return parent::save(); 96 124 } 97 125 ··· 111 139 } 112 140 113 141 public function hasAutomaticCapability( 114 - $capability, PhabricatorUser $viewer) { 142 + $capability, 143 + PhabricatorUser $viewer) { 115 144 return false; 116 145 } 117 146
+1 -1
src/applications/repository/worker/PhabricatorRepositoryIdentityChangeWorker.php
··· 21 21 foreach ($emails as $email) { 22 22 $identities = id(new PhabricatorRepositoryIdentityQuery()) 23 23 ->setViewer($viewer) 24 - ->withEmailAddress($email->getAddress()) 24 + ->withEmailAddresses($email->getAddress()) 25 25 ->execute(); 26 26 27 27 foreach ($identities as $identity) {