Page MenuHomePhorge

No OneTemporary

diff --git a/resources/sql/autopatches/20191113.identity.01.email.sql b/resources/sql/autopatches/20191113.identity.01.email.sql
new file mode 100644
index 0000000000..938e6c0767
--- /dev/null
+++ b/resources/sql/autopatches/20191113.identity.01.email.sql
@@ -0,0 +1,2 @@
+ALTER TABLE {$NAMESPACE}_repository.repository_identity
+ ADD emailAddress VARCHAR(255) COLLATE {$COLLATE_SORT};
diff --git a/resources/sql/autopatches/20191113.identity.02.populate.php b/resources/sql/autopatches/20191113.identity.02.populate.php
new file mode 100644
index 0000000000..ca86be0733
--- /dev/null
+++ b/resources/sql/autopatches/20191113.identity.02.populate.php
@@ -0,0 +1,26 @@
+<?php
+
+$table = new PhabricatorRepositoryIdentity();
+$conn = $table->establishConnection('w');
+
+$iterator = new LiskRawMigrationIterator($conn, $table->getTableName());
+foreach ($iterator as $row) {
+ $name = $row['identityNameRaw'];
+ $name = phutil_utf8ize($name);
+
+ $email = new PhutilEmailAddress($name);
+ $address = $email->getAddress();
+
+ try {
+ queryfx(
+ $conn,
+ 'UPDATE %R SET emailAddress = %ns WHERE id = %d',
+ $table,
+ $address,
+ $row['id']);
+ } catch (Exception $ex) {
+ // We may occasionally run into issues with binary or very long addresses.
+ // Just skip over them.
+ continue;
+ }
+}
diff --git a/src/applications/diffusion/controller/DiffusionIdentityViewController.php b/src/applications/diffusion/controller/DiffusionIdentityViewController.php
index 20efe2749f..0ac131daf1 100644
--- a/src/applications/diffusion/controller/DiffusionIdentityViewController.php
+++ b/src/applications/diffusion/controller/DiffusionIdentityViewController.php
@@ -1,135 +1,138 @@
<?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')
- ->setPolicyObject($identity);
+ ->setHeaderIcon('fa-globe');
$crumbs = $this->buildApplicationCrumbs();
- $crumbs->addTextCrumb($identity->getID());
+ $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())
- ->setUser($viewer);
+ ->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('Manually Set User'),
+ 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 null;
+ return phutil_tag('em', array(), pht('None'));
} else {
return $viewer->renderHandle($value);
}
}
}
diff --git a/src/applications/diffusion/controller/DiffusionRepositoryListController.php b/src/applications/diffusion/controller/DiffusionRepositoryListController.php
index 5a21d2e3f1..66226e5eab 100644
--- a/src/applications/diffusion/controller/DiffusionRepositoryListController.php
+++ b/src/applications/diffusion/controller/DiffusionRepositoryListController.php
@@ -1,36 +1,44 @@
<?php
final class DiffusionRepositoryListController extends DiffusionController {
public function shouldAllowPublic() {
return true;
}
public function handleRequest(AphrontRequest $request) {
$items = array();
$items[] = id(new PHUIListItemView())
->setType(PHUIListItemView::TYPE_LABEL)
->setName(pht('Commits'));
$items[] = id(new PHUIListItemView())
->setName(pht('Browse Commits'))
->setHref($this->getApplicationURI('commit/'));
+ $items[] = id(new PHUIListItemView())
+ ->setType(PHUIListItemView::TYPE_LABEL)
+ ->setName(pht('Identities'));
+
+ $items[] = id(new PHUIListItemView())
+ ->setName(pht('Browse Identities'))
+ ->setHref($this->getApplicationURI('identity/'));
+
return id(new PhabricatorRepositorySearchEngine())
->setController($this)
->setNavigationItems($items)
->buildResponse();
}
protected function buildApplicationCrumbs() {
$crumbs = parent::buildApplicationCrumbs();
id(new DiffusionRepositoryEditEngine())
->setViewer($this->getViewer())
->addActionToCrumbs($crumbs);
return $crumbs;
}
}
diff --git a/src/applications/repository/query/PhabricatorRepositoryIdentityQuery.php b/src/applications/repository/query/PhabricatorRepositoryIdentityQuery.php
index c64b1a296b..6ddf8d57c1 100644
--- a/src/applications/repository/query/PhabricatorRepositoryIdentityQuery.php
+++ b/src/applications/repository/query/PhabricatorRepositoryIdentityQuery.php
@@ -1,131 +1,130 @@
<?php
final class PhabricatorRepositoryIdentityQuery
extends PhabricatorCursorPagedPolicyAwareQuery {
private $ids;
private $phids;
private $identityNames;
- private $emailAddress;
+ private $emailAddresses;
private $assigneePHIDs;
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 withEmailAddress($address) {
- $this->emailAddress = $address;
+ public function withEmailAddresses(array $addresses) {
+ $this->emailAddresses = $addresses;
return $this;
}
public function withAssigneePHIDs(array $assignees) {
$this->assigneePHIDs = $assignees;
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) {
$where[] = qsprintf(
$conn,
'repository_identity.currentEffectiveUserPHID IN (%Ls)',
$this->assigneePHIDs);
}
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->emailAddress !== null) {
- $identity_style = "<{$this->emailAddress}>";
+ if ($this->emailAddresses !== null) {
$where[] = qsprintf(
$conn,
- 'repository_identity.identityNameRaw LIKE %<',
- $identity_style);
+ '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 e3833bd10e..c33b296fdc 100644
--- a/src/applications/repository/storage/PhabricatorRepositoryIdentity.php
+++ b/src/applications/repository/storage/PhabricatorRepositoryIdentity.php
@@ -1,130 +1,159 @@
<?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;
} else {
$this->currentEffectiveUserPHID = $this->automaticGuessedUserPHID;
}
+ $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) {
+ $capability,
+ PhabricatorUser $viewer) {
return false;
}
/* -( PhabricatorApplicationTransactionInterface )------------------------- */
public function getApplicationTransactionEditor() {
return new DiffusionRepositoryIdentityEditor();
}
public function getApplicationTransactionTemplate() {
return new PhabricatorRepositoryIdentityTransaction();
}
}
diff --git a/src/applications/repository/worker/PhabricatorRepositoryIdentityChangeWorker.php b/src/applications/repository/worker/PhabricatorRepositoryIdentityChangeWorker.php
index 3c129845cd..0ce01ce76a 100644
--- a/src/applications/repository/worker/PhabricatorRepositoryIdentityChangeWorker.php
+++ b/src/applications/repository/worker/PhabricatorRepositoryIdentityChangeWorker.php
@@ -1,34 +1,34 @@
<?php
final class PhabricatorRepositoryIdentityChangeWorker
extends PhabricatorWorker {
protected function doWork() {
$viewer = PhabricatorUser::getOmnipotentUser();
$task_data = $this->getTaskData();
$user_phid = idx($task_data, 'userPHID');
$user = id(new PhabricatorPeopleQuery())
->withPHIDs(array($user_phid))
->setViewer($viewer)
->executeOne();
$emails = id(new PhabricatorUserEmail())->loadAllWhere(
'userPHID = %s ORDER BY address',
$user->getPHID());
foreach ($emails as $email) {
$identities = id(new PhabricatorRepositoryIdentityQuery())
->setViewer($viewer)
- ->withEmailAddress($email->getAddress())
+ ->withEmailAddresses($email->getAddress())
->execute();
foreach ($identities as $identity) {
$identity->setAutomaticGuessedUserPHID($user->getPHID())
->save();
}
}
}
}

File Metadata

Mime Type
text/x-diff
Expires
Sun, Jan 19, 17:23 (1 w, 5 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1126915
Default Alt Text
(17 KB)

Event Timeline