Page MenuHomestyx hydra

No OneTemporary

diff --git a/resources/sql/autopatches/20191113.identity.03.unassigned.sql b/resources/sql/autopatches/20191113.identity.03.unassigned.sql
new file mode 100644
index 0000000000..768ca1d909
--- /dev/null
+++ b/resources/sql/autopatches/20191113.identity.03.unassigned.sql
@@ -0,0 +1,3 @@
+UPDATE {$NAMESPACE}_repository.repository_identity
+ SET currentEffectiveUserPHID = NULL
+ WHERE currentEffectiveUserPHID = 'unassigned()';
diff --git a/src/applications/diffusion/controller/DiffusionIdentityViewController.php b/src/applications/diffusion/controller/DiffusionIdentityViewController.php
index 0ac131daf1..1c78ec5992 100644
--- a/src/applications/diffusion/controller/DiffusionIdentityViewController.php
+++ b/src/applications/diffusion/controller/DiffusionIdentityViewController.php
@@ -1,138 +1,141 @@
<?php
final class DiffusionIdentityViewController
extends DiffusionController {
public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer();
$id = $request->getURIData('id');
$identity = id(new PhabricatorRepositoryIdentityQuery())
->setViewer($viewer)
->withIDs(array($id))
->executeOne();
if (!$identity) {
return new Aphront404Response();
}
$title = pht('Identity %d', $identity->getID());
$curtain = $this->buildCurtain($identity);
$header = id(new PHUIHeaderView())
->setUser($viewer)
->setHeader($identity->getIdentityShortName())
->setHeaderIcon('fa-globe');
$crumbs = $this->buildApplicationCrumbs();
+ $crumbs->addTextCrumb(
+ pht('Identities'),
+ $this->getApplicationURI('identity/'));
$crumbs->addTextCrumb($identity->getObjectName());
$crumbs->setBorder(true);
$timeline = $this->buildTransactionTimeline(
$identity,
new PhabricatorRepositoryIdentityTransactionQuery());
$timeline->setShouldTerminate(true);
$properties = $this->buildPropertyList($identity);
$view = id(new PHUITwoColumnView())
->setHeader($header)
->setCurtain($curtain)
->setMainColumn(array(
$properties,
$timeline,
));
return $this->newPage()
->setTitle($title)
->setCrumbs($crumbs)
->appendChild(
array(
$view,
));
}
private function buildCurtain(PhabricatorRepositoryIdentity $identity) {
$viewer = $this->getViewer();
$can_edit = PhabricatorPolicyFilter::hasCapability(
$viewer,
$identity,
PhabricatorPolicyCapability::CAN_EDIT);
$id = $identity->getID();
$edit_uri = $this->getApplicationURI("identity/edit/{$id}/");
$curtain = $this->newCurtainView($identity);
$curtain->addAction(
id(new PhabricatorActionView())
->setIcon('fa-pencil')
->setName(pht('Edit Identity'))
->setHref($edit_uri)
->setWorkflow(!$can_edit)
->setDisabled(!$can_edit));
return $curtain;
}
private function buildPropertyList(
PhabricatorRepositoryIdentity $identity) {
$viewer = $this->getViewer();
$properties = id(new PHUIPropertyListView())
->setViewer($viewer);
$properties->addProperty(
pht('Email Address'),
$identity->getEmailAddress());
$effective_phid = $identity->getCurrentEffectiveUserPHID();
$automatic_phid = $identity->getAutomaticGuessedUserPHID();
$manual_phid = $identity->getManuallySetUserPHID();
if ($effective_phid) {
$tag = id(new PHUITagView())
->setType(PHUITagView::TYPE_SHADE)
->setColor('green')
->setIcon('fa-check')
->setName('Assigned');
} else {
$tag = id(new PHUITagView())
->setType(PHUITagView::TYPE_SHADE)
->setColor('indigo')
->setIcon('fa-bomb')
->setName('Unassigned');
}
$properties->addProperty(
pht('Effective User'),
$this->buildPropertyValue($effective_phid));
$properties->addProperty(
pht('Automatically Detected User'),
$this->buildPropertyValue($automatic_phid));
$properties->addProperty(
pht('Assigned To'),
$this->buildPropertyValue($manual_phid));
$header = id(new PHUIHeaderView())
->setHeader(array(pht('Identity Assignments'), $tag));
return id(new PHUIObjectBoxView())
->setHeader($header)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->addPropertyList($properties);
}
private function buildPropertyValue($value) {
$viewer = $this->getViewer();
if ($value == DiffusionIdentityUnassignedDatasource::FUNCTION_TOKEN) {
return phutil_tag('em', array(), pht('Explicitly Unassigned'));
} else if (!$value) {
return phutil_tag('em', array(), pht('None'));
} else {
return $viewer->renderHandle($value);
}
}
}
diff --git a/src/applications/diffusion/query/DiffusionRepositoryIdentitySearchEngine.php b/src/applications/diffusion/query/DiffusionRepositoryIdentitySearchEngine.php
index 4d10ee44e0..f41b6b89a4 100644
--- a/src/applications/diffusion/query/DiffusionRepositoryIdentitySearchEngine.php
+++ b/src/applications/diffusion/query/DiffusionRepositoryIdentitySearchEngine.php
@@ -1,108 +1,165 @@
<?php
final class DiffusionRepositoryIdentitySearchEngine
extends PhabricatorApplicationSearchEngine {
public function getResultTypeDescription() {
return pht('Repository Identities');
}
public function getApplicationClassName() {
return 'PhabricatorDiffusionApplication';
}
public function newQuery() {
return new PhabricatorRepositoryIdentityQuery();
}
protected function buildCustomSearchFields() {
return array(
+ id(new PhabricatorUsersSearchField())
+ ->setLabel(pht('Matching Users'))
+ ->setKey('effectivePHIDs')
+ ->setAliases(
+ array(
+ 'effective',
+ 'effectivePHID',
+ ))
+ ->setDescription(pht('Search for identities by effective user.')),
id(new DiffusionIdentityAssigneeSearchField())
->setLabel(pht('Assigned To'))
- ->setKey('assignee')
- ->setDescription(pht('Search for identities by assignee.')),
+ ->setKey('assignedPHIDs')
+ ->setAliases(
+ array(
+ 'assigned',
+ 'assignedPHID',
+ ))
+ ->setDescription(pht('Search for identities by explicit assignee.')),
id(new PhabricatorSearchTextField())
->setLabel(pht('Identity Contains'))
->setKey('match')
->setDescription(pht('Search for identities by substring.')),
id(new PhabricatorSearchThreeStateField())
- ->setLabel(pht('Is Assigned'))
+ ->setLabel(pht('Has Matching User'))
->setKey('hasEffectivePHID')
->setOptions(
pht('(Show All)'),
- pht('Show Only Assigned Identities'),
- pht('Show Only Unassigned Identities')),
+ pht('Show Identities With Matching Users'),
+ pht('Show Identities Without Matching Users')),
);
}
protected function buildQueryFromParameters(array $map) {
$query = $this->newQuery();
if ($map['hasEffectivePHID'] !== null) {
$query->withHasEffectivePHID($map['hasEffectivePHID']);
}
if ($map['match'] !== null) {
$query->withIdentityNameLike($map['match']);
}
- if ($map['assignee']) {
- $query->withAssigneePHIDs($map['assignee']);
+ if ($map['assignedPHIDs']) {
+ $query->withAssignedPHIDs($map['assignedPHIDs']);
+ }
+
+ if ($map['effectivePHIDs']) {
+ $query->withEffectivePHIDs($map['effectivePHIDs']);
}
return $query;
}
protected function getURI($path) {
return '/diffusion/identity/'.$path;
}
protected function getBuiltinQueryNames() {
$names = array(
'all' => pht('All Identities'),
);
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 $identities,
PhabricatorSavedQuery $query,
array $handles) {
assert_instances_of($identities, 'PhabricatorRepositoryIdentity');
$viewer = $this->requireViewer();
- $list = new PHUIObjectItemListView();
- $list->setUser($viewer);
+ $list = id(new PHUIObjectItemListView())
+ ->setViewer($viewer);
+
+ $phids = array();
+ foreach ($identities as $identity) {
+ $phids[] = $identity->getCurrentEffectiveUserPHID();
+ $phids[] = $identity->getManuallySetUserPHID();
+ }
+
+ $handles = $viewer->loadHandles($phids);
+
+ $unassigned = DiffusionIdentityUnassignedDatasource::FUNCTION_TOKEN;
+
foreach ($identities as $identity) {
$item = id(new PHUIObjectItemView())
- ->setObjectName(pht('Identity %d', $identity->getID()))
+ ->setObjectName($identity->getObjectName())
->setHeader($identity->getIdentityShortName())
->setHref($identity->getURI())
->setObject($identity);
+ $status_icon = 'fa-circle-o grey';
+
+ $effective_phid = $identity->getCurrentEffectiveUserPHID();
+ if ($effective_phid) {
+ $item->addIcon(
+ 'fa-id-badge',
+ pht('Matches User: %s', $handles[$effective_phid]->getName()));
+
+ $status_icon = 'fa-id-badge';
+ }
+
+ $assigned_phid = $identity->getManuallySetUserPHID();
+ if ($assigned_phid) {
+ if ($assigned_phid === $unassigned) {
+ $item->addIcon(
+ 'fa-ban',
+ pht('Explicitly Unassigned'));
+ $status_icon = 'fa-ban';
+ } else {
+ $item->addIcon(
+ 'fa-user',
+ pht('Assigned To: %s', $handles[$assigned_phid]->getName()));
+ $status_icon = 'fa-user';
+ }
+ }
+
+ $item->setStatusIcon($status_icon);
+
$list->addItem($item);
}
$result = new PhabricatorApplicationSearchResultView();
$result->setObjectList($list);
$result->setNoDataString(pht('No Identities found.'));
return $result;
}
}
diff --git a/src/applications/repository/query/PhabricatorRepositoryIdentityQuery.php b/src/applications/repository/query/PhabricatorRepositoryIdentityQuery.php
index 6ddf8d57c1..14c2a75f80 100644
--- a/src/applications/repository/query/PhabricatorRepositoryIdentityQuery.php
+++ b/src/applications/repository/query/PhabricatorRepositoryIdentityQuery.php
@@ -1,130 +1,143 @@
<?php
final class PhabricatorRepositoryIdentityQuery
extends PhabricatorCursorPagedPolicyAwareQuery {
private $ids;
private $phids;
private $identityNames;
private $emailAddresses;
- private $assigneePHIDs;
+ private $assignedPHIDs;
+ private $effectivePHIDs;
private $identityNameLike;
private $hasEffectivePHID;
public function withIDs(array $ids) {
$this->ids = $ids;
return $this;
}
public function withPHIDs(array $phids) {
$this->phids = $phids;
return $this;
}
public function withIdentityNames(array $names) {
$this->identityNames = $names;
return $this;
}
public function withIdentityNameLike($name_like) {
$this->identityNameLike = $name_like;
return $this;
}
public function withEmailAddresses(array $addresses) {
$this->emailAddresses = $addresses;
return $this;
}
- public function withAssigneePHIDs(array $assignees) {
- $this->assigneePHIDs = $assignees;
+ public function withAssignedPHIDs(array $assigned) {
+ $this->assignedPHIDs = $assigned;
+ return $this;
+ }
+
+ public function withEffectivePHIDs(array $effective) {
+ $this->effectivePHIDs = $effective;
return $this;
}
public function withHasEffectivePHID($has_effective_phid) {
$this->hasEffectivePHID = $has_effective_phid;
return $this;
}
public function newResultObject() {
return new PhabricatorRepositoryIdentity();
}
protected function getPrimaryTableAlias() {
return 'repository_identity';
}
protected function loadPage() {
return $this->loadStandardPage($this->newResultObject());
}
protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {
$where = parent::buildWhereClauseParts($conn);
if ($this->ids !== null) {
$where[] = qsprintf(
$conn,
'repository_identity.id IN (%Ld)',
$this->ids);
}
if ($this->phids !== null) {
$where[] = qsprintf(
$conn,
'repository_identity.phid IN (%Ls)',
$this->phids);
}
- if ($this->assigneePHIDs !== null) {
+ if ($this->assignedPHIDs !== null) {
+ $where[] = qsprintf(
+ $conn,
+ 'repository_identity.manuallySetUserPHID IN (%Ls)',
+ $this->assignedPHIDs);
+ }
+
+ if ($this->effectivePHIDs !== null) {
$where[] = qsprintf(
$conn,
'repository_identity.currentEffectiveUserPHID IN (%Ls)',
- $this->assigneePHIDs);
+ $this->effectivePHIDs);
}
if ($this->hasEffectivePHID !== null) {
if ($this->hasEffectivePHID) {
$where[] = qsprintf(
$conn,
'repository_identity.currentEffectiveUserPHID IS NOT NULL');
} else {
$where[] = qsprintf(
$conn,
'repository_identity.currentEffectiveUserPHID IS NULL');
}
}
if ($this->identityNames !== null) {
$name_hashes = array();
foreach ($this->identityNames as $name) {
$name_hashes[] = PhabricatorHash::digestForIndex($name);
}
$where[] = qsprintf(
$conn,
'repository_identity.identityNameHash IN (%Ls)',
$name_hashes);
}
if ($this->emailAddresses !== null) {
$where[] = qsprintf(
$conn,
'repository_identity.emailAddress IN (%Ls)',
$this->emailAddresses);
}
if ($this->identityNameLike != null) {
$where[] = qsprintf(
$conn,
'repository_identity.identityNameRaw LIKE %~',
$this->identityNameLike);
}
return $where;
}
public function getQueryApplicationClass() {
return 'PhabricatorDiffusionApplication';
}
}
diff --git a/src/applications/repository/storage/PhabricatorRepositoryIdentity.php b/src/applications/repository/storage/PhabricatorRepositoryIdentity.php
index c33b296fdc..74fbd06544 100644
--- a/src/applications/repository/storage/PhabricatorRepositoryIdentity.php
+++ b/src/applications/repository/storage/PhabricatorRepositoryIdentity.php
@@ -1,159 +1,166 @@
<?php
final class PhabricatorRepositoryIdentity
extends PhabricatorRepositoryDAO
implements
PhabricatorPolicyInterface,
PhabricatorApplicationTransactionInterface {
protected $authorPHID;
protected $identityNameHash;
protected $identityNameRaw;
protected $identityNameEncoding;
protected $automaticGuessedUserPHID;
protected $manuallySetUserPHID;
protected $currentEffectiveUserPHID;
protected $emailAddress;
protected function getConfiguration() {
return array(
self::CONFIG_AUX_PHID => true,
self::CONFIG_BINARY => array(
'identityNameRaw' => true,
),
self::CONFIG_COLUMN_SCHEMA => array(
'identityNameHash' => 'bytes12',
'identityNameEncoding' => 'text16?',
'automaticGuessedUserPHID' => 'phid?',
'manuallySetUserPHID' => 'phid?',
'currentEffectiveUserPHID' => 'phid?',
'emailAddress' => 'sort255?',
),
self::CONFIG_KEY_SCHEMA => array(
'key_identity' => array(
'columns' => array('identityNameHash'),
'unique' => true,
),
'key_email' => array(
'columns' => array('emailAddress(64)'),
),
),
) + parent::getConfiguration();
}
public function getPHIDType() {
return PhabricatorRepositoryIdentityPHIDType::TYPECONST;
}
public function setIdentityName($name_raw) {
$this->setIdentityNameRaw($name_raw);
$this->setIdentityNameHash(PhabricatorHash::digestForIndex($name_raw));
$this->setIdentityNameEncoding($this->detectEncodingForStorage($name_raw));
return $this;
}
public function getIdentityName() {
return $this->getUTF8StringFromStorage(
$this->getIdentityNameRaw(),
$this->getIdentityNameEncoding());
}
public function getIdentityEmailAddress() {
$address = new PhutilEmailAddress($this->getIdentityName());
return $address->getAddress();
}
public function getIdentityDisplayName() {
$address = new PhutilEmailAddress($this->getIdentityName());
return $address->getDisplayName();
}
public function getIdentityShortName() {
// TODO
return $this->getIdentityName();
}
public function getObjectName() {
return pht('Identity %d', $this->getID());
}
public function getURI() {
return '/diffusion/identity/view/'.$this->getID().'/';
}
public function hasEffectiveUser() {
return ($this->currentEffectiveUserPHID != null);
}
public function getIdentityDisplayPHID() {
if ($this->hasEffectiveUser()) {
return $this->getCurrentEffectiveUserPHID();
} else {
return $this->getPHID();
}
}
public function save() {
if ($this->manuallySetUserPHID) {
- $this->currentEffectiveUserPHID = $this->manuallySetUserPHID;
+ $unassigned = DiffusionIdentityUnassignedDatasource::FUNCTION_TOKEN;
+ if ($this->manuallySetUserPHID === $unassigned) {
+ $effective_phid = null;
+ } else {
+ $effective_phid = $this->manuallySetUserPHID;
+ }
} else {
- $this->currentEffectiveUserPHID = $this->automaticGuessedUserPHID;
+ $effective_phid = $this->automaticGuessedUserPHID;
}
+ $this->setCurrentEffectiveUserPHID($effective_phid);
+
$email_address = $this->getIdentityEmailAddress();
// Raw identities are unrestricted binary data, and may consequently
// have arbitrarily long, binary email address information. We can't
// store this kind of information in the "emailAddress" column, which
// has column type "sort255".
// This kind of address almost certainly not legitimate and users can
// manually set the target of the identity, so just discard it rather
// than trying especially hard to make it work.
$byte_limit = $this->getColumnMaximumByteLength('emailAddress');
$email_address = phutil_utf8ize($email_address);
if (strlen($email_address) > $byte_limit) {
$email_address = null;
}
$this->setEmailAddress($email_address);
return parent::save();
}
/* -( PhabricatorPolicyInterface )----------------------------------------- */
public function getCapabilities() {
return array(
PhabricatorPolicyCapability::CAN_VIEW,
PhabricatorPolicyCapability::CAN_EDIT,
);
}
public function getPolicy($capability) {
return PhabricatorPolicies::getMostOpenPolicy();
}
public function hasAutomaticCapability(
$capability,
PhabricatorUser $viewer) {
return false;
}
/* -( PhabricatorApplicationTransactionInterface )------------------------- */
public function getApplicationTransactionEditor() {
return new DiffusionRepositoryIdentityEditor();
}
public function getApplicationTransactionTemplate() {
return new PhabricatorRepositoryIdentityTransaction();
}
}

File Metadata

Mime Type
text/x-diff
Expires
Tue, Jun 10, 5:28 PM (1 d, 15 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
140615
Default Alt Text
(19 KB)

Event Timeline