diff --git a/resources/sql/autopatches/20160721.pack.06.version.sql b/resources/sql/autopatches/20160721.pack.06.version.sql new file mode 100644 --- /dev/null +++ b/resources/sql/autopatches/20160721.pack.06.version.sql @@ -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}; diff --git a/resources/sql/autopatches/20160721.pack.07.versionxaction.sql b/resources/sql/autopatches/20160721.pack.07.versionxaction.sql new file mode 100644 --- /dev/null +++ b/resources/sql/autopatches/20160721.pack.07.versionxaction.sql @@ -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}; diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -2978,6 +2978,7 @@ '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', @@ -3015,6 +3016,23 @@ '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', @@ -7782,6 +7800,7 @@ 'PhabricatorConduitResultInterface', ), 'PhabricatorPackagesPackageController' => 'PhabricatorPackagesController', + 'PhabricatorPackagesPackageDatasource' => 'PhabricatorTypeaheadDatasource', 'PhabricatorPackagesPackageEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod', 'PhabricatorPackagesPackageEditController' => 'PhabricatorPackagesPackageController', 'PhabricatorPackagesPackageEditEngine' => 'PhabricatorPackagesEditEngine', @@ -7827,6 +7846,32 @@ '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', diff --git a/src/applications/packages/application/PhabricatorPackagesApplication.php b/src/applications/packages/application/PhabricatorPackagesApplication.php --- a/src/applications/packages/application/PhabricatorPackagesApplication.php +++ b/src/applications/packages/application/PhabricatorPackagesApplication.php @@ -33,6 +33,8 @@ '' => 'PhabricatorPackagesPublisherViewController', '(?P[^/]+)/' => array( '' => 'PhabricatorPackagesPackageViewController', + '(?P[^/]+)/' => + 'PhabricatorPackagesVersionViewController', ), ), ), @@ -49,6 +51,12 @@ $this->getEditRoutePattern('edit/') => 'PhabricatorPackagesPackageEditController', ), + 'version/' => array( + $this->getQueryRoutePattern() => + 'PhabricatorPackagesVersionListController', + $this->getEditRoutePattern('edit/') => + 'PhabricatorPackagesVersionEditController', + ), ), ); } diff --git a/src/applications/packages/conduit/PhabricatorPackagesVersionEditConduitAPIMethod.php b/src/applications/packages/conduit/PhabricatorPackagesVersionEditConduitAPIMethod.php new file mode 100644 --- /dev/null +++ b/src/applications/packages/conduit/PhabricatorPackagesVersionEditConduitAPIMethod.php @@ -0,0 +1,19 @@ +setController($this) + ->buildResponse(); + } + +} diff --git a/src/applications/packages/controller/PhabricatorPackagesVersionListController.php b/src/applications/packages/controller/PhabricatorPackagesVersionListController.php new file mode 100644 --- /dev/null +++ b/src/applications/packages/controller/PhabricatorPackagesVersionListController.php @@ -0,0 +1,26 @@ +setController($this) + ->buildResponse(); + } + + protected function buildApplicationCrumbs() { + $crumbs = parent::buildApplicationCrumbs(); + + id(new PhabricatorPackagesVersionEditEngine()) + ->setViewer($this->getViewer()) + ->addActionToCrumbs($crumbs); + + return $crumbs; + } + +} diff --git a/src/applications/packages/controller/PhabricatorPackagesVersionViewController.php b/src/applications/packages/controller/PhabricatorPackagesVersionViewController.php new file mode 100644 --- /dev/null +++ b/src/applications/packages/controller/PhabricatorPackagesVersionViewController.php @@ -0,0 +1,91 @@ +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-paw'); + } + + 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; + } + +} diff --git a/src/applications/packages/editor/PhabricatorPackagesVersionEditEngine.php b/src/applications/packages/editor/PhabricatorPackagesVersionEditEngine.php new file mode 100644 --- /dev/null +++ b/src/applications/packages/editor/PhabricatorPackagesVersionEditEngine.php @@ -0,0 +1,93 @@ +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; + } + +} diff --git a/src/applications/packages/editor/PhabricatorPackagesVersionEditor.php b/src/applications/packages/editor/PhabricatorPackagesVersionEditor.php new file mode 100644 --- /dev/null +++ b/src/applications/packages/editor/PhabricatorPackagesVersionEditor.php @@ -0,0 +1,46 @@ +getName()), + null); + + throw new PhabricatorApplicationTransactionValidationException($errors); + } + +} diff --git a/src/applications/packages/phid/PhabricatorPackagesVersionPHIDType.php b/src/applications/packages/phid/PhabricatorPackagesVersionPHIDType.php new file mode 100644 --- /dev/null +++ b/src/applications/packages/phid/PhabricatorPackagesVersionPHIDType.php @@ -0,0 +1,45 @@ +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); + } + } + +} diff --git a/src/applications/packages/query/PhabricatorPackagesPackageQuery.php b/src/applications/packages/query/PhabricatorPackagesPackageQuery.php --- a/src/applications/packages/query/PhabricatorPackagesPackageQuery.php +++ b/src/applications/packages/query/PhabricatorPackagesPackageQuery.php @@ -74,31 +74,8 @@ } 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; diff --git a/src/applications/packages/query/PhabricatorPackagesQuery.php b/src/applications/packages/query/PhabricatorPackagesQuery.php --- a/src/applications/packages/query/PhabricatorPackagesQuery.php +++ b/src/applications/packages/query/PhabricatorPackagesQuery.php @@ -7,4 +7,32 @@ 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); + } + } diff --git a/src/applications/packages/query/PhabricatorPackagesVersionQuery.php b/src/applications/packages/query/PhabricatorPackagesVersionQuery.php new file mode 100644 --- /dev/null +++ b/src/applications/packages/query/PhabricatorPackagesVersionQuery.php @@ -0,0 +1,141 @@ +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'; + } + + +} diff --git a/src/applications/packages/query/PhabricatorPackagesVersionSearchEngine.php b/src/applications/packages/query/PhabricatorPackagesVersionSearchEngine.php new file mode 100644 --- /dev/null +++ b/src/applications/packages/query/PhabricatorPackagesVersionSearchEngine.php @@ -0,0 +1,76 @@ +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.')); + } + +} diff --git a/src/applications/packages/query/PhabricatorPackagesVersionTransactionQuery.php b/src/applications/packages/query/PhabricatorPackagesVersionTransactionQuery.php new file mode 100644 --- /dev/null +++ b/src/applications/packages/query/PhabricatorPackagesVersionTransactionQuery.php @@ -0,0 +1,10 @@ +delete(); + $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(); } diff --git a/src/applications/packages/storage/PhabricatorPackagesPackage.php b/src/applications/packages/storage/PhabricatorPackagesVersion.php copy from src/applications/packages/storage/PhabricatorPackagesPackage.php copy to src/applications/packages/storage/PhabricatorPackagesVersion.php --- a/src/applications/packages/storage/PhabricatorPackagesPackage.php +++ b/src/applications/packages/storage/PhabricatorPackagesVersion.php @@ -1,9 +1,10 @@ true, self::CONFIG_COLUMN_SCHEMA => array( - 'name' => 'text64', - 'packageKey' => 'sort64', + 'name' => 'sort64', ), self::CONFIG_KEY_SCHEMA => array( 'key_package' => array( - 'columns' => array('publisherPHID', 'packageKey'), + 'columns' => array('packagePHID', 'name'), 'unique' => true, ), ), @@ -40,36 +37,32 @@ public function generatePHID() { return PhabricatorPHID::generateNewPHID( - PhabricatorPackagesPackagePHIDType::TYPECONST); + PhabricatorPackagesVersionPHIDType::TYPECONST); } public function getURI() { - $full_key = $this->getFullKey(); - return "/package/{$full_key}/"; - } + $package = $this->getPackage(); + $full_key = $package->getFullKey(); + $name = $this->getName(); - public function getFullKey() { - $publisher = $this->getPublisher(); - $publisher_key = $publisher->getPublisherKey(); - $package_key = $this->getPackageKey(); - return "{$publisher_key}/{$package_key}"; + return "/package/{$full_key}/{$name}/"; } - public function attachPublisher(PhabricatorPackagesPublisher $publisher) { - $this->publisher = $publisher; + public function attachPackage(PhabricatorPackagesPackage $package) { + $this->package = $package; return $this; } - public function getPublisher() { - return $this->assertAttached($this->publisher); + public function getPackage() { + return $this->assertAttached($this->package); } - public static function assertValidPackageName($value) { + public static function assertValidVersionName($value) { $length = phutil_utf8_strlen($value); if (!$length) { throw new Exception( pht( - 'Package name "%s" is not valid: package names are required.', + 'Version name "%s" is not valid: version names are required.', $value)); } @@ -77,37 +70,25 @@ if ($length > $max_length) { throw new Exception( pht( - 'Package name "%s" is not valid: package names must not be '. + 'Version name "%s" is not valid: version names must not be '. 'more than %s characters long.', $value, new PhutilNumber($max_length))); } - } - public static function assertValidPackageKey($value) { - $length = phutil_utf8_strlen($value); - if (!$length) { + if (!preg_match('/^[A-Za-z0-9.-]+\z/', $value)) { throw new Exception( pht( - 'Package key "%s" is not valid: package keys are required.', + 'Version name "%s" is not valid: version names may only contain '. + 'latin letters, digits, periods, and hyphens.', $value)); } - $max_length = 64; - if ($length > $max_length) { - throw new Exception( - pht( - 'Package key "%s" is not valid: package keys must not be '. - 'more than %s characters long.', - $value, - new PhutilNumber($max_length))); - } - - if (!preg_match('/^[a-z]+\z/', $value)) { + if (preg_match('/^[.-]|[.-]$/', $value)) { throw new Exception( pht( - 'Package key "%s" is not valid: package keys may only contain '. - 'lowercase latin letters.', + 'Version name "%s" is not valid: version names may not start or '. + 'end with a period or hyphen.', $value)); } } @@ -134,9 +115,9 @@ public function getPolicy($capability) { switch ($capability) { case PhabricatorPolicyCapability::CAN_VIEW: - return $this->getViewPolicy(); + return PhabricatorPolicies::getMostOpenPolicy(); case PhabricatorPolicyCapability::CAN_EDIT: - return $this->getEditPolicy(); + return PhabricatorPolicies::POLICY_USER; } } @@ -149,6 +130,19 @@ } +/* -( PhabricatorExtendedPolicyInterface )--------------------------------- */ + + + public function getExtendedPolicy($capability, PhabricatorUser $viewer) { + return array( + array( + $this->getPackage(), + $capability, + ), + ); + } + + /* -( PhabricatorDestructibleInterface )----------------------------------- */ @@ -162,7 +156,7 @@ public function getApplicationTransactionEditor() { - return new PhabricatorPackagesPackageEditor(); + return new PhabricatorPackagesVersionEditor(); } public function getApplicationTransactionObject() { @@ -170,7 +164,7 @@ } public function getApplicationTransactionTemplate() { - return new PhabricatorPackagesPackageTransaction(); + return new PhabricatorPackagesVersionTransaction(); } public function willRenderTimeline( @@ -188,29 +182,13 @@ id(new PhabricatorConduitSearchFieldSpecification()) ->setKey('name') ->setType('string') - ->setDescription(pht('The name of the package.')), - id(new PhabricatorConduitSearchFieldSpecification()) - ->setKey('packageKey') - ->setType('string') - ->setDescription(pht('The unique key of the package.')), + ->setDescription(pht('The name of the version.')), ); } public function getFieldValuesForConduit() { - $publisher = $this->getPublisher(); - - $publisher_map = array( - 'id' => (int)$publisher->getID(), - 'phid' => $publisher->getPHID(), - 'name' => $publisher->getName(), - 'publisherKey' => $publisher->getPublisherKey(), - ); - return array( 'name' => $this->getName(), - 'packageKey' => $this->getPackageKey(), - 'fullKey' => $this->getFullKey(), - 'publisher' => $publisher_map, ); } diff --git a/src/applications/packages/storage/PhabricatorPackagesVersionTransaction.php b/src/applications/packages/storage/PhabricatorPackagesVersionTransaction.php new file mode 100644 --- /dev/null +++ b/src/applications/packages/storage/PhabricatorPackagesVersionTransaction.php @@ -0,0 +1,18 @@ +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); + } + +} diff --git a/src/applications/packages/xaction/package/PhabricatorPackagesPackagePublisherTransaction.php b/src/applications/packages/xaction/package/PhabricatorPackagesPackagePublisherTransaction.php --- a/src/applications/packages/xaction/package/PhabricatorPackagesPackagePublisherTransaction.php +++ b/src/applications/packages/xaction/package/PhabricatorPackagesPackagePublisherTransaction.php @@ -16,7 +16,8 @@ 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.')); diff --git a/src/applications/packages/xaction/version/PhabricatorPackagesVersionNameTransaction.php b/src/applications/packages/xaction/version/PhabricatorPackagesVersionNameTransaction.php new file mode 100644 --- /dev/null +++ b/src/applications/packages/xaction/version/PhabricatorPackagesVersionNameTransaction.php @@ -0,0 +1,62 @@ +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; + } + +} diff --git a/src/applications/packages/xaction/package/PhabricatorPackagesPackagePublisherTransaction.php b/src/applications/packages/xaction/version/PhabricatorPackagesVersionPackageTransaction.php copy from src/applications/packages/xaction/package/PhabricatorPackagesPackagePublisherTransaction.php copy to src/applications/packages/xaction/version/PhabricatorPackagesVersionPackageTransaction.php --- a/src/applications/packages/xaction/package/PhabricatorPackagesPackagePublisherTransaction.php +++ b/src/applications/packages/xaction/version/PhabricatorPackagesVersionPackageTransaction.php @@ -1,43 +1,43 @@ getPublisherPHID(); + return $object->getPackagePHID(); } public function applyInternalEffects($object, $value) { - $object->setPublisherPHID($value); + $object->setPackagePHID($value); } public function validateTransactions($object, array $xactions) { $errors = array(); - if ($this->isEmptyTextTransaction($object->getName(), $xactions)) { + if ($this->isEmptyTextTransaction($object->getPackagePHID(), $xactions)) { $errors[] = $this->newRequiredError( pht( - 'You must select a publisher when creating a package.')); + 'You must select a package when creating a version')); return $errors; } if (!$this->isNewObject()) { foreach ($xactions as $xaction) { $errors[] = $this->newInvalidError( - pht('Once a package is created, its publisher can not be changed.'), + pht('Once a version is created, its package can not be changed.'), $xaction); } } $viewer = $this->getActor(); foreach ($xactions as $xaction) { - $publisher_phid = $xaction->getNewValue(); + $package_phid = $xaction->getNewValue(); - $publisher = id(new PhabricatorPackagesPublisherQuery()) + $package = id(new PhabricatorPackagesPackageQuery()) ->setViewer($viewer) - ->withPHIDs(array($publisher_phid)) + ->withPHIDs(array($package_phid)) ->setRaisePolicyExceptions(false) ->requireCapabilities( array( @@ -46,18 +46,18 @@ )) ->executeOne(); - if (!$publisher) { + if (!$package) { $errors[] = $this->newInvalidError( pht( - 'Publisher "%s" is invalid: the publisher must exist and you '. + 'Package "%s" is invalid: the package must exist and you '. 'must have permission to edit it in order to create a new '. 'package.', - $publisher_phid), + $package_phid), $xaction); continue; } - $object->attachPublisher($publisher); + $object->attachPackage($package); } return $errors; diff --git a/src/applications/packages/xaction/version/PhabricatorPackagesVersionTransactionType.php b/src/applications/packages/xaction/version/PhabricatorPackagesVersionTransactionType.php new file mode 100644 --- /dev/null +++ b/src/applications/packages/xaction/version/PhabricatorPackagesVersionTransactionType.php @@ -0,0 +1,4 @@ +