@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

Add a Packages application and PackagePublisher

Summary:
Ref T8116. Partially scavenged from D14152. This roughs in a new Packages application for Arcanist extensions and third-party applications, and adds a "Publisher" object.

A "Publisher" represents an individual or entity who is publishing a package, like "Phacility". It's explicitly //not// necessarily the original author -- just the primary entity vouching for the safety of the code.

A publisher just has a name and a unique key for now. For example, Phacility might have "Phacility" and "phacility", respectively.

Unique keys are immutable, e.g., the package "phacility/arcanist" will always be exactly the same package by exactly the same publisher.

Test Plan: {F1731621}

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T8116

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

+1011
+11
resources/sql/autopatches/20160721.pack.01.pub.sql
··· 1 + CREATE TABLE {$NAMESPACE}_packages.packages_publisher ( 2 + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, 3 + phid VARBINARY(64) NOT NULL, 4 + name VARCHAR(64) NOT NULL COLLATE {$COLLATE_TEXT}, 5 + publisherKey VARCHAR(64) NOT NULL COLLATE {$COLLATE_SORT}, 6 + editPolicy VARBINARY(64) NOT NULL, 7 + dateCreated INT UNSIGNED NOT NULL, 8 + dateModified INT UNSIGNED NOT NULL, 9 + UNIQUE KEY `key_phid` (phid), 10 + UNIQUE KEY `key_publisher` (publisherKey) 11 + ) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};
+19
resources/sql/autopatches/20160721.pack.02.pubxaction.sql
··· 1 + CREATE TABLE {$NAMESPACE}_packages.packages_publishertransaction ( 2 + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, 3 + phid VARBINARY(64) NOT NULL, 4 + authorPHID VARBINARY(64) NOT NULL, 5 + objectPHID VARBINARY(64) NOT NULL, 6 + viewPolicy VARBINARY(64) NOT NULL, 7 + editPolicy VARBINARY(64) NOT NULL, 8 + commentPHID VARBINARY(64) DEFAULT NULL, 9 + commentVersion INT UNSIGNED NOT NULL, 10 + transactionType VARCHAR(32) COLLATE {$COLLATE_TEXT} NOT NULL, 11 + oldValue LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL, 12 + newValue LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL, 13 + contentSource LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL, 14 + metadata LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL, 15 + dateCreated INT UNSIGNED NOT NULL, 16 + dateModified INT UNSIGNED NOT NULL, 17 + UNIQUE KEY `key_phid` (`phid`), 18 + KEY `key_object` (`objectPHID`) 19 + ) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};
+16
resources/sql/autopatches/20160721.pack.03.edge.sql
··· 1 + CREATE TABLE {$NAMESPACE}_packages.edge ( 2 + src VARBINARY(64) NOT NULL, 3 + type INT UNSIGNED NOT NULL, 4 + dst VARBINARY(64) NOT NULL, 5 + dateCreated INT UNSIGNED NOT NULL, 6 + seq INT UNSIGNED NOT NULL, 7 + dataID INT UNSIGNED, 8 + PRIMARY KEY (src, type, dst), 9 + KEY `src` (src, type, dateCreated, seq), 10 + UNIQUE KEY `key_dst` (dst, type, src) 11 + ) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT}; 12 + 13 + CREATE TABLE {$NAMESPACE}_packages.edgedata ( 14 + id INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, 15 + data LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT} 16 + ) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};
+56
src/__phutil_library_map__.php
··· 2972 2972 'PhabricatorPHPASTApplication' => 'applications/phpast/application/PhabricatorPHPASTApplication.php', 2973 2973 'PhabricatorPHPConfigSetupCheck' => 'applications/config/check/PhabricatorPHPConfigSetupCheck.php', 2974 2974 'PhabricatorPHPMailerConfigOptions' => 'applications/config/option/PhabricatorPHPMailerConfigOptions.php', 2975 + 'PhabricatorPackagesApplication' => 'applications/packages/application/PhabricatorPackagesApplication.php', 2976 + 'PhabricatorPackagesController' => 'applications/packages/controller/PhabricatorPackagesController.php', 2977 + 'PhabricatorPackagesDAO' => 'applications/packages/storage/PhabricatorPackagesDAO.php', 2978 + 'PhabricatorPackagesEditEngine' => 'applications/packages/editor/PhabricatorPackagesEditEngine.php', 2979 + 'PhabricatorPackagesEditor' => 'applications/packages/editor/PhabricatorPackagesEditor.php', 2980 + 'PhabricatorPackagesPublisher' => 'applications/packages/storage/PhabricatorPackagesPublisher.php', 2981 + 'PhabricatorPackagesPublisherController' => 'applications/packages/controller/PhabricatorPackagesPublisherController.php', 2982 + 'PhabricatorPackagesPublisherEditConduitAPIMethod' => 'applications/packages/conduit/PhabricatorPackagesPublisherEditConduitAPIMethod.php', 2983 + 'PhabricatorPackagesPublisherEditController' => 'applications/packages/controller/PhabricatorPackagesPublisherEditController.php', 2984 + 'PhabricatorPackagesPublisherEditEngine' => 'applications/packages/editor/PhabricatorPackagesPublisherEditEngine.php', 2985 + 'PhabricatorPackagesPublisherEditor' => 'applications/packages/editor/PhabricatorPackagesPublisherEditor.php', 2986 + 'PhabricatorPackagesPublisherKeyTransaction' => 'applications/packages/xaction/publisher/PhabricatorPackagesPublisherKeyTransaction.php', 2987 + 'PhabricatorPackagesPublisherListController' => 'applications/packages/controller/PhabricatorPackagesPublisherListController.php', 2988 + 'PhabricatorPackagesPublisherNameTransaction' => 'applications/packages/xaction/publisher/PhabricatorPackagesPublisherNameTransaction.php', 2989 + 'PhabricatorPackagesPublisherPHIDType' => 'applications/packages/phid/PhabricatorPackagesPublisherPHIDType.php', 2990 + 'PhabricatorPackagesPublisherQuery' => 'applications/packages/query/PhabricatorPackagesPublisherQuery.php', 2991 + 'PhabricatorPackagesPublisherSearchConduitAPIMethod' => 'applications/packages/conduit/PhabricatorPackagesPublisherSearchConduitAPIMethod.php', 2992 + 'PhabricatorPackagesPublisherSearchEngine' => 'applications/packages/query/PhabricatorPackagesPublisherSearchEngine.php', 2993 + 'PhabricatorPackagesPublisherTransaction' => 'applications/packages/storage/PhabricatorPackagesPublisherTransaction.php', 2994 + 'PhabricatorPackagesPublisherTransactionQuery' => 'applications/packages/query/PhabricatorPackagesPublisherTransactionQuery.php', 2995 + 'PhabricatorPackagesPublisherTransactionType' => 'applications/packages/xaction/publisher/PhabricatorPackagesPublisherTransactionType.php', 2996 + 'PhabricatorPackagesPublisherViewController' => 'applications/packages/controller/PhabricatorPackagesPublisherViewController.php', 2997 + 'PhabricatorPackagesSchemaSpec' => 'applications/packages/storage/PhabricatorPackagesSchemaSpec.php', 2998 + 'PhabricatorPackagesTransactionType' => 'applications/packages/xaction/PhabricatorPackagesTransactionType.php', 2975 2999 'PhabricatorPagerUIExample' => 'applications/uiexample/examples/PhabricatorPagerUIExample.php', 2976 3000 'PhabricatorPassphraseApplication' => 'applications/passphrase/application/PhabricatorPassphraseApplication.php', 2977 3001 'PhabricatorPasswordAuthProvider' => 'applications/auth/provider/PhabricatorPasswordAuthProvider.php', ··· 7725 7749 'PhabricatorPHPASTApplication' => 'PhabricatorApplication', 7726 7750 'PhabricatorPHPConfigSetupCheck' => 'PhabricatorSetupCheck', 7727 7751 'PhabricatorPHPMailerConfigOptions' => 'PhabricatorApplicationConfigOptions', 7752 + 'PhabricatorPackagesApplication' => 'PhabricatorApplication', 7753 + 'PhabricatorPackagesController' => 'PhabricatorController', 7754 + 'PhabricatorPackagesDAO' => 'PhabricatorLiskDAO', 7755 + 'PhabricatorPackagesEditEngine' => 'PhabricatorEditEngine', 7756 + 'PhabricatorPackagesEditor' => 'PhabricatorApplicationTransactionEditor', 7757 + 'PhabricatorPackagesPublisher' => array( 7758 + 'PhabricatorPackagesDAO', 7759 + 'PhabricatorPolicyInterface', 7760 + 'PhabricatorApplicationTransactionInterface', 7761 + 'PhabricatorDestructibleInterface', 7762 + 'PhabricatorSubscribableInterface', 7763 + 'PhabricatorProjectInterface', 7764 + 'PhabricatorConduitResultInterface', 7765 + ), 7766 + 'PhabricatorPackagesPublisherController' => 'PhabricatorPackagesController', 7767 + 'PhabricatorPackagesPublisherEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod', 7768 + 'PhabricatorPackagesPublisherEditController' => 'PhabricatorPackagesPublisherController', 7769 + 'PhabricatorPackagesPublisherEditEngine' => 'PhabricatorPackagesEditEngine', 7770 + 'PhabricatorPackagesPublisherEditor' => 'PhabricatorPackagesEditor', 7771 + 'PhabricatorPackagesPublisherKeyTransaction' => 'PhabricatorPackagesPublisherTransactionType', 7772 + 'PhabricatorPackagesPublisherListController' => 'PhabricatorPackagesPublisherController', 7773 + 'PhabricatorPackagesPublisherNameTransaction' => 'PhabricatorPackagesPublisherTransactionType', 7774 + 'PhabricatorPackagesPublisherPHIDType' => 'PhabricatorPHIDType', 7775 + 'PhabricatorPackagesPublisherQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 7776 + 'PhabricatorPackagesPublisherSearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod', 7777 + 'PhabricatorPackagesPublisherSearchEngine' => 'PhabricatorApplicationSearchEngine', 7778 + 'PhabricatorPackagesPublisherTransaction' => 'PhabricatorModularTransaction', 7779 + 'PhabricatorPackagesPublisherTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 7780 + 'PhabricatorPackagesPublisherTransactionType' => 'PhabricatorPackagesTransactionType', 7781 + 'PhabricatorPackagesPublisherViewController' => 'PhabricatorPackagesPublisherController', 7782 + 'PhabricatorPackagesSchemaSpec' => 'PhabricatorConfigSchemaSpec', 7783 + 'PhabricatorPackagesTransactionType' => 'PhabricatorModularTransactionType', 7728 7784 'PhabricatorPagerUIExample' => 'PhabricatorUIExample', 7729 7785 'PhabricatorPassphraseApplication' => 'PhabricatorApplication', 7730 7786 'PhabricatorPasswordAuthProvider' => 'PhabricatorAuthProvider',
+47
src/applications/packages/application/PhabricatorPackagesApplication.php
··· 1 + <?php 2 + 3 + final class PhabricatorPackagesApplication extends PhabricatorApplication { 4 + 5 + public function getName() { 6 + return pht('Packages'); 7 + } 8 + 9 + public function getShortDescription() { 10 + return pht('Publish Software'); 11 + } 12 + 13 + public function getFlavorText() { 14 + return pht('Applications and Extensions'); 15 + } 16 + 17 + public function getBaseURI() { 18 + return '/packages/'; 19 + } 20 + 21 + public function getIcon() { 22 + return 'fa-gift'; 23 + } 24 + 25 + public function isPrototype() { 26 + return true; 27 + } 28 + 29 + public function getRoutes() { 30 + return array( 31 + '/package/' => array( 32 + '(?P<publisherKey>[^/]+)/' => array( 33 + '' => 'PhabricatorPackagesPublisherViewController', 34 + ), 35 + ), 36 + '/packages/' => array( 37 + 'publisher/' => array( 38 + $this->getQueryRoutePattern() => 39 + 'PhabricatorPackagesPublisherListController', 40 + $this->getEditRoutePattern('edit/') => 41 + 'PhabricatorPackagesPublisherEditController', 42 + ), 43 + ), 44 + ); 45 + } 46 + 47 + }
+19
src/applications/packages/conduit/PhabricatorPackagesPublisherEditConduitAPIMethod.php
··· 1 + <?php 2 + 3 + final class PhabricatorPackagesPublisherEditConduitAPIMethod 4 + extends PhabricatorEditEngineAPIMethod { 5 + 6 + public function getAPIMethodName() { 7 + return 'packages.publisher.edit'; 8 + } 9 + 10 + public function newEditEngine() { 11 + return new PhabricatorPackagesPublisherEditEngine(); 12 + } 13 + 14 + public function getMethodSummary() { 15 + return pht( 16 + 'Apply transactions to create a new publisher or edit an existing one.'); 17 + } 18 + 19 + }
+18
src/applications/packages/conduit/PhabricatorPackagesPublisherSearchConduitAPIMethod.php
··· 1 + <?php 2 + 3 + final class PhabricatorPackagesPublisherSearchConduitAPIMethod 4 + extends PhabricatorSearchEngineAPIMethod { 5 + 6 + public function getAPIMethodName() { 7 + return 'packages.publisher.search'; 8 + } 9 + 10 + public function newSearchEngine() { 11 + return new PhabricatorPackagesPublisherSearchEngine(); 12 + } 13 + 14 + public function getMethodSummary() { 15 + return pht('Read information about publishers.'); 16 + } 17 + 18 + }
+3
src/applications/packages/controller/PhabricatorPackagesController.php
··· 1 + <?php 2 + 3 + abstract class PhabricatorPackagesController extends PhabricatorController {}
+4
src/applications/packages/controller/PhabricatorPackagesPublisherController.php
··· 1 + <?php 2 + 3 + abstract class PhabricatorPackagesPublisherController 4 + extends PhabricatorPackagesController {}
+12
src/applications/packages/controller/PhabricatorPackagesPublisherEditController.php
··· 1 + <?php 2 + 3 + final class PhabricatorPackagesPublisherEditController 4 + extends PhabricatorPackagesPublisherController { 5 + 6 + public function handleRequest(AphrontRequest $request) { 7 + return id(new PhabricatorPackagesPublisherEditEngine()) 8 + ->setController($this) 9 + ->buildResponse(); 10 + } 11 + 12 + }
+26
src/applications/packages/controller/PhabricatorPackagesPublisherListController.php
··· 1 + <?php 2 + 3 + final class PhabricatorPackagesPublisherListController 4 + extends PhabricatorPackagesPublisherController { 5 + 6 + public function shouldAllowPublic() { 7 + return true; 8 + } 9 + 10 + public function handleRequest(AphrontRequest $request) { 11 + return id(new PhabricatorPackagesPublisherSearchEngine()) 12 + ->setController($this) 13 + ->buildResponse(); 14 + } 15 + 16 + protected function buildApplicationCrumbs() { 17 + $crumbs = parent::buildApplicationCrumbs(); 18 + 19 + id(new PhabricatorPackagesPublisherEditEngine()) 20 + ->setViewer($this->getViewer()) 21 + ->addActionToCrumbs($crumbs); 22 + 23 + return $crumbs; 24 + } 25 + 26 + }
+84
src/applications/packages/controller/PhabricatorPackagesPublisherViewController.php
··· 1 + <?php 2 + 3 + final class PhabricatorPackagesPublisherViewController 4 + extends PhabricatorPackagesPublisherController { 5 + 6 + public function shouldAllowPublic() { 7 + return true; 8 + } 9 + 10 + public function handleRequest(AphrontRequest $request) { 11 + $viewer = $request->getViewer(); 12 + $publisher_key = $request->getURIData('publisherKey'); 13 + 14 + $publisher = id(new PhabricatorPackagesPublisherQuery()) 15 + ->setViewer($viewer) 16 + ->withPublisherKeys(array($publisher_key)) 17 + ->executeOne(); 18 + if (!$publisher) { 19 + return new Aphront404Response(); 20 + } 21 + 22 + $crumbs = $this->buildApplicationCrumbs() 23 + ->addTextCrumb( 24 + pht('Publishers'), 25 + $this->getApplicationURI('publisher/')) 26 + ->addTextCrumb($publisher->getName()) 27 + ->setBorder(true); 28 + 29 + $header = $this->buildHeaderView($publisher); 30 + $curtain = $this->buildCurtain($publisher); 31 + 32 + $timeline = $this->buildTransactionTimeline( 33 + $publisher, 34 + new PhabricatorPackagesPublisherTransactionQuery()); 35 + 36 + $publisher_view = id(new PHUITwoColumnView()) 37 + ->setHeader($header) 38 + ->setCurtain($curtain) 39 + ->setMainColumn($timeline); 40 + 41 + return $this->newPage() 42 + ->setCrumbs($crumbs) 43 + ->setPageObjectPHIDs( 44 + array( 45 + $publisher->getPHID(), 46 + )) 47 + ->appendChild($publisher_view); 48 + } 49 + 50 + 51 + private function buildHeaderView(PhabricatorPackagesPublisher $publisher) { 52 + $viewer = $this->getViewer(); 53 + $name = $publisher->getName(); 54 + 55 + return id(new PHUIHeaderView()) 56 + ->setViewer($viewer) 57 + ->setHeader($name) 58 + ->setPolicyObject($publisher) 59 + ->setHeaderIcon('fa-paw'); 60 + } 61 + 62 + private function buildCurtain(PhabricatorPackagesPublisher $publisher) { 63 + $viewer = $this->getViewer(); 64 + $curtain = $this->newCurtainView($publisher); 65 + 66 + $can_edit = PhabricatorPolicyFilter::hasCapability( 67 + $viewer, 68 + $publisher, 69 + PhabricatorPolicyCapability::CAN_EDIT); 70 + 71 + $id = $publisher->getID(); 72 + $edit_uri = $this->getApplicationURI("publisher/edit/{$id}/"); 73 + 74 + $curtain->addAction( 75 + id(new PhabricatorActionView()) 76 + ->setName(pht('Edit Publisher')) 77 + ->setIcon('fa-pencil') 78 + ->setDisabled(!$can_edit) 79 + ->setHref($edit_uri)); 80 + 81 + return $curtain; 82 + } 83 + 84 + }
+14
src/applications/packages/editor/PhabricatorPackagesEditEngine.php
··· 1 + <?php 2 + 3 + abstract class PhabricatorPackagesEditEngine 4 + extends PhabricatorEditEngine { 5 + 6 + public function isEngineConfigurable() { 7 + return false; 8 + } 9 + 10 + public function getEngineApplicationClass() { 11 + return 'PhabricatorPackagesApplication'; 12 + } 13 + 14 + }
+10
src/applications/packages/editor/PhabricatorPackagesEditor.php
··· 1 + <?php 2 + 3 + abstract class PhabricatorPackagesEditor 4 + extends PhabricatorApplicationTransactionEditor { 5 + 6 + public function getEditorApplicationClass() { 7 + return 'PhabricatorPasteApplication'; 8 + } 9 + 10 + }
+91
src/applications/packages/editor/PhabricatorPackagesPublisherEditEngine.php
··· 1 + <?php 2 + 3 + final class PhabricatorPackagesPublisherEditEngine 4 + extends PhabricatorPackagesEditEngine { 5 + 6 + const ENGINECONST = 'packages.publisher'; 7 + 8 + public function getEngineName() { 9 + return pht('Package Publishers'); 10 + } 11 + 12 + public function getSummaryHeader() { 13 + return pht('Edit Package Publisher Configurations'); 14 + } 15 + 16 + public function getSummaryText() { 17 + return pht('This engine is used to edit Packages publishers.'); 18 + } 19 + 20 + protected function newEditableObject() { 21 + $viewer = $this->getViewer(); 22 + return PhabricatorPackagesPublisher::initializeNewPublisher($viewer); 23 + } 24 + 25 + protected function newObjectQuery() { 26 + return new PhabricatorPackagesPublisherQuery(); 27 + } 28 + 29 + protected function getObjectCreateTitleText($object) { 30 + return pht('Create Publisher'); 31 + } 32 + 33 + protected function getObjectCreateButtonText($object) { 34 + return pht('Create Publisher'); 35 + } 36 + 37 + protected function getObjectEditTitleText($object) { 38 + return pht('Edit Publisher: %s', $object->getName()); 39 + } 40 + 41 + protected function getObjectEditShortText($object) { 42 + return pht('Edit Publisher'); 43 + } 44 + 45 + protected function getObjectCreateShortText() { 46 + return pht('Create Publisher'); 47 + } 48 + 49 + protected function getObjectName() { 50 + return pht('Publisher'); 51 + } 52 + 53 + protected function getEditorURI() { 54 + return '/packages/publisher/edit/'; 55 + } 56 + 57 + protected function getObjectCreateCancelURI($object) { 58 + return '/packages/publisher/'; 59 + } 60 + 61 + protected function getObjectViewURI($object) { 62 + return $object->getURI(); 63 + } 64 + 65 + protected function buildCustomEditFields($object) { 66 + $fields = array(); 67 + 68 + $fields[] = id(new PhabricatorTextEditField()) 69 + ->setKey('name') 70 + ->setLabel(pht('Name')) 71 + ->setDescription(pht('Name of the publisher.')) 72 + ->setTransactionType( 73 + PhabricatorPackagesPublisherNameTransaction::TRANSACTIONTYPE) 74 + ->setIsRequired(true) 75 + ->setValue($object->getName()); 76 + 77 + if ($this->getIsCreate()) { 78 + $fields[] = id(new PhabricatorTextEditField()) 79 + ->setKey('publisherKey') 80 + ->setLabel(pht('Publisher Key')) 81 + ->setDescription(pht('Unique key to identify the publisher.')) 82 + ->setTransactionType( 83 + PhabricatorPackagesPublisherKeyTransaction::TRANSACTIONTYPE) 84 + ->setIsRequired(true) 85 + ->setValue($object->getPublisherKey()); 86 + } 87 + 88 + return $fields; 89 + } 90 + 91 + }
+51
src/applications/packages/editor/PhabricatorPackagesPublisherEditor.php
··· 1 + <?php 2 + 3 + final class PhabricatorPackagesPublisherEditor 4 + extends PhabricatorPackagesEditor { 5 + 6 + public function getEditorObjectsDescription() { 7 + return pht('Package Publishers'); 8 + } 9 + 10 + public function getCreateObjectTitle($author, $object) { 11 + return pht('%s created this publisher.', $author); 12 + } 13 + 14 + public function getCreateObjectTitleForFeed($author, $object) { 15 + return pht('%s created %s.', $author, $object); 16 + } 17 + 18 + public function getTransactionTypes() { 19 + $types = parent::getTransactionTypes(); 20 + $types[] = PhabricatorTransactions::TYPE_EDIT_POLICY; 21 + return $types; 22 + } 23 + 24 + protected function shouldPublishFeedStory( 25 + PhabricatorLiskDAO $object, 26 + array $xactions) { 27 + return true; 28 + } 29 + 30 + protected function getMailTo(PhabricatorLiskDAO $object) { 31 + return array(); 32 + } 33 + 34 + protected function didCatchDuplicateKeyException( 35 + PhabricatorLiskDAO $object, 36 + array $xactions, 37 + Exception $ex) { 38 + 39 + $errors = array(); 40 + $errors[] = new PhabricatorApplicationTransactionValidationError( 41 + PhabricatorPackagesPublisherKeyTransaction::TRANSACTIONTYPE, 42 + pht('Duplicate'), 43 + pht( 44 + 'The publisher key "%s" is already in use by another publisher.', 45 + $object->getPublisherKey()), 46 + null); 47 + 48 + throw new PhabricatorApplicationTransactionValidationException($errors); 49 + } 50 + 51 + }
+45
src/applications/packages/phid/PhabricatorPackagesPublisherPHIDType.php
··· 1 + <?php 2 + 3 + final class PhabricatorPackagesPublisherPHIDType 4 + extends PhabricatorPHIDType { 5 + 6 + const TYPECONST = 'PPUB'; 7 + 8 + public function getTypeName() { 9 + return pht('Package Publisher'); 10 + } 11 + 12 + public function newObject() { 13 + return new PhabricatorPackagesPublisher(); 14 + } 15 + 16 + public function getPHIDTypeApplicationClass() { 17 + return 'PhabricatorPackagesApplication'; 18 + } 19 + 20 + protected function buildQueryForObjects( 21 + PhabricatorObjectQuery $query, 22 + array $phids) { 23 + 24 + return id(new PhabricatorPackagesPublisherQuery()) 25 + ->withPHIDs($phids); 26 + } 27 + 28 + public function loadHandles( 29 + PhabricatorHandleQuery $query, 30 + array $handles, 31 + array $objects) { 32 + 33 + foreach ($handles as $phid => $handle) { 34 + $publisher = $objects[$phid]; 35 + 36 + $name = $publisher->getName(); 37 + $uri = $publisher->getURI(); 38 + 39 + $handle 40 + ->setName($name) 41 + ->setURI($uri); 42 + } 43 + } 44 + 45 + }
+64
src/applications/packages/query/PhabricatorPackagesPublisherQuery.php
··· 1 + <?php 2 + 3 + final class PhabricatorPackagesPublisherQuery 4 + extends PhabricatorCursorPagedPolicyAwareQuery { 5 + 6 + private $ids; 7 + private $phids; 8 + private $publisherKeys; 9 + 10 + public function withIDs(array $ids) { 11 + $this->ids = $ids; 12 + return $this; 13 + } 14 + 15 + public function withPHIDs(array $phids) { 16 + $this->phids = $phids; 17 + return $this; 18 + } 19 + 20 + public function withPublisherKeys(array $keys) { 21 + $this->publisherKeys = $keys; 22 + return $this; 23 + } 24 + 25 + public function newResultObject() { 26 + return new PhabricatorPackagesPublisher(); 27 + } 28 + 29 + protected function loadPage() { 30 + return $this->loadStandardPage($this->newResultObject()); 31 + } 32 + 33 + protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { 34 + $where = parent::buildWhereClauseParts($conn); 35 + 36 + if ($this->ids !== null) { 37 + $where[] = qsprintf( 38 + $conn, 39 + 'id IN (%Ld)', 40 + $this->ids); 41 + } 42 + 43 + if ($this->phids !== null) { 44 + $where[] = qsprintf( 45 + $conn, 46 + 'phid IN (%Ls)', 47 + $this->phids); 48 + } 49 + 50 + if ($this->publisherKeys !== null) { 51 + $where[] = qsprintf( 52 + $conn, 53 + 'publisherKey IN (%Ls)', 54 + $this->publisherKeys); 55 + } 56 + 57 + return $where; 58 + } 59 + 60 + public function getQueryApplicationClass() { 61 + return 'PhabricatorPackagesApplication'; 62 + } 63 + 64 + }
+77
src/applications/packages/query/PhabricatorPackagesPublisherSearchEngine.php
··· 1 + <?php 2 + 3 + final class PhabricatorPackagesPublisherSearchEngine 4 + extends PhabricatorApplicationSearchEngine { 5 + 6 + public function getResultTypeDescription() { 7 + return pht('Package Publishers'); 8 + } 9 + 10 + public function getApplicationClassName() { 11 + return 'PhabricatorPackagesApplication'; 12 + } 13 + 14 + public function newQuery() { 15 + return id(new PhabricatorPackagesPublisherQuery()); 16 + } 17 + 18 + protected function buildQueryFromParameters(array $map) { 19 + $query = $this->newQuery(); 20 + 21 + return $query; 22 + } 23 + 24 + protected function buildCustomSearchFields() { 25 + return array(); 26 + } 27 + 28 + protected function getURI($path) { 29 + return '/packages/publisher/'.$path; 30 + } 31 + 32 + protected function getBuiltinQueryNames() { 33 + $names = array( 34 + 'all' => pht('All Publishers'), 35 + ); 36 + 37 + return $names; 38 + } 39 + 40 + public function buildSavedQueryFromBuiltin($query_key) { 41 + $query = $this->newSavedQuery(); 42 + $query->setQueryKey($query_key); 43 + 44 + switch ($query_key) { 45 + case 'all': 46 + return $query; 47 + } 48 + 49 + return parent::buildSavedQueryFromBuiltin($query_key); 50 + } 51 + 52 + protected function renderResultList( 53 + array $publishers, 54 + PhabricatorSavedQuery $query, 55 + array $handles) { 56 + 57 + assert_instances_of($publishers, 'PhabricatorPackagesPublisher'); 58 + 59 + $viewer = $this->requireViewer(); 60 + 61 + $list = id(new PHUIObjectItemListView()) 62 + ->setViewer($viewer); 63 + foreach ($publishers as $publisher) { 64 + $item = id(new PHUIObjectItemView()) 65 + ->setObjectName($publisher->getPublisherKey()) 66 + ->setHeader($publisher->getName()) 67 + ->setHref($publisher->getURI()); 68 + 69 + $list->addItem($item); 70 + } 71 + 72 + return id(new PhabricatorApplicationSearchResultView()) 73 + ->setObjectList($list) 74 + ->setNoDataString(pht('No publishers found.')); 75 + } 76 + 77 + }
+10
src/applications/packages/query/PhabricatorPackagesPublisherTransactionQuery.php
··· 1 + <?php 2 + 3 + final class PhabricatorPackagesPublisherTransactionQuery 4 + extends PhabricatorApplicationTransactionQuery { 5 + 6 + public function getTemplateApplicationTransaction() { 7 + return new PhabricatorPackagesPublisherTransaction(); 8 + } 9 + 10 + }
+9
src/applications/packages/storage/PhabricatorPackagesDAO.php
··· 1 + <?php 2 + 3 + abstract class PhabricatorPackagesDAO extends PhabricatorLiskDAO { 4 + 5 + public function getApplicationName() { 6 + return 'packages'; 7 + } 8 + 9 + }
+191
src/applications/packages/storage/PhabricatorPackagesPublisher.php
··· 1 + <?php 2 + 3 + final class PhabricatorPackagesPublisher 4 + extends PhabricatorPackagesDAO 5 + implements 6 + PhabricatorPolicyInterface, 7 + PhabricatorApplicationTransactionInterface, 8 + PhabricatorDestructibleInterface, 9 + PhabricatorSubscribableInterface, 10 + PhabricatorProjectInterface, 11 + PhabricatorConduitResultInterface { 12 + 13 + protected $name; 14 + protected $publisherKey; 15 + protected $editPolicy; 16 + 17 + public static function initializeNewPublisher(PhabricatorUser $actor) { 18 + return id(new self()); 19 + } 20 + 21 + protected function getConfiguration() { 22 + return array( 23 + self::CONFIG_AUX_PHID => true, 24 + self::CONFIG_COLUMN_SCHEMA => array( 25 + 'name' => 'text64', 26 + 'publisherKey' => 'sort64', 27 + ), 28 + self::CONFIG_KEY_SCHEMA => array( 29 + 'key_publisher' => array( 30 + 'columns' => array('publisherKey'), 31 + 'unique' => true, 32 + ), 33 + ), 34 + ) + parent::getConfiguration(); 35 + } 36 + 37 + public function generatePHID() { 38 + return PhabricatorPHID::generateNewPHID( 39 + PhabricatorPackagesPublisherPHIDType::TYPECONST); 40 + } 41 + 42 + public function getURI() { 43 + $publisher_key = $this->getPublisherKey(); 44 + return "/package/{$publisher_key}/"; 45 + } 46 + 47 + public static function assertValidPublisherName($value) { 48 + $length = phutil_utf8_strlen($value); 49 + if (!$length) { 50 + throw new Exception( 51 + pht( 52 + 'Publisher name "%s" is not valid: publisher names are required.', 53 + $value)); 54 + } 55 + 56 + $max_length = 64; 57 + if ($length > $max_length) { 58 + throw new Exception( 59 + pht( 60 + 'Publisher name "%s" is not valid: publisher names must not be '. 61 + 'more than %s characters long.', 62 + $value, 63 + new PhutilNumber($max_length))); 64 + } 65 + } 66 + 67 + public static function assertValidPublisherKey($value) { 68 + $length = phutil_utf8_strlen($value); 69 + if (!$length) { 70 + throw new Exception( 71 + pht( 72 + 'Publisher key "%s" is not valid: publisher keys are required.', 73 + $value)); 74 + } 75 + 76 + $max_length = 64; 77 + if ($length > $max_length) { 78 + throw new Exception( 79 + pht( 80 + 'Publisher key "%s" is not valid: publisher keys must not be '. 81 + 'more than %s characters long.', 82 + $value, 83 + new PhutilNumber($max_length))); 84 + } 85 + 86 + if (!preg_match('/^[a-z]+\z/', $value)) { 87 + throw new Exception( 88 + pht( 89 + 'Publisher key "%s" is not valid: publisher keys may only contain '. 90 + 'lowercase latin letters.', 91 + $value)); 92 + } 93 + } 94 + 95 + 96 + /* -( PhabricatorSubscribableInterface )----------------------------------- */ 97 + 98 + 99 + public function isAutomaticallySubscribed($phid) { 100 + return false; 101 + } 102 + 103 + 104 + /* -( Policy Interface )--------------------------------------------------- */ 105 + 106 + 107 + public function getCapabilities() { 108 + return array( 109 + PhabricatorPolicyCapability::CAN_VIEW, 110 + PhabricatorPolicyCapability::CAN_EDIT, 111 + ); 112 + } 113 + 114 + public function getPolicy($capability) { 115 + switch ($capability) { 116 + case PhabricatorPolicyCapability::CAN_VIEW: 117 + return PhabricatorPolicies::getMostOpenPolicy(); 118 + case PhabricatorPolicyCapability::CAN_EDIT: 119 + return $this->getEditPolicy(); 120 + } 121 + } 122 + 123 + public function hasAutomaticCapability($capability, PhabricatorUser $user) { 124 + return false; 125 + } 126 + 127 + public function describeAutomaticCapability($capability) { 128 + return null; 129 + } 130 + 131 + 132 + /* -( PhabricatorDestructibleInterface )----------------------------------- */ 133 + 134 + 135 + public function destroyObjectPermanently( 136 + PhabricatorDestructionEngine $engine) { 137 + $this->delete(); 138 + } 139 + 140 + 141 + /* -( PhabricatorApplicationTransactionInterface )------------------------- */ 142 + 143 + 144 + public function getApplicationTransactionEditor() { 145 + return new PhabricatorPackagesPublisherEditor(); 146 + } 147 + 148 + public function getApplicationTransactionObject() { 149 + return $this; 150 + } 151 + 152 + public function getApplicationTransactionTemplate() { 153 + return new PhabricatorPackagesPublisherTransaction(); 154 + } 155 + 156 + public function willRenderTimeline( 157 + PhabricatorApplicationTransactionView $timeline, 158 + AphrontRequest $request) { 159 + return $timeline; 160 + } 161 + 162 + 163 + /* -( PhabricatorConduitResultInterface )---------------------------------- */ 164 + 165 + 166 + public function getFieldSpecificationsForConduit() { 167 + return array( 168 + id(new PhabricatorConduitSearchFieldSpecification()) 169 + ->setKey('name') 170 + ->setType('string') 171 + ->setDescription(pht('The name of the publisher.')), 172 + id(new PhabricatorConduitSearchFieldSpecification()) 173 + ->setKey('publisherKey') 174 + ->setType('string') 175 + ->setDescription(pht('The unique key of the publisher.')), 176 + ); 177 + } 178 + 179 + public function getFieldValuesForConduit() { 180 + return array( 181 + 'name' => $this->getName(), 182 + 'publisherKey' => $this->getPublisherKey(), 183 + ); 184 + } 185 + 186 + public function getConduitSearchAttachments() { 187 + return array(); 188 + } 189 + 190 + 191 + }
+18
src/applications/packages/storage/PhabricatorPackagesPublisherTransaction.php
··· 1 + <?php 2 + 3 + final class PhabricatorPackagesPublisherTransaction 4 + extends PhabricatorModularTransaction { 5 + 6 + public function getApplicationName() { 7 + return 'packages'; 8 + } 9 + 10 + public function getApplicationTransactionType() { 11 + return PhabricatorPackagesPublisherPHIDType::TYPECONST; 12 + } 13 + 14 + public function getBaseTransactionClass() { 15 + return 'PhabricatorPackagesPublisherTransactionType'; 16 + } 17 + 18 + }
+10
src/applications/packages/storage/PhabricatorPackagesSchemaSpec.php
··· 1 + <?php 2 + 3 + final class PhabricatorPackagesSchemaSpec 4 + extends PhabricatorConfigSchemaSpec { 5 + 6 + public function buildSchemata() { 7 + $this->buildEdgeSchemata(new PhabricatorPackagesPublisher()); 8 + } 9 + 10 + }
+4
src/applications/packages/xaction/PhabricatorPackagesTransactionType.php
··· 1 + <?php 2 + 3 + abstract class PhabricatorPackagesTransactionType 4 + extends PhabricatorModularTransactionType {}
+44
src/applications/packages/xaction/publisher/PhabricatorPackagesPublisherKeyTransaction.php
··· 1 + <?php 2 + 3 + final class PhabricatorPackagesPublisherKeyTransaction 4 + extends PhabricatorPackagesPublisherTransactionType { 5 + 6 + const TRANSACTIONTYPE = 'packages.publisher.key'; 7 + 8 + public function generateOldValue($object) { 9 + return $object->getPublisherKey(); 10 + } 11 + 12 + public function applyInternalEffects($object, $value) { 13 + $object->setPublisherKey($value); 14 + } 15 + 16 + public function validateTransactions($object, array $xactions) { 17 + $errors = array(); 18 + 19 + if ($this->isEmptyTextTransaction($object->getName(), $xactions)) { 20 + $errors[] = $this->newRequiredError( 21 + pht('Publishers must have a unique publisher key.')); 22 + } 23 + 24 + if (!$this->isNewObject()) { 25 + foreach ($xactions as $xaction) { 26 + $errors[] = $this->newInvalidError( 27 + pht('Once a publisher is created, its key can not be changed.'), 28 + $xaction); 29 + } 30 + } 31 + 32 + foreach ($xactions as $xaction) { 33 + $value = $xaction->getNewValue(); 34 + try { 35 + PhabricatorPackagesPublisher::assertValidPublisherKey($value); 36 + } catch (Exception $ex) { 37 + $errors[] = $this->newInvalidError($ex->getMessage(), $xaction); 38 + } 39 + } 40 + 41 + return $errors; 42 + } 43 + 44 + }
+53
src/applications/packages/xaction/publisher/PhabricatorPackagesPublisherNameTransaction.php
··· 1 + <?php 2 + 3 + final class PhabricatorPackagesPublisherNameTransaction 4 + extends PhabricatorPackagesPublisherTransactionType { 5 + 6 + const TRANSACTIONTYPE = 'packages.publisher.name'; 7 + 8 + public function generateOldValue($object) { 9 + return $object->getName(); 10 + } 11 + 12 + public function applyInternalEffects($object, $value) { 13 + $object->setName($value); 14 + } 15 + 16 + public function getTitle() { 17 + return pht( 18 + '%s changed the name of this publisher from %s to %s.', 19 + $this->renderAuthor(), 20 + $this->renderOldValue(), 21 + $this->renderNewValue()); 22 + } 23 + 24 + public function getTitleForFeed() { 25 + return pht( 26 + '%s updated the name for %s from %s to %s.', 27 + $this->renderAuthor(), 28 + $this->renderObject(), 29 + $this->renderOldValue(), 30 + $this->renderNewValue()); 31 + } 32 + 33 + public function validateTransactions($object, array $xactions) { 34 + $errors = array(); 35 + 36 + if ($this->isEmptyTextTransaction($object->getName(), $xactions)) { 37 + $errors[] = $this->newRequiredError( 38 + pht('Publishers must have a name.')); 39 + } 40 + 41 + foreach ($xactions as $xaction) { 42 + $value = $xaction->getNewValue(); 43 + try { 44 + PhabricatorPackagesPublisher::assertValidPublisherName($value); 45 + } catch (Exception $ex) { 46 + $errors[] = $this->newInvalidError($ex->getMessage(), $xaction); 47 + } 48 + } 49 + 50 + return $errors; 51 + } 52 + 53 + }
+4
src/applications/packages/xaction/publisher/PhabricatorPackagesPublisherTransactionType.php
··· 1 + <?php 2 + 3 + abstract class PhabricatorPackagesPublisherTransactionType 4 + extends PhabricatorPackagesTransactionType {}
+1
src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php
··· 111 111 'db.spaces' => array(), 112 112 'db.phurl' => array(), 113 113 'db.badges' => array(), 114 + 'db.packages' => array(), 114 115 '0000.legacy.sql' => array( 115 116 'legacy' => 0, 116 117 ),