Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F2892797
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Advanced/Developer...
View Handle
View Hovercard
Size
17 KB
Referenced Files
None
Subscribers
None
View Options
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
Details
Attached
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)
Attached To
Mode
rP Phorge
Attached
Detach File
Event Timeline
Log In to Comment