1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-25 16:22:43 +01:00

Add PackagesVersion

Summary:
Ref T8116. A version has:

  - a package (like "Arcanist") which it belongs to;
  - a name (like "v3.1.5").

The name is immutable and unique, like the package key and publisher key.

Policy stuff:

  - Versions have the exact same policies as their packages.
  - You must be able to edit a package to create new versions of it.

This is still entirely uninteresting.

Test Plan: {F1731703}

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T8116

Differential Revision: https://secure.phabricator.com/D16316
This commit is contained in:
epriestley 2016-07-21 12:11:11 -07:00
parent 704afea281
commit ee37eca2e4
26 changed files with 1095 additions and 27 deletions

View file

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

View file

@ -0,0 +1,19 @@
CREATE TABLE {$NAMESPACE}_packages.packages_versiontransaction (
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

@ -2979,6 +2979,7 @@ phutil_register_library_map(array(
'PhabricatorPackagesEditor' => 'applications/packages/editor/PhabricatorPackagesEditor.php',
'PhabricatorPackagesPackage' => 'applications/packages/storage/PhabricatorPackagesPackage.php',
'PhabricatorPackagesPackageController' => 'applications/packages/controller/PhabricatorPackagesPackageController.php',
'PhabricatorPackagesPackageDatasource' => 'applications/packages/typeahead/PhabricatorPackagesPackageDatasource.php',
'PhabricatorPackagesPackageEditConduitAPIMethod' => 'applications/packages/conduit/PhabricatorPackagesPackageEditConduitAPIMethod.php',
'PhabricatorPackagesPackageEditController' => 'applications/packages/controller/PhabricatorPackagesPackageEditController.php',
'PhabricatorPackagesPackageEditEngine' => 'applications/packages/editor/PhabricatorPackagesPackageEditEngine.php',
@ -3016,6 +3017,23 @@ phutil_register_library_map(array(
'PhabricatorPackagesQuery' => 'applications/packages/query/PhabricatorPackagesQuery.php',
'PhabricatorPackagesSchemaSpec' => 'applications/packages/storage/PhabricatorPackagesSchemaSpec.php',
'PhabricatorPackagesTransactionType' => 'applications/packages/xaction/PhabricatorPackagesTransactionType.php',
'PhabricatorPackagesVersion' => 'applications/packages/storage/PhabricatorPackagesVersion.php',
'PhabricatorPackagesVersionController' => 'applications/packages/controller/PhabricatorPackagesVersionController.php',
'PhabricatorPackagesVersionEditConduitAPIMethod' => 'applications/packages/conduit/PhabricatorPackagesVersionEditConduitAPIMethod.php',
'PhabricatorPackagesVersionEditController' => 'applications/packages/controller/PhabricatorPackagesVersionEditController.php',
'PhabricatorPackagesVersionEditEngine' => 'applications/packages/editor/PhabricatorPackagesVersionEditEngine.php',
'PhabricatorPackagesVersionEditor' => 'applications/packages/editor/PhabricatorPackagesVersionEditor.php',
'PhabricatorPackagesVersionListController' => 'applications/packages/controller/PhabricatorPackagesVersionListController.php',
'PhabricatorPackagesVersionNameTransaction' => 'applications/packages/xaction/version/PhabricatorPackagesVersionNameTransaction.php',
'PhabricatorPackagesVersionPHIDType' => 'applications/packages/phid/PhabricatorPackagesVersionPHIDType.php',
'PhabricatorPackagesVersionPackageTransaction' => 'applications/packages/xaction/version/PhabricatorPackagesVersionPackageTransaction.php',
'PhabricatorPackagesVersionQuery' => 'applications/packages/query/PhabricatorPackagesVersionQuery.php',
'PhabricatorPackagesVersionSearchConduitAPIMethod' => 'applications/packages/conduit/PhabricatorPackagesVersionSearchConduitAPIMethod.php',
'PhabricatorPackagesVersionSearchEngine' => 'applications/packages/query/PhabricatorPackagesVersionSearchEngine.php',
'PhabricatorPackagesVersionTransaction' => 'applications/packages/storage/PhabricatorPackagesVersionTransaction.php',
'PhabricatorPackagesVersionTransactionQuery' => 'applications/packages/query/PhabricatorPackagesVersionTransactionQuery.php',
'PhabricatorPackagesVersionTransactionType' => 'applications/packages/xaction/version/PhabricatorPackagesVersionTransactionType.php',
'PhabricatorPackagesVersionViewController' => 'applications/packages/controller/PhabricatorPackagesVersionViewController.php',
'PhabricatorPagerUIExample' => 'applications/uiexample/examples/PhabricatorPagerUIExample.php',
'PhabricatorPassphraseApplication' => 'applications/passphrase/application/PhabricatorPassphraseApplication.php',
'PhabricatorPasswordAuthProvider' => 'applications/auth/provider/PhabricatorPasswordAuthProvider.php',
@ -7784,6 +7802,7 @@ phutil_register_library_map(array(
'PhabricatorConduitResultInterface',
),
'PhabricatorPackagesPackageController' => 'PhabricatorPackagesController',
'PhabricatorPackagesPackageDatasource' => 'PhabricatorTypeaheadDatasource',
'PhabricatorPackagesPackageEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod',
'PhabricatorPackagesPackageEditController' => 'PhabricatorPackagesPackageController',
'PhabricatorPackagesPackageEditEngine' => 'PhabricatorPackagesEditEngine',
@ -7829,6 +7848,32 @@ phutil_register_library_map(array(
'PhabricatorPackagesQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorPackagesSchemaSpec' => 'PhabricatorConfigSchemaSpec',
'PhabricatorPackagesTransactionType' => 'PhabricatorModularTransactionType',
'PhabricatorPackagesVersion' => array(
'PhabricatorPackagesDAO',
'PhabricatorPolicyInterface',
'PhabricatorExtendedPolicyInterface',
'PhabricatorApplicationTransactionInterface',
'PhabricatorDestructibleInterface',
'PhabricatorSubscribableInterface',
'PhabricatorProjectInterface',
'PhabricatorConduitResultInterface',
),
'PhabricatorPackagesVersionController' => 'PhabricatorPackagesController',
'PhabricatorPackagesVersionEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod',
'PhabricatorPackagesVersionEditController' => 'PhabricatorPackagesVersionController',
'PhabricatorPackagesVersionEditEngine' => 'PhabricatorPackagesEditEngine',
'PhabricatorPackagesVersionEditor' => 'PhabricatorPackagesEditor',
'PhabricatorPackagesVersionListController' => 'PhabricatorPackagesVersionController',
'PhabricatorPackagesVersionNameTransaction' => 'PhabricatorPackagesVersionTransactionType',
'PhabricatorPackagesVersionPHIDType' => 'PhabricatorPHIDType',
'PhabricatorPackagesVersionPackageTransaction' => 'PhabricatorPackagesVersionTransactionType',
'PhabricatorPackagesVersionQuery' => 'PhabricatorPackagesQuery',
'PhabricatorPackagesVersionSearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod',
'PhabricatorPackagesVersionSearchEngine' => 'PhabricatorApplicationSearchEngine',
'PhabricatorPackagesVersionTransaction' => 'PhabricatorModularTransaction',
'PhabricatorPackagesVersionTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
'PhabricatorPackagesVersionTransactionType' => 'PhabricatorPackagesTransactionType',
'PhabricatorPackagesVersionViewController' => 'PhabricatorPackagesVersionController',
'PhabricatorPagerUIExample' => 'PhabricatorUIExample',
'PhabricatorPassphraseApplication' => 'PhabricatorApplication',
'PhabricatorPasswordAuthProvider' => 'PhabricatorAuthProvider',

View file

@ -33,6 +33,8 @@ final class PhabricatorPackagesApplication extends PhabricatorApplication {
'' => 'PhabricatorPackagesPublisherViewController',
'(?P<packageKey>[^/]+)/' => array(
'' => 'PhabricatorPackagesPackageViewController',
'(?P<versionKey>[^/]+)/' =>
'PhabricatorPackagesVersionViewController',
),
),
),
@ -49,6 +51,12 @@ final class PhabricatorPackagesApplication extends PhabricatorApplication {
$this->getEditRoutePattern('edit/') =>
'PhabricatorPackagesPackageEditController',
),
'version/' => array(
$this->getQueryRoutePattern() =>
'PhabricatorPackagesVersionListController',
$this->getEditRoutePattern('edit/') =>
'PhabricatorPackagesVersionEditController',
),
),
);
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -0,0 +1,91 @@
<?php
final class PhabricatorPackagesVersionViewController
extends PhabricatorPackagesVersionController {
public function shouldAllowPublic() {
return true;
}
public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer();
$publisher_key = $request->getURIData('publisherKey');
$package_key = $request->getURIData('packageKey');
$full_key = $publisher_key.'/'.$package_key;
$version_key = $request->getURIData('versionKey');
$version = id(new PhabricatorPackagesVersionQuery())
->setViewer($viewer)
->withFullKeys(array($full_key))
->withNames(array($version_key))
->executeOne();
if (!$version) {
return new Aphront404Response();
}
$package = $version->getPackage();
$publisher = $package->getPublisher();
$crumbs = $this->buildApplicationCrumbs()
->addTextCrumb($publisher->getName(), $publisher->getURI())
->addTextCrumb($package->getName(), $package->getURI())
->addTextCrumb($version->getName())
->setBorder(true);
$header = $this->buildHeaderView($version);
$curtain = $this->buildCurtain($version);
$timeline = $this->buildTransactionTimeline(
$version,
new PhabricatorPackagesVersionTransactionQuery());
$version_view = id(new PHUITwoColumnView())
->setHeader($header)
->setCurtain($curtain)
->setMainColumn($timeline);
return $this->newPage()
->setCrumbs($crumbs)
->setPageObjectPHIDs(
array(
$version->getPHID(),
))
->appendChild($version_view);
}
private function buildHeaderView(PhabricatorPackagesVersion $version) {
$viewer = $this->getViewer();
$name = $version->getName();
return id(new PHUIHeaderView())
->setViewer($viewer)
->setHeader($name)
->setPolicyObject($version)
->setHeaderIcon('fa-tag');
}
private function buildCurtain(PhabricatorPackagesVersion $version) {
$viewer = $this->getViewer();
$curtain = $this->newCurtainView($version);
$can_edit = PhabricatorPolicyFilter::hasCapability(
$viewer,
$version,
PhabricatorPolicyCapability::CAN_EDIT);
$id = $version->getID();
$edit_uri = $this->getApplicationURI("version/edit/{$id}/");
$curtain->addAction(
id(new PhabricatorActionView())
->setName(pht('Edit Version'))
->setIcon('fa-pencil')
->setDisabled(!$can_edit)
->setHref($edit_uri));
return $curtain;
}
}

View file

@ -0,0 +1,93 @@
<?php
final class PhabricatorPackagesVersionEditEngine
extends PhabricatorPackagesEditEngine {
const ENGINECONST = 'packages.version';
public function getEngineName() {
return pht('Package Versions');
}
public function getSummaryHeader() {
return pht('Edit Package Version Configurations');
}
public function getSummaryText() {
return pht('This engine is used to edit Packages versions.');
}
protected function newEditableObject() {
$viewer = $this->getViewer();
return PhabricatorPackagesVersion::initializeNewVersion($viewer);
}
protected function newObjectQuery() {
return new PhabricatorPackagesVersionQuery();
}
protected function getObjectCreateTitleText($object) {
return pht('Create Version');
}
protected function getObjectCreateButtonText($object) {
return pht('Create Version');
}
protected function getObjectEditTitleText($object) {
return pht('Edit Version: %s', $object->getName());
}
protected function getObjectEditShortText($object) {
return pht('Edit Version');
}
protected function getObjectCreateShortText() {
return pht('Create Version');
}
protected function getObjectName() {
return pht('Version');
}
protected function getEditorURI() {
return '/packages/version/edit/';
}
protected function getObjectCreateCancelURI($object) {
return '/packages/version/';
}
protected function getObjectViewURI($object) {
return $object->getURI();
}
protected function buildCustomEditFields($object) {
$fields = array();
if ($this->getIsCreate()) {
$fields[] = id(new PhabricatorDatasourceEditField())
->setKey('package')
->setAliases(array('packagePHID'))
->setLabel(pht('Package'))
->setDescription(pht('Package for this version.'))
->setTransactionType(
PhabricatorPackagesVersionPackageTransaction::TRANSACTIONTYPE)
->setIsRequired(true)
->setDatasource(new PhabricatorPackagesPackageDatasource())
->setSingleValue($object->getPackagePHID());
$fields[] = id(new PhabricatorTextEditField())
->setKey('name')
->setLabel(pht('Name'))
->setDescription(pht('Name of the version.'))
->setTransactionType(
PhabricatorPackagesVersionNameTransaction::TRANSACTIONTYPE)
->setIsRequired(true)
->setValue($object->getName());
}
return $fields;
}
}

View file

@ -0,0 +1,46 @@
<?php
final class PhabricatorPackagesVersionEditor
extends PhabricatorPackagesEditor {
public function getEditorObjectsDescription() {
return pht('Package Versions');
}
public function getCreateObjectTitle($author, $object) {
return pht('%s created this version.', $author);
}
public function getCreateObjectTitleForFeed($author, $object) {
return pht('%s created %s.', $author, $object);
}
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(
PhabricatorPackagesVersionNameTransaction::TRANSACTIONTYPE,
pht('Duplicate'),
pht(
'The version "%s" already exists for this package. Each version '.
'must have a unique name.',
$object->getName()),
null);
throw new PhabricatorApplicationTransactionValidationException($errors);
}
}

View file

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

View file

@ -74,31 +74,8 @@ final class PhabricatorPackagesPackageQuery
}
if ($this->fullKeys !== null) {
$parts = array();
foreach ($this->fullKeys as $full_key) {
$key_parts = explode('/', $full_key, 2);
if (count($key_parts) != 2) {
continue;
}
$parts[] = qsprintf(
$conn,
'(u.publisherKey = %s AND p.packageKey = %s)',
$key_parts[0],
$key_parts[1]);
}
// If none of the full keys we were provided were valid, we don't
// match any results.
if (!$parts) {
throw new PhabricatorEmptyQueryException();
}
$where[] = qsprintf(
$conn,
'%Q',
implode(' OR ', $parts));
$parts = $this->buildFullKeyClauseParts($conn, $this->fullKeys);
$where[] = qsprintf($conn, '%Q', $parts);
}
return $where;

View file

@ -7,4 +7,32 @@ abstract class PhabricatorPackagesQuery
return 'PhabricatorPackagesApplication';
}
protected function buildFullKeyClauseParts(
AphrontDatabaseConnection $conn,
array $full_keys) {
$parts = array();
foreach ($full_keys as $full_key) {
$key_parts = explode('/', $full_key, 2);
if (count($key_parts) != 2) {
continue;
}
$parts[] = qsprintf(
$conn,
'(u.publisherKey = %s AND p.packageKey = %s)',
$key_parts[0],
$key_parts[1]);
}
// If none of the full keys we were provided were valid, we don't
// match any results.
if (!$parts) {
throw new PhabricatorEmptyQueryException();
}
return implode(' OR ', $parts);
}
}

View file

@ -0,0 +1,141 @@
<?php
final class PhabricatorPackagesVersionQuery
extends PhabricatorPackagesQuery {
private $ids;
private $phids;
private $packagePHIDs;
private $fullKeys;
private $names;
public function withIDs(array $ids) {
$this->ids = $ids;
return $this;
}
public function withPHIDs(array $phids) {
$this->phids = $phids;
return $this;
}
public function withPackagePHIDs(array $phids) {
$this->packagePHIDs = $phids;
return $this;
}
public function withFullKeys(array $keys) {
$this->fullKeys = $keys;
return $this;
}
public function withNames(array $names) {
$this->names = $names;
return $this;
}
public function newResultObject() {
return new PhabricatorPackagesVersion();
}
protected function loadPage() {
return $this->loadStandardPage($this->newResultObject());
}
protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {
$where = parent::buildWhereClauseParts($conn);
if ($this->ids !== null) {
$where[] = qsprintf(
$conn,
'v.id IN (%Ld)',
$this->ids);
}
if ($this->phids !== null) {
$where[] = qsprintf(
$conn,
'v.phid IN (%Ls)',
$this->phids);
}
if ($this->packagePHIDs !== null) {
$where[] = qsprintf(
$conn,
'v.packagePHID IN (%Ls)',
$this->packagePHIDs);
}
if ($this->names !== null) {
$where[] = qsprintf(
$conn,
'v.name IN (%Ls)',
$this->names);
}
if ($this->fullKeys !== null) {
$parts = $this->buildFullKeyClauseParts($conn, $this->fullKeys);
$where[] = qsprintf($conn, '%Q', $parts);
}
return $where;
}
protected function buildJoinClauseParts(AphrontDatabaseConnection $conn) {
$joins = parent::buildJoinClauseParts($conn);
$join_publisher = ($this->fullKeys !== null);
$join_package = ($this->fullKeys !== null) || $join_publisher;
if ($join_package) {
$package_table = new PhabricatorPackagesPackage();
$joins[] = qsprintf(
$conn,
'JOIN %T p ON v.packagePHID = p.phid',
$package_table->getTableName());
}
if ($join_publisher) {
$publisher_table = new PhabricatorPackagesPublisher();
$joins[] = qsprintf(
$conn,
'JOIN %T u ON u.phid = p.publisherPHID',
$publisher_table->getTableName());
}
return $joins;
}
protected function willFilterPage(array $versions) {
$package_phids = mpull($versions, 'getPackagePHID');
$packages = id(new PhabricatorPackagesPackageQuery())
->setViewer($this->getViewer())
->setParentQuery($this)
->withPHIDs($package_phids)
->execute();
$packages = mpull($packages, null, 'getPHID');
foreach ($versions as $key => $version) {
$package = idx($packages, $version->getPackagePHID());
if (!$package) {
unset($versions[$key]);
$this->didRejectResult($version);
continue;
}
$version->attachPackage($package);
}
return $versions;
}
protected function getPrimaryTableAlias() {
return 'v';
}
}

View file

@ -0,0 +1,76 @@
<?php
final class PhabricatorPackagesVersionSearchEngine
extends PhabricatorApplicationSearchEngine {
public function getResultTypeDescription() {
return pht('Package Versions');
}
public function getApplicationClassName() {
return 'PhabricatorPackagesApplication';
}
public function newQuery() {
return id(new PhabricatorPackagesVersionQuery());
}
protected function buildQueryFromParameters(array $map) {
$query = $this->newQuery();
return $query;
}
protected function buildCustomSearchFields() {
return array();
}
protected function getURI($path) {
return '/packages/version/'.$path;
}
protected function getBuiltinQueryNames() {
$names = array(
'all' => pht('All Versions'),
);
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 $versions,
PhabricatorSavedQuery $query,
array $handles) {
assert_instances_of($versions, 'PhabricatorPackagesVersion');
$viewer = $this->requireViewer();
$list = id(new PHUIObjectItemListView())
->setViewer($viewer);
foreach ($versions as $version) {
$item = id(new PHUIObjectItemView())
->setHeader($version->getName())
->setHref($version->getURI());
$list->addItem($item);
}
return id(new PhabricatorApplicationSearchResultView())
->setObjectList($list)
->setNoDataString(pht('No versions found.'));
}
}

View file

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

View file

@ -154,7 +154,21 @@ final class PhabricatorPackagesPackage
public function destroyObjectPermanently(
PhabricatorDestructionEngine $engine) {
$viewer = $engine->getViewer();
$this->openTransaction();
$versions = id(new PhabricatorPackagesVersionQuery())
->setViewer($viewer)
->withPackagePHIDs(array($this->getPHID()))
->execute();
foreach ($versions as $version) {
$engine->destroyObject($version);
}
$this->delete();
$this->saveTransaction();
}

View file

@ -0,0 +1,200 @@
<?php
final class PhabricatorPackagesVersion
extends PhabricatorPackagesDAO
implements
PhabricatorPolicyInterface,
PhabricatorExtendedPolicyInterface,
PhabricatorApplicationTransactionInterface,
PhabricatorDestructibleInterface,
PhabricatorSubscribableInterface,
PhabricatorProjectInterface,
PhabricatorConduitResultInterface {
protected $name;
protected $packagePHID;
private $package;
public static function initializeNewVersion(PhabricatorUser $actor) {
return id(new self());
}
protected function getConfiguration() {
return array(
self::CONFIG_AUX_PHID => true,
self::CONFIG_COLUMN_SCHEMA => array(
'name' => 'sort64',
),
self::CONFIG_KEY_SCHEMA => array(
'key_package' => array(
'columns' => array('packagePHID', 'name'),
'unique' => true,
),
),
) + parent::getConfiguration();
}
public function generatePHID() {
return PhabricatorPHID::generateNewPHID(
PhabricatorPackagesVersionPHIDType::TYPECONST);
}
public function getURI() {
$package = $this->getPackage();
$full_key = $package->getFullKey();
$name = $this->getName();
return "/package/{$full_key}/{$name}/";
}
public function attachPackage(PhabricatorPackagesPackage $package) {
$this->package = $package;
return $this;
}
public function getPackage() {
return $this->assertAttached($this->package);
}
public static function assertValidVersionName($value) {
$length = phutil_utf8_strlen($value);
if (!$length) {
throw new Exception(
pht(
'Version name "%s" is not valid: version names are required.',
$value));
}
$max_length = 64;
if ($length > $max_length) {
throw new Exception(
pht(
'Version name "%s" is not valid: version names must not be '.
'more than %s characters long.',
$value,
new PhutilNumber($max_length)));
}
if (!preg_match('/^[A-Za-z0-9.-]+\z/', $value)) {
throw new Exception(
pht(
'Version name "%s" is not valid: version names may only contain '.
'latin letters, digits, periods, and hyphens.',
$value));
}
if (preg_match('/^[.-]|[.-]$/', $value)) {
throw new Exception(
pht(
'Version name "%s" is not valid: version names may not start or '.
'end with a period or hyphen.',
$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 PhabricatorPolicies::POLICY_USER;
}
}
public function hasAutomaticCapability($capability, PhabricatorUser $user) {
return false;
}
public function describeAutomaticCapability($capability) {
return null;
}
/* -( PhabricatorExtendedPolicyInterface )--------------------------------- */
public function getExtendedPolicy($capability, PhabricatorUser $viewer) {
return array(
array(
$this->getPackage(),
$capability,
),
);
}
/* -( PhabricatorDestructibleInterface )----------------------------------- */
public function destroyObjectPermanently(
PhabricatorDestructionEngine $engine) {
$this->delete();
}
/* -( PhabricatorApplicationTransactionInterface )------------------------- */
public function getApplicationTransactionEditor() {
return new PhabricatorPackagesVersionEditor();
}
public function getApplicationTransactionObject() {
return $this;
}
public function getApplicationTransactionTemplate() {
return new PhabricatorPackagesVersionTransaction();
}
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 version.')),
);
}
public function getFieldValuesForConduit() {
return array(
'name' => $this->getName(),
);
}
public function getConduitSearchAttachments() {
return array();
}
}

View file

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

View file

@ -0,0 +1,35 @@
<?php
final class PhabricatorPackagesPackageDatasource
extends PhabricatorTypeaheadDatasource {
public function getBrowseTitle() {
return pht('Browse Packagess');
}
public function getPlaceholderText() {
return pht('Type a package name...');
}
public function getDatasourceApplicationClass() {
return 'PhabricatorPackagesApplication';
}
public function loadResults() {
$viewer = $this->getViewer();
$raw_query = $this->getRawQuery();
$package_query = id(new PhabricatorPackagesPackageQuery());
$packages = $this->executeQuery($package_query);
$results = array();
foreach ($packages as $package) {
$results[] = id(new PhabricatorTypeaheadResult())
->setName($package->getName())
->setPHID($package->getPHID());
}
return $this->filterResultsAgainstTokens($results);
}
}

View file

@ -16,7 +16,8 @@ final class PhabricatorPackagesPackagePublisherTransaction
public function validateTransactions($object, array $xactions) {
$errors = array();
if ($this->isEmptyTextTransaction($object->getName(), $xactions)) {
$current_value = $object->getPublisherPHID();
if ($this->isEmptyTextTransaction($current_value, $xactions)) {
$errors[] = $this->newRequiredError(
pht(
'You must select a publisher when creating a package.'));

View file

@ -0,0 +1,62 @@
<?php
final class PhabricatorPackagesVersionNameTransaction
extends PhabricatorPackagesVersionTransactionType {
const TRANSACTIONTYPE = 'packages.version.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 version 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('Versions must have a name.'));
return $errors;
}
foreach ($xactions as $xaction) {
$value = $xaction->getNewValue();
try {
PhabricatorPackagesVersion::assertValidVersionName($value);
} catch (Exception $ex) {
$errors[] = $this->newInvalidError($ex->getMessage(), $xaction);
}
}
if (!$this->isNewObject()) {
foreach ($xactions as $xaction) {
$errors[] = $this->newInvalidError(
pht('Once a version is created, its name can not be changed.'),
$xaction);
}
}
return $errors;
}
}

View file

@ -0,0 +1,66 @@
<?php
final class PhabricatorPackagesVersionPackageTransaction
extends PhabricatorPackagesVersionTransactionType {
const TRANSACTIONTYPE = 'packages.version.package';
public function generateOldValue($object) {
return $object->getPackagePHID();
}
public function applyInternalEffects($object, $value) {
$object->setPackagePHID($value);
}
public function validateTransactions($object, array $xactions) {
$errors = array();
if ($this->isEmptyTextTransaction($object->getPackagePHID(), $xactions)) {
$errors[] = $this->newRequiredError(
pht(
'You must select a package when creating a version'));
return $errors;
}
if (!$this->isNewObject()) {
foreach ($xactions as $xaction) {
$errors[] = $this->newInvalidError(
pht('Once a version is created, its package can not be changed.'),
$xaction);
}
}
$viewer = $this->getActor();
foreach ($xactions as $xaction) {
$package_phid = $xaction->getNewValue();
$package = id(new PhabricatorPackagesPackageQuery())
->setViewer($viewer)
->withPHIDs(array($package_phid))
->setRaisePolicyExceptions(false)
->requireCapabilities(
array(
PhabricatorPolicyCapability::CAN_VIEW,
PhabricatorPolicyCapability::CAN_EDIT,
))
->executeOne();
if (!$package) {
$errors[] = $this->newInvalidError(
pht(
'Package "%s" is invalid: the package must exist and you '.
'must have permission to edit it in order to create a new '.
'package.',
$package_phid),
$xaction);
continue;
}
$object->attachPackage($package);
}
return $errors;
}
}

View file

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