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

Add unique constraint for Almanac network names

Summary:
The name of networks should be unique.

Also adds support for exact-name queries for AlamanacNetworks.

Test Plan: Applied migration with existing duplicates, saw networks renamed, attempted to add duplicates, got a nice error message.

Reviewers: epriestley

Reviewed By: epriestley

Subscribers: Korvin, PHID-OPKG-gm6ozazyms6q6i22gyam

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

+115 -17
+46
resources/sql/autopatches/20180418.almanac.network.unique.php
··· 1 + <?php 2 + 3 + $table = new AlmanacNetwork(); 4 + $conn = $table->establishConnection('w'); 5 + 6 + queryfx( 7 + $conn, 8 + 'LOCK TABLES %T WRITE', 9 + $table->getTableName()); 10 + 11 + $seen = array(); 12 + foreach (new LiskMigrationIterator($table) as $network) { 13 + $name = $network->getName(); 14 + 15 + // If this is the first copy of this row we've seen, mark it as seen and 16 + // move on. 17 + if (empty($seen[$name])) { 18 + $seen[$name] = 1; 19 + continue; 20 + } 21 + 22 + // Otherwise, rename this row. 23 + while (true) { 24 + $new_name = $name.'-'.$seen[$name]; 25 + if (empty($seen[$new_name])) { 26 + $network->setName($new_name); 27 + try { 28 + $network->save(); 29 + break; 30 + } catch (AphrontDuplicateKeyQueryException $ex) { 31 + // New name is a dupe of a network we haven't seen yet. 32 + } 33 + } 34 + $seen[$name]++; 35 + } 36 + $seen[$new_name] = 1; 37 + } 38 + 39 + queryfx( 40 + $conn, 41 + 'ALTER TABLE %T ADD UNIQUE KEY `key_name` (name)', 42 + $table->getTableName()); 43 + 44 + queryfx( 45 + $conn, 46 + 'UNLOCK TABLES');
+13
src/applications/almanac/query/AlmanacNetworkQuery.php
··· 5 5 6 6 private $ids; 7 7 private $phids; 8 + private $names; 8 9 9 10 public function withIDs(array $ids) { 10 11 $this->ids = $ids; ··· 18 19 19 20 public function newResultObject() { 20 21 return new AlmanacNetwork(); 22 + } 23 + 24 + public function withNames(array $names) { 25 + $this->names = $names; 26 + return $this; 21 27 } 22 28 23 29 public function withNameNgrams($ngrams) { ··· 45 51 $conn, 46 52 'network.phid IN (%Ls)', 47 53 $this->phids); 54 + } 55 + 56 + if ($this->names !== null) { 57 + $where[] = qsprintf( 58 + $conn, 59 + 'network.name IN (%Ls)', 60 + $this->names); 48 61 } 49 62 50 63 return $where;
+8 -1
src/applications/almanac/storage/AlmanacNetwork.php
··· 24 24 return array( 25 25 self::CONFIG_AUX_PHID => true, 26 26 self::CONFIG_COLUMN_SCHEMA => array( 27 - 'name' => 'text128', 27 + 'name' => 'sort128', 28 28 'mailKey' => 'bytes20', 29 + 30 + ), 31 + self::CONFIG_KEY_SCHEMA => array( 32 + 'key_name' => array( 33 + 'columns' => array('name'), 34 + 'unique' => true, 35 + ), 29 36 ), 30 37 ) + parent::getConfiguration(); 31 38 }
+17 -16
src/applications/almanac/util/AlmanacNames.php
··· 6 6 if (strlen($name) < 3) { 7 7 throw new Exception( 8 8 pht( 9 - 'Almanac service, device, property and namespace names must be '. 10 - 'at least 3 characters long.')); 9 + 'Almanac service, device, property, network and namespace names '. 10 + 'must be at least 3 characters long.')); 11 11 } 12 12 13 13 if (strlen($name) > 100) { 14 14 throw new Exception( 15 15 pht( 16 - 'Almanac service, device, property and namespace names may not '. 17 - 'be more than 100 characters long.')); 16 + 'Almanac service, device, property, network and namespace names '. 17 + 'may not be more than 100 characters long.')); 18 18 } 19 19 20 20 if (!preg_match('/^[a-z0-9.-]+\z/', $name)) { 21 21 throw new Exception( 22 22 pht( 23 - 'Almanac service, device, property and namespace names may only '. 24 - 'contain lowercase letters, numbers, hyphens, and periods.')); 23 + 'Almanac service, device, property, network and namespace names '. 24 + 'may only contain lowercase letters, numbers, hyphens, and '. 25 + 'periods.')); 25 26 } 26 27 27 28 if (preg_match('/(^|\\.)\d+(\z|\\.)/', $name)) { 28 29 throw new Exception( 29 30 pht( 30 - 'Almanac service, device, property and namespace names may not '. 31 - 'have any segments containing only digits.')); 31 + 'Almanac service, device, network, property and namespace names '. 32 + 'may not have any segments containing only digits.')); 32 33 } 33 34 34 35 if (preg_match('/\.\./', $name)) { 35 36 throw new Exception( 36 37 pht( 37 - 'Almanac service, device, property and namespace names may not '. 38 - 'contain multiple consecutive periods.')); 38 + 'Almanac service, device, property, network and namespace names '. 39 + 'may not contain multiple consecutive periods.')); 39 40 } 40 41 41 42 if (preg_match('/\\.-|-\\./', $name)) { 42 43 throw new Exception( 43 44 pht( 44 - 'Almanac service, device, property and namespace names may not '. 45 - 'contain hyphens adjacent to periods.')); 45 + 'Almanac service, device, property, network and namespace names '. 46 + 'may not contain hyphens adjacent to periods.')); 46 47 } 47 48 48 49 if (preg_match('/--/', $name)) { 49 50 throw new Exception( 50 51 pht( 51 - 'Almanac service, device, property and namespace names may not '. 52 - 'contain multiple consecutive hyphens.')); 52 + 'Almanac service, device, property, network and namespace names '. 53 + 'may not contain multiple consecutive hyphens.')); 53 54 } 54 55 55 56 if (!preg_match('/^[a-z0-9].*[a-z0-9]\z/', $name)) { 56 57 throw new Exception( 57 58 pht( 58 - 'Almanac service, device, property and namespace names must begin '. 59 - 'and end with a letter or number.')); 59 + 'Almanac service, device, property, network and namespace names '. 60 + 'must begin and end with a letter or number.')); 60 61 } 61 62 } 62 63
+31
src/applications/almanac/xaction/AlmanacNetworkNameTransaction.php
··· 38 38 pht('Network name is required.')); 39 39 } 40 40 41 + foreach ($xactions as $xaction) { 42 + $name = $xaction->getNewValue(); 43 + 44 + $message = null; 45 + try { 46 + AlmanacNames::validateName($name); 47 + } catch (Exception $ex) { 48 + $message = $ex->getMessage(); 49 + } 50 + 51 + if ($message !== null) { 52 + $errors[] = $this->newInvalidError($message, $xaction); 53 + continue; 54 + } 55 + 56 + if ($name === $object->getName()) { 57 + continue; 58 + } 59 + 60 + $other = id(new AlmanacNetworkQuery()) 61 + ->setViewer(PhabricatorUser::getOmnipotentUser()) 62 + ->withNames(array($name)) 63 + ->executeOne(); 64 + if ($other && ($other->getID() != $object->getID())) { 65 + $errors[] = $this->newInvalidError( 66 + pht('Almanac networks must have unique names.'), 67 + $xaction); 68 + continue; 69 + } 70 + } 71 + 41 72 return $errors; 42 73 } 43 74