1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-12-18 03:20:59 +01:00

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
This commit is contained in:
epriestley 2016-07-21 08:14:34 -07:00
parent eab74a9d7c
commit 9160da1afb
29 changed files with 1011 additions and 0 deletions

View file

@ -0,0 +1,11 @@
CREATE TABLE {$NAMESPACE}_packages.packages_publisher (
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
phid VARBINARY(64) NOT NULL,
name VARCHAR(64) NOT NULL COLLATE {$COLLATE_TEXT},
publisherKey VARCHAR(64) NOT NULL COLLATE {$COLLATE_SORT},
editPolicy VARBINARY(64) NOT NULL,
dateCreated INT UNSIGNED NOT NULL,
dateModified INT UNSIGNED NOT NULL,
UNIQUE KEY `key_phid` (phid),
UNIQUE KEY `key_publisher` (publisherKey)
) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};

View file

@ -0,0 +1,19 @@
CREATE TABLE {$NAMESPACE}_packages.packages_publishertransaction (
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
phid VARBINARY(64) NOT NULL,
authorPHID VARBINARY(64) NOT NULL,
objectPHID VARBINARY(64) NOT NULL,
viewPolicy VARBINARY(64) NOT NULL,
editPolicy VARBINARY(64) NOT NULL,
commentPHID VARBINARY(64) DEFAULT NULL,
commentVersion INT UNSIGNED NOT NULL,
transactionType VARCHAR(32) COLLATE {$COLLATE_TEXT} NOT NULL,
oldValue LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL,
newValue LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL,
contentSource LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL,
metadata LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL,
dateCreated INT UNSIGNED NOT NULL,
dateModified INT UNSIGNED NOT NULL,
UNIQUE KEY `key_phid` (`phid`),
KEY `key_object` (`objectPHID`)
) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};

View file

@ -0,0 +1,16 @@
CREATE TABLE {$NAMESPACE}_packages.edge (
src VARBINARY(64) NOT NULL,
type INT UNSIGNED NOT NULL,
dst VARBINARY(64) NOT NULL,
dateCreated INT UNSIGNED NOT NULL,
seq INT UNSIGNED NOT NULL,
dataID INT UNSIGNED,
PRIMARY KEY (src, type, dst),
KEY `src` (src, type, dateCreated, seq),
UNIQUE KEY `key_dst` (dst, type, src)
) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};
CREATE TABLE {$NAMESPACE}_packages.edgedata (
id INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
data LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT}
) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};

View file

@ -2972,6 +2972,30 @@ phutil_register_library_map(array(
'PhabricatorPHPASTApplication' => 'applications/phpast/application/PhabricatorPHPASTApplication.php', 'PhabricatorPHPASTApplication' => 'applications/phpast/application/PhabricatorPHPASTApplication.php',
'PhabricatorPHPConfigSetupCheck' => 'applications/config/check/PhabricatorPHPConfigSetupCheck.php', 'PhabricatorPHPConfigSetupCheck' => 'applications/config/check/PhabricatorPHPConfigSetupCheck.php',
'PhabricatorPHPMailerConfigOptions' => 'applications/config/option/PhabricatorPHPMailerConfigOptions.php', 'PhabricatorPHPMailerConfigOptions' => 'applications/config/option/PhabricatorPHPMailerConfigOptions.php',
'PhabricatorPackagesApplication' => 'applications/packages/application/PhabricatorPackagesApplication.php',
'PhabricatorPackagesController' => 'applications/packages/controller/PhabricatorPackagesController.php',
'PhabricatorPackagesDAO' => 'applications/packages/storage/PhabricatorPackagesDAO.php',
'PhabricatorPackagesEditEngine' => 'applications/packages/editor/PhabricatorPackagesEditEngine.php',
'PhabricatorPackagesEditor' => 'applications/packages/editor/PhabricatorPackagesEditor.php',
'PhabricatorPackagesPublisher' => 'applications/packages/storage/PhabricatorPackagesPublisher.php',
'PhabricatorPackagesPublisherController' => 'applications/packages/controller/PhabricatorPackagesPublisherController.php',
'PhabricatorPackagesPublisherEditConduitAPIMethod' => 'applications/packages/conduit/PhabricatorPackagesPublisherEditConduitAPIMethod.php',
'PhabricatorPackagesPublisherEditController' => 'applications/packages/controller/PhabricatorPackagesPublisherEditController.php',
'PhabricatorPackagesPublisherEditEngine' => 'applications/packages/editor/PhabricatorPackagesPublisherEditEngine.php',
'PhabricatorPackagesPublisherEditor' => 'applications/packages/editor/PhabricatorPackagesPublisherEditor.php',
'PhabricatorPackagesPublisherKeyTransaction' => 'applications/packages/xaction/publisher/PhabricatorPackagesPublisherKeyTransaction.php',
'PhabricatorPackagesPublisherListController' => 'applications/packages/controller/PhabricatorPackagesPublisherListController.php',
'PhabricatorPackagesPublisherNameTransaction' => 'applications/packages/xaction/publisher/PhabricatorPackagesPublisherNameTransaction.php',
'PhabricatorPackagesPublisherPHIDType' => 'applications/packages/phid/PhabricatorPackagesPublisherPHIDType.php',
'PhabricatorPackagesPublisherQuery' => 'applications/packages/query/PhabricatorPackagesPublisherQuery.php',
'PhabricatorPackagesPublisherSearchConduitAPIMethod' => 'applications/packages/conduit/PhabricatorPackagesPublisherSearchConduitAPIMethod.php',
'PhabricatorPackagesPublisherSearchEngine' => 'applications/packages/query/PhabricatorPackagesPublisherSearchEngine.php',
'PhabricatorPackagesPublisherTransaction' => 'applications/packages/storage/PhabricatorPackagesPublisherTransaction.php',
'PhabricatorPackagesPublisherTransactionQuery' => 'applications/packages/query/PhabricatorPackagesPublisherTransactionQuery.php',
'PhabricatorPackagesPublisherTransactionType' => 'applications/packages/xaction/publisher/PhabricatorPackagesPublisherTransactionType.php',
'PhabricatorPackagesPublisherViewController' => 'applications/packages/controller/PhabricatorPackagesPublisherViewController.php',
'PhabricatorPackagesSchemaSpec' => 'applications/packages/storage/PhabricatorPackagesSchemaSpec.php',
'PhabricatorPackagesTransactionType' => 'applications/packages/xaction/PhabricatorPackagesTransactionType.php',
'PhabricatorPagerUIExample' => 'applications/uiexample/examples/PhabricatorPagerUIExample.php', 'PhabricatorPagerUIExample' => 'applications/uiexample/examples/PhabricatorPagerUIExample.php',
'PhabricatorPassphraseApplication' => 'applications/passphrase/application/PhabricatorPassphraseApplication.php', 'PhabricatorPassphraseApplication' => 'applications/passphrase/application/PhabricatorPassphraseApplication.php',
'PhabricatorPasswordAuthProvider' => 'applications/auth/provider/PhabricatorPasswordAuthProvider.php', 'PhabricatorPasswordAuthProvider' => 'applications/auth/provider/PhabricatorPasswordAuthProvider.php',
@ -7725,6 +7749,38 @@ phutil_register_library_map(array(
'PhabricatorPHPASTApplication' => 'PhabricatorApplication', 'PhabricatorPHPASTApplication' => 'PhabricatorApplication',
'PhabricatorPHPConfigSetupCheck' => 'PhabricatorSetupCheck', 'PhabricatorPHPConfigSetupCheck' => 'PhabricatorSetupCheck',
'PhabricatorPHPMailerConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorPHPMailerConfigOptions' => 'PhabricatorApplicationConfigOptions',
'PhabricatorPackagesApplication' => 'PhabricatorApplication',
'PhabricatorPackagesController' => 'PhabricatorController',
'PhabricatorPackagesDAO' => 'PhabricatorLiskDAO',
'PhabricatorPackagesEditEngine' => 'PhabricatorEditEngine',
'PhabricatorPackagesEditor' => 'PhabricatorApplicationTransactionEditor',
'PhabricatorPackagesPublisher' => array(
'PhabricatorPackagesDAO',
'PhabricatorPolicyInterface',
'PhabricatorApplicationTransactionInterface',
'PhabricatorDestructibleInterface',
'PhabricatorSubscribableInterface',
'PhabricatorProjectInterface',
'PhabricatorConduitResultInterface',
),
'PhabricatorPackagesPublisherController' => 'PhabricatorPackagesController',
'PhabricatorPackagesPublisherEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod',
'PhabricatorPackagesPublisherEditController' => 'PhabricatorPackagesPublisherController',
'PhabricatorPackagesPublisherEditEngine' => 'PhabricatorPackagesEditEngine',
'PhabricatorPackagesPublisherEditor' => 'PhabricatorPackagesEditor',
'PhabricatorPackagesPublisherKeyTransaction' => 'PhabricatorPackagesPublisherTransactionType',
'PhabricatorPackagesPublisherListController' => 'PhabricatorPackagesPublisherController',
'PhabricatorPackagesPublisherNameTransaction' => 'PhabricatorPackagesPublisherTransactionType',
'PhabricatorPackagesPublisherPHIDType' => 'PhabricatorPHIDType',
'PhabricatorPackagesPublisherQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorPackagesPublisherSearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod',
'PhabricatorPackagesPublisherSearchEngine' => 'PhabricatorApplicationSearchEngine',
'PhabricatorPackagesPublisherTransaction' => 'PhabricatorModularTransaction',
'PhabricatorPackagesPublisherTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
'PhabricatorPackagesPublisherTransactionType' => 'PhabricatorPackagesTransactionType',
'PhabricatorPackagesPublisherViewController' => 'PhabricatorPackagesPublisherController',
'PhabricatorPackagesSchemaSpec' => 'PhabricatorConfigSchemaSpec',
'PhabricatorPackagesTransactionType' => 'PhabricatorModularTransactionType',
'PhabricatorPagerUIExample' => 'PhabricatorUIExample', 'PhabricatorPagerUIExample' => 'PhabricatorUIExample',
'PhabricatorPassphraseApplication' => 'PhabricatorApplication', 'PhabricatorPassphraseApplication' => 'PhabricatorApplication',
'PhabricatorPasswordAuthProvider' => 'PhabricatorAuthProvider', 'PhabricatorPasswordAuthProvider' => 'PhabricatorAuthProvider',

View file

@ -0,0 +1,47 @@
<?php
final class PhabricatorPackagesApplication extends PhabricatorApplication {
public function getName() {
return pht('Packages');
}
public function getShortDescription() {
return pht('Publish Software');
}
public function getFlavorText() {
return pht('Applications and Extensions');
}
public function getBaseURI() {
return '/packages/';
}
public function getIcon() {
return 'fa-gift';
}
public function isPrototype() {
return true;
}
public function getRoutes() {
return array(
'/package/' => array(
'(?P<publisherKey>[^/]+)/' => array(
'' => 'PhabricatorPackagesPublisherViewController',
),
),
'/packages/' => array(
'publisher/' => array(
$this->getQueryRoutePattern() =>
'PhabricatorPackagesPublisherListController',
$this->getEditRoutePattern('edit/') =>
'PhabricatorPackagesPublisherEditController',
),
),
);
}
}

View file

@ -0,0 +1,19 @@
<?php
final class PhabricatorPackagesPublisherEditConduitAPIMethod
extends PhabricatorEditEngineAPIMethod {
public function getAPIMethodName() {
return 'packages.publisher.edit';
}
public function newEditEngine() {
return new PhabricatorPackagesPublisherEditEngine();
}
public function getMethodSummary() {
return pht(
'Apply transactions to create a new publisher or edit an existing one.');
}
}

View file

@ -0,0 +1,18 @@
<?php
final class PhabricatorPackagesPublisherSearchConduitAPIMethod
extends PhabricatorSearchEngineAPIMethod {
public function getAPIMethodName() {
return 'packages.publisher.search';
}
public function newSearchEngine() {
return new PhabricatorPackagesPublisherSearchEngine();
}
public function getMethodSummary() {
return pht('Read information about publishers.');
}
}

View file

@ -0,0 +1,3 @@
<?php
abstract class PhabricatorPackagesController extends PhabricatorController {}

View file

@ -0,0 +1,4 @@
<?php
abstract class PhabricatorPackagesPublisherController
extends PhabricatorPackagesController {}

View file

@ -0,0 +1,12 @@
<?php
final class PhabricatorPackagesPublisherEditController
extends PhabricatorPackagesPublisherController {
public function handleRequest(AphrontRequest $request) {
return id(new PhabricatorPackagesPublisherEditEngine())
->setController($this)
->buildResponse();
}
}

View file

@ -0,0 +1,26 @@
<?php
final class PhabricatorPackagesPublisherListController
extends PhabricatorPackagesPublisherController {
public function shouldAllowPublic() {
return true;
}
public function handleRequest(AphrontRequest $request) {
return id(new PhabricatorPackagesPublisherSearchEngine())
->setController($this)
->buildResponse();
}
protected function buildApplicationCrumbs() {
$crumbs = parent::buildApplicationCrumbs();
id(new PhabricatorPackagesPublisherEditEngine())
->setViewer($this->getViewer())
->addActionToCrumbs($crumbs);
return $crumbs;
}
}

View file

@ -0,0 +1,84 @@
<?php
final class PhabricatorPackagesPublisherViewController
extends PhabricatorPackagesPublisherController {
public function shouldAllowPublic() {
return true;
}
public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer();
$publisher_key = $request->getURIData('publisherKey');
$publisher = id(new PhabricatorPackagesPublisherQuery())
->setViewer($viewer)
->withPublisherKeys(array($publisher_key))
->executeOne();
if (!$publisher) {
return new Aphront404Response();
}
$crumbs = $this->buildApplicationCrumbs()
->addTextCrumb(
pht('Publishers'),
$this->getApplicationURI('publisher/'))
->addTextCrumb($publisher->getName())
->setBorder(true);
$header = $this->buildHeaderView($publisher);
$curtain = $this->buildCurtain($publisher);
$timeline = $this->buildTransactionTimeline(
$publisher,
new PhabricatorPackagesPublisherTransactionQuery());
$publisher_view = id(new PHUITwoColumnView())
->setHeader($header)
->setCurtain($curtain)
->setMainColumn($timeline);
return $this->newPage()
->setCrumbs($crumbs)
->setPageObjectPHIDs(
array(
$publisher->getPHID(),
))
->appendChild($publisher_view);
}
private function buildHeaderView(PhabricatorPackagesPublisher $publisher) {
$viewer = $this->getViewer();
$name = $publisher->getName();
return id(new PHUIHeaderView())
->setViewer($viewer)
->setHeader($name)
->setPolicyObject($publisher)
->setHeaderIcon('fa-paw');
}
private function buildCurtain(PhabricatorPackagesPublisher $publisher) {
$viewer = $this->getViewer();
$curtain = $this->newCurtainView($publisher);
$can_edit = PhabricatorPolicyFilter::hasCapability(
$viewer,
$publisher,
PhabricatorPolicyCapability::CAN_EDIT);
$id = $publisher->getID();
$edit_uri = $this->getApplicationURI("publisher/edit/{$id}/");
$curtain->addAction(
id(new PhabricatorActionView())
->setName(pht('Edit Publisher'))
->setIcon('fa-pencil')
->setDisabled(!$can_edit)
->setHref($edit_uri));
return $curtain;
}
}

View file

@ -0,0 +1,14 @@
<?php
abstract class PhabricatorPackagesEditEngine
extends PhabricatorEditEngine {
public function isEngineConfigurable() {
return false;
}
public function getEngineApplicationClass() {
return 'PhabricatorPackagesApplication';
}
}

View file

@ -0,0 +1,10 @@
<?php
abstract class PhabricatorPackagesEditor
extends PhabricatorApplicationTransactionEditor {
public function getEditorApplicationClass() {
return 'PhabricatorPasteApplication';
}
}

View file

@ -0,0 +1,91 @@
<?php
final class PhabricatorPackagesPublisherEditEngine
extends PhabricatorPackagesEditEngine {
const ENGINECONST = 'packages.publisher';
public function getEngineName() {
return pht('Package Publishers');
}
public function getSummaryHeader() {
return pht('Edit Package Publisher Configurations');
}
public function getSummaryText() {
return pht('This engine is used to edit Packages publishers.');
}
protected function newEditableObject() {
$viewer = $this->getViewer();
return PhabricatorPackagesPublisher::initializeNewPublisher($viewer);
}
protected function newObjectQuery() {
return new PhabricatorPackagesPublisherQuery();
}
protected function getObjectCreateTitleText($object) {
return pht('Create Publisher');
}
protected function getObjectCreateButtonText($object) {
return pht('Create Publisher');
}
protected function getObjectEditTitleText($object) {
return pht('Edit Publisher: %s', $object->getName());
}
protected function getObjectEditShortText($object) {
return pht('Edit Publisher');
}
protected function getObjectCreateShortText() {
return pht('Create Publisher');
}
protected function getObjectName() {
return pht('Publisher');
}
protected function getEditorURI() {
return '/packages/publisher/edit/';
}
protected function getObjectCreateCancelURI($object) {
return '/packages/publisher/';
}
protected function getObjectViewURI($object) {
return $object->getURI();
}
protected function buildCustomEditFields($object) {
$fields = array();
$fields[] = id(new PhabricatorTextEditField())
->setKey('name')
->setLabel(pht('Name'))
->setDescription(pht('Name of the publisher.'))
->setTransactionType(
PhabricatorPackagesPublisherNameTransaction::TRANSACTIONTYPE)
->setIsRequired(true)
->setValue($object->getName());
if ($this->getIsCreate()) {
$fields[] = id(new PhabricatorTextEditField())
->setKey('publisherKey')
->setLabel(pht('Publisher Key'))
->setDescription(pht('Unique key to identify the publisher.'))
->setTransactionType(
PhabricatorPackagesPublisherKeyTransaction::TRANSACTIONTYPE)
->setIsRequired(true)
->setValue($object->getPublisherKey());
}
return $fields;
}
}

View file

@ -0,0 +1,51 @@
<?php
final class PhabricatorPackagesPublisherEditor
extends PhabricatorPackagesEditor {
public function getEditorObjectsDescription() {
return pht('Package Publishers');
}
public function getCreateObjectTitle($author, $object) {
return pht('%s created this publisher.', $author);
}
public function getCreateObjectTitleForFeed($author, $object) {
return pht('%s created %s.', $author, $object);
}
public function getTransactionTypes() {
$types = parent::getTransactionTypes();
$types[] = PhabricatorTransactions::TYPE_EDIT_POLICY;
return $types;
}
protected function shouldPublishFeedStory(
PhabricatorLiskDAO $object,
array $xactions) {
return true;
}
protected function getMailTo(PhabricatorLiskDAO $object) {
return array();
}
protected function didCatchDuplicateKeyException(
PhabricatorLiskDAO $object,
array $xactions,
Exception $ex) {
$errors = array();
$errors[] = new PhabricatorApplicationTransactionValidationError(
PhabricatorPackagesPublisherKeyTransaction::TRANSACTIONTYPE,
pht('Duplicate'),
pht(
'The publisher key "%s" is already in use by another publisher.',
$object->getPublisherKey()),
null);
throw new PhabricatorApplicationTransactionValidationException($errors);
}
}

View file

@ -0,0 +1,45 @@
<?php
final class PhabricatorPackagesPublisherPHIDType
extends PhabricatorPHIDType {
const TYPECONST = 'PPUB';
public function getTypeName() {
return pht('Package Publisher');
}
public function newObject() {
return new PhabricatorPackagesPublisher();
}
public function getPHIDTypeApplicationClass() {
return 'PhabricatorPackagesApplication';
}
protected function buildQueryForObjects(
PhabricatorObjectQuery $query,
array $phids) {
return id(new PhabricatorPackagesPublisherQuery())
->withPHIDs($phids);
}
public function loadHandles(
PhabricatorHandleQuery $query,
array $handles,
array $objects) {
foreach ($handles as $phid => $handle) {
$publisher = $objects[$phid];
$name = $publisher->getName();
$uri = $publisher->getURI();
$handle
->setName($name)
->setURI($uri);
}
}
}

View file

@ -0,0 +1,64 @@
<?php
final class PhabricatorPackagesPublisherQuery
extends PhabricatorCursorPagedPolicyAwareQuery {
private $ids;
private $phids;
private $publisherKeys;
public function withIDs(array $ids) {
$this->ids = $ids;
return $this;
}
public function withPHIDs(array $phids) {
$this->phids = $phids;
return $this;
}
public function withPublisherKeys(array $keys) {
$this->publisherKeys = $keys;
return $this;
}
public function newResultObject() {
return new PhabricatorPackagesPublisher();
}
protected function loadPage() {
return $this->loadStandardPage($this->newResultObject());
}
protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {
$where = parent::buildWhereClauseParts($conn);
if ($this->ids !== null) {
$where[] = qsprintf(
$conn,
'id IN (%Ld)',
$this->ids);
}
if ($this->phids !== null) {
$where[] = qsprintf(
$conn,
'phid IN (%Ls)',
$this->phids);
}
if ($this->publisherKeys !== null) {
$where[] = qsprintf(
$conn,
'publisherKey IN (%Ls)',
$this->publisherKeys);
}
return $where;
}
public function getQueryApplicationClass() {
return 'PhabricatorPackagesApplication';
}
}

View file

@ -0,0 +1,77 @@
<?php
final class PhabricatorPackagesPublisherSearchEngine
extends PhabricatorApplicationSearchEngine {
public function getResultTypeDescription() {
return pht('Package Publishers');
}
public function getApplicationClassName() {
return 'PhabricatorPackagesApplication';
}
public function newQuery() {
return id(new PhabricatorPackagesPublisherQuery());
}
protected function buildQueryFromParameters(array $map) {
$query = $this->newQuery();
return $query;
}
protected function buildCustomSearchFields() {
return array();
}
protected function getURI($path) {
return '/packages/publisher/'.$path;
}
protected function getBuiltinQueryNames() {
$names = array(
'all' => pht('All Publishers'),
);
return $names;
}
public function buildSavedQueryFromBuiltin($query_key) {
$query = $this->newSavedQuery();
$query->setQueryKey($query_key);
switch ($query_key) {
case 'all':
return $query;
}
return parent::buildSavedQueryFromBuiltin($query_key);
}
protected function renderResultList(
array $publishers,
PhabricatorSavedQuery $query,
array $handles) {
assert_instances_of($publishers, 'PhabricatorPackagesPublisher');
$viewer = $this->requireViewer();
$list = id(new PHUIObjectItemListView())
->setViewer($viewer);
foreach ($publishers as $publisher) {
$item = id(new PHUIObjectItemView())
->setObjectName($publisher->getPublisherKey())
->setHeader($publisher->getName())
->setHref($publisher->getURI());
$list->addItem($item);
}
return id(new PhabricatorApplicationSearchResultView())
->setObjectList($list)
->setNoDataString(pht('No publishers found.'));
}
}

View file

@ -0,0 +1,10 @@
<?php
final class PhabricatorPackagesPublisherTransactionQuery
extends PhabricatorApplicationTransactionQuery {
public function getTemplateApplicationTransaction() {
return new PhabricatorPackagesPublisherTransaction();
}
}

View file

@ -0,0 +1,9 @@
<?php
abstract class PhabricatorPackagesDAO extends PhabricatorLiskDAO {
public function getApplicationName() {
return 'packages';
}
}

View file

@ -0,0 +1,191 @@
<?php
final class PhabricatorPackagesPublisher
extends PhabricatorPackagesDAO
implements
PhabricatorPolicyInterface,
PhabricatorApplicationTransactionInterface,
PhabricatorDestructibleInterface,
PhabricatorSubscribableInterface,
PhabricatorProjectInterface,
PhabricatorConduitResultInterface {
protected $name;
protected $publisherKey;
protected $editPolicy;
public static function initializeNewPublisher(PhabricatorUser $actor) {
return id(new self());
}
protected function getConfiguration() {
return array(
self::CONFIG_AUX_PHID => true,
self::CONFIG_COLUMN_SCHEMA => array(
'name' => 'text64',
'publisherKey' => 'sort64',
),
self::CONFIG_KEY_SCHEMA => array(
'key_publisher' => array(
'columns' => array('publisherKey'),
'unique' => true,
),
),
) + parent::getConfiguration();
}
public function generatePHID() {
return PhabricatorPHID::generateNewPHID(
PhabricatorPackagesPublisherPHIDType::TYPECONST);
}
public function getURI() {
$publisher_key = $this->getPublisherKey();
return "/package/{$publisher_key}/";
}
public static function assertValidPublisherName($value) {
$length = phutil_utf8_strlen($value);
if (!$length) {
throw new Exception(
pht(
'Publisher name "%s" is not valid: publisher names are required.',
$value));
}
$max_length = 64;
if ($length > $max_length) {
throw new Exception(
pht(
'Publisher name "%s" is not valid: publisher names must not be '.
'more than %s characters long.',
$value,
new PhutilNumber($max_length)));
}
}
public static function assertValidPublisherKey($value) {
$length = phutil_utf8_strlen($value);
if (!$length) {
throw new Exception(
pht(
'Publisher key "%s" is not valid: publisher keys are required.',
$value));
}
$max_length = 64;
if ($length > $max_length) {
throw new Exception(
pht(
'Publisher key "%s" is not valid: publisher keys must not be '.
'more than %s characters long.',
$value,
new PhutilNumber($max_length)));
}
if (!preg_match('/^[a-z]+\z/', $value)) {
throw new Exception(
pht(
'Publisher key "%s" is not valid: publisher keys may only contain '.
'lowercase latin letters.',
$value));
}
}
/* -( PhabricatorSubscribableInterface )----------------------------------- */
public function isAutomaticallySubscribed($phid) {
return false;
}
/* -( Policy Interface )--------------------------------------------------- */
public function getCapabilities() {
return array(
PhabricatorPolicyCapability::CAN_VIEW,
PhabricatorPolicyCapability::CAN_EDIT,
);
}
public function getPolicy($capability) {
switch ($capability) {
case PhabricatorPolicyCapability::CAN_VIEW:
return PhabricatorPolicies::getMostOpenPolicy();
case PhabricatorPolicyCapability::CAN_EDIT:
return $this->getEditPolicy();
}
}
public function hasAutomaticCapability($capability, PhabricatorUser $user) {
return false;
}
public function describeAutomaticCapability($capability) {
return null;
}
/* -( PhabricatorDestructibleInterface )----------------------------------- */
public function destroyObjectPermanently(
PhabricatorDestructionEngine $engine) {
$this->delete();
}
/* -( PhabricatorApplicationTransactionInterface )------------------------- */
public function getApplicationTransactionEditor() {
return new PhabricatorPackagesPublisherEditor();
}
public function getApplicationTransactionObject() {
return $this;
}
public function getApplicationTransactionTemplate() {
return new PhabricatorPackagesPublisherTransaction();
}
public function willRenderTimeline(
PhabricatorApplicationTransactionView $timeline,
AphrontRequest $request) {
return $timeline;
}
/* -( PhabricatorConduitResultInterface )---------------------------------- */
public function getFieldSpecificationsForConduit() {
return array(
id(new PhabricatorConduitSearchFieldSpecification())
->setKey('name')
->setType('string')
->setDescription(pht('The name of the publisher.')),
id(new PhabricatorConduitSearchFieldSpecification())
->setKey('publisherKey')
->setType('string')
->setDescription(pht('The unique key of the publisher.')),
);
}
public function getFieldValuesForConduit() {
return array(
'name' => $this->getName(),
'publisherKey' => $this->getPublisherKey(),
);
}
public function getConduitSearchAttachments() {
return array();
}
}

View file

@ -0,0 +1,18 @@
<?php
final class PhabricatorPackagesPublisherTransaction
extends PhabricatorModularTransaction {
public function getApplicationName() {
return 'packages';
}
public function getApplicationTransactionType() {
return PhabricatorPackagesPublisherPHIDType::TYPECONST;
}
public function getBaseTransactionClass() {
return 'PhabricatorPackagesPublisherTransactionType';
}
}

View file

@ -0,0 +1,10 @@
<?php
final class PhabricatorPackagesSchemaSpec
extends PhabricatorConfigSchemaSpec {
public function buildSchemata() {
$this->buildEdgeSchemata(new PhabricatorPackagesPublisher());
}
}

View file

@ -0,0 +1,4 @@
<?php
abstract class PhabricatorPackagesTransactionType
extends PhabricatorModularTransactionType {}

View file

@ -0,0 +1,44 @@
<?php
final class PhabricatorPackagesPublisherKeyTransaction
extends PhabricatorPackagesPublisherTransactionType {
const TRANSACTIONTYPE = 'packages.publisher.key';
public function generateOldValue($object) {
return $object->getPublisherKey();
}
public function applyInternalEffects($object, $value) {
$object->setPublisherKey($value);
}
public function validateTransactions($object, array $xactions) {
$errors = array();
if ($this->isEmptyTextTransaction($object->getName(), $xactions)) {
$errors[] = $this->newRequiredError(
pht('Publishers must have a unique publisher key.'));
}
if (!$this->isNewObject()) {
foreach ($xactions as $xaction) {
$errors[] = $this->newInvalidError(
pht('Once a publisher is created, its key can not be changed.'),
$xaction);
}
}
foreach ($xactions as $xaction) {
$value = $xaction->getNewValue();
try {
PhabricatorPackagesPublisher::assertValidPublisherKey($value);
} catch (Exception $ex) {
$errors[] = $this->newInvalidError($ex->getMessage(), $xaction);
}
}
return $errors;
}
}

View file

@ -0,0 +1,53 @@
<?php
final class PhabricatorPackagesPublisherNameTransaction
extends PhabricatorPackagesPublisherTransactionType {
const TRANSACTIONTYPE = 'packages.publisher.name';
public function generateOldValue($object) {
return $object->getName();
}
public function applyInternalEffects($object, $value) {
$object->setName($value);
}
public function getTitle() {
return pht(
'%s changed the name of this publisher from %s to %s.',
$this->renderAuthor(),
$this->renderOldValue(),
$this->renderNewValue());
}
public function getTitleForFeed() {
return pht(
'%s updated the name for %s from %s to %s.',
$this->renderAuthor(),
$this->renderObject(),
$this->renderOldValue(),
$this->renderNewValue());
}
public function validateTransactions($object, array $xactions) {
$errors = array();
if ($this->isEmptyTextTransaction($object->getName(), $xactions)) {
$errors[] = $this->newRequiredError(
pht('Publishers must have a name.'));
}
foreach ($xactions as $xaction) {
$value = $xaction->getNewValue();
try {
PhabricatorPackagesPublisher::assertValidPublisherName($value);
} catch (Exception $ex) {
$errors[] = $this->newInvalidError($ex->getMessage(), $xaction);
}
}
return $errors;
}
}

View file

@ -0,0 +1,4 @@
<?php
abstract class PhabricatorPackagesPublisherTransactionType
extends PhabricatorPackagesTransactionType {}

View file

@ -111,6 +111,7 @@ final class PhabricatorBuiltinPatchList extends PhabricatorSQLPatchList {
'db.spaces' => array(), 'db.spaces' => array(),
'db.phurl' => array(), 'db.phurl' => array(),
'db.badges' => array(), 'db.badges' => array(),
'db.packages' => array(),
'0000.legacy.sql' => array( '0000.legacy.sql' => array(
'legacy' => 0, 'legacy' => 0,
), ),