2011-04-03 23:48:36 +02:00
|
|
|
<?php
|
|
|
|
|
2015-05-27 19:30:08 +02:00
|
|
|
final class PhabricatorOwnersPackage
|
|
|
|
extends PhabricatorOwnersDAO
|
|
|
|
implements
|
|
|
|
PhabricatorPolicyInterface,
|
2015-09-10 22:32:31 +02:00
|
|
|
PhabricatorApplicationTransactionInterface,
|
2015-12-10 14:14:54 +01:00
|
|
|
PhabricatorCustomFieldInterface,
|
2015-12-13 01:25:51 +01:00
|
|
|
PhabricatorDestructibleInterface,
|
Implement basic ngram search for Owners Package names
Summary:
Ref T9979. This uses ngrams (specifically, trigrams) to build a reasonably efficient index for substring matching. Specifically, for a package like "Example", with ID 123, we store rows like this:
```
< ex, 123>
<exa, 123>
<xam, 123>
<amp, 123>
<mpl, 123>
<ple, 123>
<le , 123>
```
When the user searches for `exam`, we join this table for packages with tokens `exa` and `xam`. MySQL can do this a lot more efficiently than it can process a `LIKE "%exam%"` query against a huge table.
When the user searches for a one-letter or two-letter string, we only search the beginnings of words. This is probably what they want, the only thing we can do quickly, and a reasonable/expected behavior for typeaheads.
Test Plan:
- Ran storage upgrades and search indexer.
- Searched for stuff with "name contains".
- Used typehaead and got sensible results.
- Searched for `aabbccddeeffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz` and saw only 16 joins.
Reviewers: chad
Reviewed By: chad
Maniphest Tasks: T9979
Differential Revision: https://secure.phabricator.com/D14846
2015-12-21 21:22:07 +01:00
|
|
|
PhabricatorConduitResultInterface,
|
|
|
|
PhabricatorFulltextInterface,
|
|
|
|
PhabricatorNgramsInterface {
|
2011-04-03 23:48:36 +02:00
|
|
|
|
|
|
|
protected $name;
|
2012-06-14 05:52:10 +02:00
|
|
|
protected $originalName;
|
Add Basic Auditing Functionalities
Summary:
add basic auditing functionalities. For the related commits for a
package, we detect the following conditions which might be suspicious to the
owners of the package:
* no revision specified
* revision not found
* author not match
* reviewedby not match
* owners not involved
* commit author not recognized
The owners of the package can change the status of the audit entries by
accepting it or specify concern.
The owner can turn on/off the auditing for a package.
Test Plan:
* verified that non-owner cannot see the details of the audit and cannot modify
it
* verified that all the audit reasons can be detected
* tested dropdown filtering and package search
* verified really normal change not detected
* verified accept/concern a commit
* tested enable/disable a package for auditing
* verified one audit applies to all <commit, packages> to the packages the
auditor owns
* verified that re-parsing a commit won't have effect if there exists a
relationship for <commit, package> already
Reviewers: epriestley, nh
Reviewed By: epriestley
CC: aran, benmathews, btrahan, mpodobnik, prithvi, TomL, epriestley
Differential Revision: 1242
2011-12-18 00:52:54 +01:00
|
|
|
protected $auditingEnabled;
|
2011-04-03 23:48:36 +02:00
|
|
|
protected $description;
|
|
|
|
protected $primaryOwnerPHID;
|
2015-05-27 19:30:08 +02:00
|
|
|
protected $mailKey;
|
2015-08-18 22:36:05 +02:00
|
|
|
protected $status;
|
2011-04-03 23:48:36 +02:00
|
|
|
|
2015-08-15 22:06:10 +02:00
|
|
|
private $paths = self::ATTACHABLE;
|
2015-08-17 19:09:17 +02:00
|
|
|
private $owners = self::ATTACHABLE;
|
2015-09-10 22:32:31 +02:00
|
|
|
private $customFields = self::ATTACHABLE;
|
2015-08-15 22:06:10 +02:00
|
|
|
|
2015-08-18 22:36:05 +02:00
|
|
|
const STATUS_ACTIVE = 'active';
|
|
|
|
const STATUS_ARCHIVED = 'archived';
|
|
|
|
|
2015-05-27 19:30:08 +02:00
|
|
|
public static function initializeNewPackage(PhabricatorUser $actor) {
|
|
|
|
return id(new PhabricatorOwnersPackage())
|
2015-08-17 19:09:17 +02:00
|
|
|
->setAuditingEnabled(0)
|
|
|
|
->attachPaths(array())
|
2015-08-18 22:36:05 +02:00
|
|
|
->setStatus(self::STATUS_ACTIVE)
|
2015-11-29 18:33:36 +01:00
|
|
|
->attachOwners(array())
|
|
|
|
->setDescription('');
|
2013-09-27 17:43:41 +02:00
|
|
|
}
|
|
|
|
|
2015-08-18 22:36:05 +02:00
|
|
|
public static function getStatusNameMap() {
|
|
|
|
return array(
|
|
|
|
self::STATUS_ACTIVE => pht('Active'),
|
|
|
|
self::STATUS_ARCHIVED => pht('Archived'),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2015-01-13 20:47:05 +01:00
|
|
|
protected function getConfiguration() {
|
2011-04-03 23:48:36 +02:00
|
|
|
return array(
|
|
|
|
// This information is better available from the history table.
|
|
|
|
self::CONFIG_TIMESTAMPS => false,
|
2015-05-27 19:29:01 +02:00
|
|
|
self::CONFIG_AUX_PHID => true,
|
2014-10-01 16:53:12 +02:00
|
|
|
self::CONFIG_COLUMN_SCHEMA => array(
|
Implement basic ngram search for Owners Package names
Summary:
Ref T9979. This uses ngrams (specifically, trigrams) to build a reasonably efficient index for substring matching. Specifically, for a package like "Example", with ID 123, we store rows like this:
```
< ex, 123>
<exa, 123>
<xam, 123>
<amp, 123>
<mpl, 123>
<ple, 123>
<le , 123>
```
When the user searches for `exam`, we join this table for packages with tokens `exa` and `xam`. MySQL can do this a lot more efficiently than it can process a `LIKE "%exam%"` query against a huge table.
When the user searches for a one-letter or two-letter string, we only search the beginnings of words. This is probably what they want, the only thing we can do quickly, and a reasonable/expected behavior for typeaheads.
Test Plan:
- Ran storage upgrades and search indexer.
- Searched for stuff with "name contains".
- Used typehaead and got sensible results.
- Searched for `aabbccddeeffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz` and saw only 16 joins.
Reviewers: chad
Reviewed By: chad
Maniphest Tasks: T9979
Differential Revision: https://secure.phabricator.com/D14846
2015-12-21 21:22:07 +01:00
|
|
|
'name' => 'sort128',
|
2014-10-01 16:53:12 +02:00
|
|
|
'originalName' => 'text255',
|
|
|
|
'description' => 'text',
|
|
|
|
'primaryOwnerPHID' => 'phid?',
|
|
|
|
'auditingEnabled' => 'bool',
|
2015-05-27 19:30:08 +02:00
|
|
|
'mailKey' => 'bytes20',
|
2015-08-18 22:36:05 +02:00
|
|
|
'status' => 'text32',
|
2014-10-01 16:53:12 +02:00
|
|
|
),
|
2011-04-04 07:03:27 +02:00
|
|
|
) + parent::getConfiguration();
|
2011-04-03 23:48:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public function generatePHID() {
|
2015-05-27 19:29:01 +02:00
|
|
|
return PhabricatorPHID::generateNewPHID(
|
|
|
|
PhabricatorOwnersPackagePHIDType::TYPECONST);
|
2011-04-04 07:03:27 +02:00
|
|
|
}
|
|
|
|
|
2015-05-27 19:30:08 +02:00
|
|
|
public function save() {
|
|
|
|
if (!$this->getMailKey()) {
|
|
|
|
$this->setMailKey(Filesystem::readRandomCharacters(20));
|
|
|
|
}
|
|
|
|
|
|
|
|
return parent::save();
|
|
|
|
}
|
|
|
|
|
2015-08-18 22:36:05 +02:00
|
|
|
public function isArchived() {
|
|
|
|
return ($this->getStatus() == self::STATUS_ARCHIVED);
|
|
|
|
}
|
|
|
|
|
2012-06-14 05:52:10 +02:00
|
|
|
public function setName($name) {
|
|
|
|
$this->name = $name;
|
|
|
|
if (!$this->getID()) {
|
|
|
|
$this->originalName = $name;
|
|
|
|
}
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2011-04-04 07:03:27 +02:00
|
|
|
public function loadOwners() {
|
|
|
|
if (!$this->getID()) {
|
|
|
|
return array();
|
|
|
|
}
|
|
|
|
return id(new PhabricatorOwnersOwner())->loadAllWhere(
|
|
|
|
'packageID = %d',
|
|
|
|
$this->getID());
|
|
|
|
}
|
|
|
|
|
|
|
|
public function loadPaths() {
|
|
|
|
if (!$this->getID()) {
|
|
|
|
return array();
|
|
|
|
}
|
|
|
|
return id(new PhabricatorOwnersPath())->loadAllWhere(
|
|
|
|
'packageID = %d',
|
|
|
|
$this->getID());
|
|
|
|
}
|
|
|
|
|
2011-04-04 08:23:36 +02:00
|
|
|
public static function loadAffectedPackages(
|
|
|
|
PhabricatorRepository $repository,
|
|
|
|
array $paths) {
|
|
|
|
|
|
|
|
if (!$paths) {
|
|
|
|
return array();
|
|
|
|
}
|
|
|
|
|
2012-12-07 02:23:56 +01:00
|
|
|
return self::loadPackagesForPaths($repository, $paths);
|
Convert Owners paths to application transactions
Summary:
Ref T8320. Fixes T8317. Fixes T2831. Fixes T8073. Fixes T7127.
There was a bug with this line:
for ($ii = 0; $ii < count($paths); $ii++) {
...because the array may be sparse if there have been deletes, so `count($paths)` might be 3, but the real keys could be `1`, `5` and `6`. I think this was the primary issue behind T7127.
The old Editor did a lot of work to try to validate paths. When a path failed to validate, it silently discarded it. This was silly and pointless: it's incredibly bad UX; and it's totally fine if users saves "invalid" paths. This was likely the cause of T8317, and probably the cause of T8073.
T2831 I'm less sure about, but I can't reproduce it and I rewrote all the logic so I suspect it's gone.
This also records and shows edits, so if stuff does keep happening it should be more clear what's going on.
I removed some adjacent stuff:
- I removed the ability to delete packages. I'll add "disable" in a future diff, plus `bin/remove destroy`, like other objects. Getting rid of this now let me get rid of all the mail stuff.
- I removed "path validation" where packages would try to automatically update in response to commits. This doesn't necessarily make sense in Git/Mercurial, is sketchy, could easily have been the source of T2831, and seems generally complicated and not very valuable. We could maybe restore it some day, but I'd like to get Owners stable before trying to do crazy stuff like that.
Test Plan: {F437687}
Reviewers: chad, btrahan
Reviewed By: btrahan
Subscribers: epriestley
Maniphest Tasks: T8317, T8073, T7127, T2831, T8320
Differential Revision: https://secure.phabricator.com/D13032
2015-05-27 19:30:26 +02:00
|
|
|
}
|
2011-04-12 06:51:36 +02:00
|
|
|
|
Convert Owners paths to application transactions
Summary:
Ref T8320. Fixes T8317. Fixes T2831. Fixes T8073. Fixes T7127.
There was a bug with this line:
for ($ii = 0; $ii < count($paths); $ii++) {
...because the array may be sparse if there have been deletes, so `count($paths)` might be 3, but the real keys could be `1`, `5` and `6`. I think this was the primary issue behind T7127.
The old Editor did a lot of work to try to validate paths. When a path failed to validate, it silently discarded it. This was silly and pointless: it's incredibly bad UX; and it's totally fine if users saves "invalid" paths. This was likely the cause of T8317, and probably the cause of T8073.
T2831 I'm less sure about, but I can't reproduce it and I rewrote all the logic so I suspect it's gone.
This also records and shows edits, so if stuff does keep happening it should be more clear what's going on.
I removed some adjacent stuff:
- I removed the ability to delete packages. I'll add "disable" in a future diff, plus `bin/remove destroy`, like other objects. Getting rid of this now let me get rid of all the mail stuff.
- I removed "path validation" where packages would try to automatically update in response to commits. This doesn't necessarily make sense in Git/Mercurial, is sketchy, could easily have been the source of T2831, and seems generally complicated and not very valuable. We could maybe restore it some day, but I'd like to get Owners stable before trying to do crazy stuff like that.
Test Plan: {F437687}
Reviewers: chad, btrahan
Reviewed By: btrahan
Subscribers: epriestley
Maniphest Tasks: T8317, T8073, T7127, T2831, T8320
Differential Revision: https://secure.phabricator.com/D13032
2015-05-27 19:30:26 +02:00
|
|
|
public static function loadOwningPackages($repository, $path) {
|
2011-04-12 06:51:36 +02:00
|
|
|
if (empty($path)) {
|
|
|
|
return array();
|
2011-04-04 08:23:36 +02:00
|
|
|
}
|
|
|
|
|
2012-12-07 02:23:56 +01:00
|
|
|
return self::loadPackagesForPaths($repository, array($path), 1);
|
Convert Owners paths to application transactions
Summary:
Ref T8320. Fixes T8317. Fixes T2831. Fixes T8073. Fixes T7127.
There was a bug with this line:
for ($ii = 0; $ii < count($paths); $ii++) {
...because the array may be sparse if there have been deletes, so `count($paths)` might be 3, but the real keys could be `1`, `5` and `6`. I think this was the primary issue behind T7127.
The old Editor did a lot of work to try to validate paths. When a path failed to validate, it silently discarded it. This was silly and pointless: it's incredibly bad UX; and it's totally fine if users saves "invalid" paths. This was likely the cause of T8317, and probably the cause of T8073.
T2831 I'm less sure about, but I can't reproduce it and I rewrote all the logic so I suspect it's gone.
This also records and shows edits, so if stuff does keep happening it should be more clear what's going on.
I removed some adjacent stuff:
- I removed the ability to delete packages. I'll add "disable" in a future diff, plus `bin/remove destroy`, like other objects. Getting rid of this now let me get rid of all the mail stuff.
- I removed "path validation" where packages would try to automatically update in response to commits. This doesn't necessarily make sense in Git/Mercurial, is sketchy, could easily have been the source of T2831, and seems generally complicated and not very valuable. We could maybe restore it some day, but I'd like to get Owners stable before trying to do crazy stuff like that.
Test Plan: {F437687}
Reviewers: chad, btrahan
Reviewed By: btrahan
Subscribers: epriestley
Maniphest Tasks: T8317, T8073, T7127, T2831, T8320
Differential Revision: https://secure.phabricator.com/D13032
2015-05-27 19:30:26 +02:00
|
|
|
}
|
2011-04-12 06:51:36 +02:00
|
|
|
|
|
|
|
private static function loadPackagesForPaths(
|
|
|
|
PhabricatorRepository $repository,
|
|
|
|
array $paths,
|
|
|
|
$limit = 0) {
|
2012-12-07 02:23:56 +01:00
|
|
|
|
|
|
|
$fragments = array();
|
|
|
|
foreach ($paths as $path) {
|
|
|
|
foreach (self::splitPath($path) as $fragment) {
|
|
|
|
$fragments[$fragment][$path] = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-04-04 08:23:36 +02:00
|
|
|
$package = new PhabricatorOwnersPackage();
|
|
|
|
$path = new PhabricatorOwnersPath();
|
2011-04-12 06:51:36 +02:00
|
|
|
$conn = $package->establishConnection('r');
|
|
|
|
|
2012-07-09 19:51:46 +02:00
|
|
|
$repository_clause = qsprintf(
|
|
|
|
$conn,
|
|
|
|
'AND p.repositoryPHID = %s',
|
2011-04-12 06:51:36 +02:00
|
|
|
$repository->getPHID());
|
|
|
|
|
2012-07-09 19:51:46 +02:00
|
|
|
// NOTE: The list of $paths may be very large if we're coming from
|
|
|
|
// the OwnersWorker and processing, e.g., an SVN commit which created a new
|
|
|
|
// branch. Break it apart so that it will fit within 'max_allowed_packet',
|
|
|
|
// and then merge results in PHP.
|
|
|
|
|
2012-12-07 02:23:56 +01:00
|
|
|
$rows = array();
|
|
|
|
foreach (array_chunk(array_keys($fragments), 128) as $chunk) {
|
|
|
|
$rows[] = queryfx_all(
|
2012-07-09 19:51:46 +02:00
|
|
|
$conn,
|
2012-12-07 02:23:56 +01:00
|
|
|
'SELECT pkg.id, p.excluded, p.path
|
2012-07-09 19:51:46 +02:00
|
|
|
FROM %T pkg JOIN %T p ON p.packageID = pkg.id
|
|
|
|
WHERE p.path IN (%Ls) %Q',
|
|
|
|
$package->getTableName(),
|
|
|
|
$path->getTableName(),
|
|
|
|
$chunk,
|
|
|
|
$repository_clause);
|
2011-04-12 06:51:36 +02:00
|
|
|
}
|
2012-12-07 02:23:56 +01:00
|
|
|
$rows = array_mergev($rows);
|
|
|
|
|
|
|
|
$ids = self::findLongestPathsPerPackage($rows, $fragments);
|
2011-04-12 06:51:36 +02:00
|
|
|
|
2012-07-09 19:51:46 +02:00
|
|
|
if (!$ids) {
|
2011-04-12 06:51:36 +02:00
|
|
|
return array();
|
|
|
|
}
|
|
|
|
|
2012-07-09 19:51:46 +02:00
|
|
|
arsort($ids);
|
|
|
|
if ($limit) {
|
|
|
|
$ids = array_slice($ids, 0, $limit, $preserve_keys = true);
|
2011-04-12 06:51:36 +02:00
|
|
|
}
|
2012-07-09 19:51:46 +02:00
|
|
|
$ids = array_keys($ids);
|
2011-04-12 06:51:36 +02:00
|
|
|
|
2012-07-25 21:38:32 +02:00
|
|
|
$packages = $package->loadAllWhere('id in (%Ld)', $ids);
|
|
|
|
$packages = array_select_keys($packages, $ids);
|
2011-04-12 06:51:36 +02:00
|
|
|
|
2011-04-15 01:17:39 +02:00
|
|
|
return $packages;
|
2011-04-04 08:23:36 +02:00
|
|
|
}
|
|
|
|
|
2013-04-24 15:07:26 +02:00
|
|
|
public static function loadPackagesForRepository($repository) {
|
|
|
|
$package = new PhabricatorOwnersPackage();
|
|
|
|
$ids = ipull(
|
|
|
|
queryfx_all(
|
|
|
|
$package->establishConnection('r'),
|
|
|
|
'SELECT DISTINCT packageID FROM %T WHERE repositoryPHID = %s',
|
|
|
|
id(new PhabricatorOwnersPath())->getTableName(),
|
|
|
|
$repository->getPHID()),
|
|
|
|
'packageID');
|
|
|
|
|
|
|
|
return $package->loadAllWhere('id in (%Ld)', $ids);
|
|
|
|
}
|
|
|
|
|
2012-12-07 02:23:56 +01:00
|
|
|
public static function findLongestPathsPerPackage(array $rows, array $paths) {
|
|
|
|
$ids = array();
|
|
|
|
|
|
|
|
foreach (igroup($rows, 'id') as $id => $package_paths) {
|
|
|
|
$relevant_paths = array_select_keys(
|
|
|
|
$paths,
|
|
|
|
ipull($package_paths, 'path'));
|
|
|
|
|
|
|
|
// For every package, remove all excluded paths.
|
|
|
|
$remove = array();
|
|
|
|
foreach ($package_paths as $package_path) {
|
|
|
|
if ($package_path['excluded']) {
|
2014-04-15 20:12:42 +02:00
|
|
|
$remove += idx($relevant_paths, $package_path['path'], array());
|
2012-12-07 02:23:56 +01:00
|
|
|
unset($relevant_paths[$package_path['path']]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($remove) {
|
|
|
|
foreach ($relevant_paths as $fragment => $fragment_paths) {
|
|
|
|
$relevant_paths[$fragment] = array_diff_key($fragment_paths, $remove);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$relevant_paths = array_filter($relevant_paths);
|
|
|
|
if ($relevant_paths) {
|
|
|
|
$ids[$id] = max(array_map('strlen', array_keys($relevant_paths)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return $ids;
|
|
|
|
}
|
|
|
|
|
2015-08-15 22:06:10 +02:00
|
|
|
public static function splitPath($path) {
|
2011-04-12 06:51:36 +02:00
|
|
|
$trailing_slash = preg_match('@/$@', $path) ? '/' : '';
|
|
|
|
$path = trim($path, '/');
|
|
|
|
$parts = explode('/', $path);
|
2015-08-18 21:12:51 +02:00
|
|
|
|
|
|
|
$result = array();
|
2011-04-12 06:51:36 +02:00
|
|
|
while (count($parts)) {
|
2012-12-07 02:23:56 +01:00
|
|
|
$result[] = '/'.implode('/', $parts).$trailing_slash;
|
2011-04-12 06:51:36 +02:00
|
|
|
$trailing_slash = '/';
|
|
|
|
array_pop($parts);
|
|
|
|
}
|
2015-08-18 21:12:51 +02:00
|
|
|
$result[] = '/';
|
|
|
|
|
|
|
|
return array_reverse($result);
|
2011-04-12 06:51:36 +02:00
|
|
|
}
|
2015-05-27 19:30:08 +02:00
|
|
|
|
2015-08-15 22:06:10 +02:00
|
|
|
public function attachPaths(array $paths) {
|
|
|
|
assert_instances_of($paths, 'PhabricatorOwnersPath');
|
|
|
|
$this->paths = $paths;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getPaths() {
|
|
|
|
return $this->assertAttached($this->paths);
|
|
|
|
}
|
|
|
|
|
2015-08-17 19:09:17 +02:00
|
|
|
public function attachOwners(array $owners) {
|
|
|
|
assert_instances_of($owners, 'PhabricatorOwnersOwner');
|
|
|
|
$this->owners = $owners;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getOwners() {
|
|
|
|
return $this->assertAttached($this->owners);
|
|
|
|
}
|
|
|
|
|
2015-11-29 18:33:36 +01:00
|
|
|
public function getOwnerPHIDs() {
|
|
|
|
return mpull($this->getOwners(), 'getUserPHID');
|
|
|
|
}
|
|
|
|
|
2015-12-14 15:11:03 +01:00
|
|
|
public function isOwnerPHID($phid) {
|
|
|
|
if (!$phid) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
$owner_phids = $this->getOwnerPHIDs();
|
|
|
|
$owner_phids = array_fuse($owner_phids);
|
|
|
|
|
|
|
|
return isset($owner_phids[$phid]);
|
|
|
|
}
|
|
|
|
|
2015-11-29 18:33:36 +01:00
|
|
|
|
|
|
|
/* -( PhabricatorPolicyInterface )----------------------------------------- */
|
|
|
|
|
|
|
|
|
|
|
|
public function getCapabilities() {
|
|
|
|
return array(
|
|
|
|
PhabricatorPolicyCapability::CAN_VIEW,
|
|
|
|
PhabricatorPolicyCapability::CAN_EDIT,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getPolicy($capability) {
|
|
|
|
// TODO: Implement proper policies.
|
|
|
|
return PhabricatorPolicies::POLICY_USER;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
|
2015-12-14 15:11:03 +01:00
|
|
|
switch ($capability) {
|
|
|
|
case PhabricatorPolicyCapability::CAN_VIEW:
|
|
|
|
if ($this->isOwnerPHID($viewer->getPHID())) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2015-11-29 18:33:36 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function describeAutomaticCapability($capability) {
|
2015-12-14 15:11:03 +01:00
|
|
|
return pht('Owners of a package may always view it.');
|
2015-11-29 18:33:36 +01:00
|
|
|
}
|
|
|
|
|
2015-05-27 19:30:08 +02:00
|
|
|
|
|
|
|
/* -( PhabricatorApplicationTransactionInterface )------------------------- */
|
|
|
|
|
|
|
|
|
|
|
|
public function getApplicationTransactionEditor() {
|
|
|
|
return new PhabricatorOwnersPackageTransactionEditor();
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getApplicationTransactionObject() {
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getApplicationTransactionTemplate() {
|
|
|
|
return new PhabricatorOwnersPackageTransaction();
|
|
|
|
}
|
|
|
|
|
|
|
|
public function willRenderTimeline(
|
|
|
|
PhabricatorApplicationTransactionView $timeline,
|
|
|
|
AphrontRequest $request) {
|
|
|
|
return $timeline;
|
|
|
|
}
|
|
|
|
|
2015-09-10 22:32:31 +02:00
|
|
|
|
|
|
|
/* -( PhabricatorCustomFieldInterface )------------------------------------ */
|
|
|
|
|
|
|
|
|
|
|
|
public function getCustomFieldSpecificationForRole($role) {
|
|
|
|
return PhabricatorEnv::getEnvConfig('owners.fields');
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getCustomFieldBaseClass() {
|
|
|
|
return 'PhabricatorOwnersCustomField';
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getCustomFields() {
|
|
|
|
return $this->assertAttached($this->customFields);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function attachCustomFields(PhabricatorCustomFieldAttachment $fields) {
|
|
|
|
$this->customFields = $fields;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2015-12-10 14:14:54 +01:00
|
|
|
|
|
|
|
/* -( PhabricatorDestructibleInterface )----------------------------------- */
|
|
|
|
|
|
|
|
|
|
|
|
public function destroyObjectPermanently(
|
|
|
|
PhabricatorDestructionEngine $engine) {
|
|
|
|
|
|
|
|
$this->openTransaction();
|
|
|
|
$conn_w = $this->establishConnection('w');
|
|
|
|
|
|
|
|
queryfx(
|
|
|
|
$conn_w,
|
|
|
|
'DELETE FROM %T WHERE packageID = %d',
|
|
|
|
id(new PhabricatorOwnersPath())->getTableName(),
|
|
|
|
$this->getID());
|
|
|
|
|
|
|
|
queryfx(
|
|
|
|
$conn_w,
|
|
|
|
'DELETE FROM %T WHERE packageID = %d',
|
|
|
|
id(new PhabricatorOwnersOwner())->getTableName(),
|
|
|
|
$this->getID());
|
|
|
|
|
|
|
|
$this->delete();
|
|
|
|
$this->saveTransaction();
|
|
|
|
}
|
|
|
|
|
2015-12-13 01:25:51 +01:00
|
|
|
|
|
|
|
/* -( PhabricatorConduitResultInterface )---------------------------------- */
|
|
|
|
|
|
|
|
|
|
|
|
public function getFieldSpecificationsForConduit() {
|
|
|
|
return array(
|
2015-12-14 15:42:21 +01:00
|
|
|
id(new PhabricatorConduitSearchFieldSpecification())
|
|
|
|
->setKey('name')
|
|
|
|
->setType('string')
|
|
|
|
->setDescription(pht('The name of the package.')),
|
|
|
|
id(new PhabricatorConduitSearchFieldSpecification())
|
|
|
|
->setKey('description')
|
|
|
|
->setType('string')
|
|
|
|
->setDescription(pht('The package description.')),
|
|
|
|
id(new PhabricatorConduitSearchFieldSpecification())
|
|
|
|
->setKey('status')
|
|
|
|
->setType('string')
|
|
|
|
->setDescription(pht('Active or archived status of the package.')),
|
|
|
|
id(new PhabricatorConduitSearchFieldSpecification())
|
|
|
|
->setKey('owners')
|
|
|
|
->setType('list<map<string, wild>>')
|
|
|
|
->setDescription(pht('List of package owners.')),
|
2015-12-13 01:25:51 +01:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getFieldValuesForConduit() {
|
2015-12-14 15:11:03 +01:00
|
|
|
$owner_list = array();
|
|
|
|
foreach ($this->getOwners() as $owner) {
|
|
|
|
$owner_list[] = array(
|
|
|
|
'ownerPHID' => $owner->getUserPHID(),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2015-12-13 01:25:51 +01:00
|
|
|
return array(
|
|
|
|
'name' => $this->getName(),
|
|
|
|
'description' => $this->getDescription(),
|
|
|
|
'status' => $this->getStatus(),
|
2015-12-14 15:11:03 +01:00
|
|
|
'owners' => $owner_list,
|
2015-12-13 01:25:51 +01:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2015-12-14 15:01:04 +01:00
|
|
|
public function getConduitSearchAttachments() {
|
2015-12-14 15:11:03 +01:00
|
|
|
return array(
|
|
|
|
id(new PhabricatorOwnersPathsSearchEngineAttachment())
|
|
|
|
->setAttachmentKey('paths'),
|
|
|
|
);
|
2015-12-14 15:01:04 +01:00
|
|
|
}
|
|
|
|
|
Implement basic ngram search for Owners Package names
Summary:
Ref T9979. This uses ngrams (specifically, trigrams) to build a reasonably efficient index for substring matching. Specifically, for a package like "Example", with ID 123, we store rows like this:
```
< ex, 123>
<exa, 123>
<xam, 123>
<amp, 123>
<mpl, 123>
<ple, 123>
<le , 123>
```
When the user searches for `exam`, we join this table for packages with tokens `exa` and `xam`. MySQL can do this a lot more efficiently than it can process a `LIKE "%exam%"` query against a huge table.
When the user searches for a one-letter or two-letter string, we only search the beginnings of words. This is probably what they want, the only thing we can do quickly, and a reasonable/expected behavior for typeaheads.
Test Plan:
- Ran storage upgrades and search indexer.
- Searched for stuff with "name contains".
- Used typehaead and got sensible results.
- Searched for `aabbccddeeffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz` and saw only 16 joins.
Reviewers: chad
Reviewed By: chad
Maniphest Tasks: T9979
Differential Revision: https://secure.phabricator.com/D14846
2015-12-21 21:22:07 +01:00
|
|
|
|
|
|
|
/* -( PhabricatorFulltextInterface )--------------------------------------- */
|
|
|
|
|
|
|
|
|
|
|
|
public function newFulltextEngine() {
|
|
|
|
return new PhabricatorOwnersPackageFulltextEngine();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* -( PhabricatorNgramInterface )------------------------------------------ */
|
|
|
|
|
|
|
|
|
|
|
|
public function newNgrams() {
|
|
|
|
return array(
|
|
|
|
id(new PhabricatorOwnersPackageNameNgrams())
|
|
|
|
->setValue($this->getName()),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2011-04-03 23:48:36 +02:00
|
|
|
}
|