1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2025-01-25 14:08:19 +01:00

(stable) Promote 2018 Week 22

This commit is contained in:
epriestley 2018-06-02 18:26:13 -07:00
commit 236253df8c
34 changed files with 1242 additions and 15 deletions

View file

@ -9,8 +9,8 @@ return array(
'names' => array(
'conpherence.pkg.css' => 'e68cf1fa',
'conpherence.pkg.js' => '15191c65',
'core.pkg.css' => '8be474cc',
'core.pkg.js' => 'e452721e',
'core.pkg.css' => '8e3d1fb7',
'core.pkg.js' => '2058ec09',
'differential.pkg.css' => '06dc617c',
'differential.pkg.js' => 'c2ca903a',
'diffusion.pkg.css' => 'a2d17c7d',
@ -167,7 +167,7 @@ return array(
'rsrc/css/phui/phui-object-box.css' => '9cff003c',
'rsrc/css/phui/phui-pager.css' => 'edcbc226',
'rsrc/css/phui/phui-pinboard-view.css' => '2495140e',
'rsrc/css/phui/phui-property-list-view.css' => 'de4754d8',
'rsrc/css/phui/phui-property-list-view.css' => '546a04ae',
'rsrc/css/phui/phui-remarkup-preview.css' => '54a34863',
'rsrc/css/phui/phui-segment-bar-view.css' => 'b1d1b892',
'rsrc/css/phui/phui-spacing.css' => '042804d6',
@ -259,7 +259,7 @@ return array(
'rsrc/externals/javelin/lib/__tests__/URI.js' => '1e45fda9',
'rsrc/externals/javelin/lib/__tests__/behavior.js' => '1ea62783',
'rsrc/externals/javelin/lib/behavior.js' => '61cbc29a',
'rsrc/externals/javelin/lib/control/tokenizer/Tokenizer.js' => 'dfaf006b',
'rsrc/externals/javelin/lib/control/tokenizer/Tokenizer.js' => 'bb6e5c16',
'rsrc/externals/javelin/lib/control/typeahead/Typeahead.js' => '70baed2f',
'rsrc/externals/javelin/lib/control/typeahead/normalizer/TypeaheadNormalizer.js' => '185bbd53',
'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadCompositeSource.js' => '503e17fd',
@ -710,7 +710,7 @@ return array(
'javelin-scrollbar' => '9065f639',
'javelin-sound' => '949c0fe5',
'javelin-stratcom' => '327f418a',
'javelin-tokenizer' => 'dfaf006b',
'javelin-tokenizer' => 'bb6e5c16',
'javelin-typeahead' => '70baed2f',
'javelin-typeahead-composite-source' => '503e17fd',
'javelin-typeahead-normalizer' => '185bbd53',
@ -842,7 +842,7 @@ return array(
'phui-oi-simple-ui-css' => 'a8beebea',
'phui-pager-css' => 'edcbc226',
'phui-pinboard-view-css' => '2495140e',
'phui-property-list-view-css' => 'de4754d8',
'phui-property-list-view-css' => '546a04ae',
'phui-remarkup-preview-css' => '54a34863',
'phui-segment-bar-view-css' => 'b1d1b892',
'phui-spacing-css' => '042804d6',
@ -1842,6 +1842,12 @@ return array(
'javelin-uri',
'phabricator-notification',
),
'bb6e5c16' => array(
'javelin-dom',
'javelin-util',
'javelin-stratcom',
'javelin-install',
),
'bcaccd64' => array(
'javelin-behavior',
'javelin-behavior-device',
@ -2019,12 +2025,6 @@ return array(
'phuix-icon-view',
'phabricator-prefab',
),
'dfaf006b' => array(
'javelin-dom',
'javelin-util',
'javelin-stratcom',
'javelin-install',
),
'e1d25dfb' => array(
'javelin-behavior',
'javelin-stratcom',

View file

@ -0,0 +1,14 @@
CREATE TABLE {$NAMESPACE}_repository.repository_identity (
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
phid VARBINARY(64) NOT NULL,
dateCreated INT UNSIGNED NOT NULL,
dateModified INT UNSIGNED NOT NULL,
automaticGuessedUserPHID VARBINARY(64) DEFAULT NULL,
manuallySetUserPHID VARBINARY(64) DEFAULT NULL,
currentEffectiveUserPHID VARBINARY(64) DEFAULT NULL,
identityNameHash BINARY(12) NOT NULL,
identityNameRaw LONGBLOB NOT NULL,
identityNameEncoding VARCHAR(16) DEFAULT NULL COLLATE {$COLLATE_TEXT},
UNIQUE KEY `key_phid` (phid),
UNIQUE KEY `key_identity` (identityNameHash)
) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE={$COLLATE_TEXT};

View file

@ -0,0 +1,2 @@
ALTER TABLE {$NAMESPACE}_repository.repository_identity
ADD COLUMN authorPHID VARBINARY(64) NOT NULL;

View file

@ -0,0 +1,19 @@
CREATE TABLE {$NAMESPACE}_repository.repository_identitytransaction (
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) NOT NULL,
oldValue LONGTEXT NOT NULL,
newValue LONGTEXT NOT NULL,
contentSource LONGTEXT NOT NULL,
metadata LONGTEXT NOT NULL,
dateCreated INT UNSIGNED NOT NULL,
dateModified INT UNSIGNED NOT NULL,
UNIQUE KEY `key_phid` (`phid`),
KEY `key_object` (`objectPHID`)
) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE {$COLLATE_TEXT};

View file

@ -0,0 +1,3 @@
ALTER TABLE {$NAMESPACE}_repository.repository_commit
ADD COLUMN authorIdentityPHID VARBINARY(64) DEFAULT NULL,
ADD COLUMN committerIdentityPHID VARBINARY(64) DEFAULT NULL;

View file

@ -815,6 +815,13 @@ phutil_register_library_map(array(
'DiffusionHistoryTableView' => 'applications/diffusion/view/DiffusionHistoryTableView.php',
'DiffusionHistoryView' => 'applications/diffusion/view/DiffusionHistoryView.php',
'DiffusionHovercardEngineExtension' => 'applications/diffusion/engineextension/DiffusionHovercardEngineExtension.php',
'DiffusionIdentityAssigneeDatasource' => 'applications/diffusion/typeahead/DiffusionIdentityAssigneeDatasource.php',
'DiffusionIdentityAssigneeEditField' => 'applications/diffusion/editfield/DiffusionIdentityAssigneeEditField.php',
'DiffusionIdentityAssigneeSearchField' => 'applications/diffusion/searchfield/DiffusionIdentityAssigneeSearchField.php',
'DiffusionIdentityEditController' => 'applications/diffusion/controller/DiffusionIdentityEditController.php',
'DiffusionIdentityListController' => 'applications/diffusion/controller/DiffusionIdentityListController.php',
'DiffusionIdentityUnassignedDatasource' => 'applications/diffusion/typeahead/DiffusionIdentityUnassignedDatasource.php',
'DiffusionIdentityViewController' => 'applications/diffusion/controller/DiffusionIdentityViewController.php',
'DiffusionInlineCommentController' => 'applications/diffusion/controller/DiffusionInlineCommentController.php',
'DiffusionInlineCommentPreviewController' => 'applications/diffusion/controller/DiffusionInlineCommentPreviewController.php',
'DiffusionInternalAncestorsConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionInternalAncestorsConduitAPIMethod.php',
@ -937,6 +944,8 @@ phutil_register_library_map(array(
'DiffusionRepositoryEditUpdateController' => 'applications/diffusion/controller/DiffusionRepositoryEditUpdateController.php',
'DiffusionRepositoryFunctionDatasource' => 'applications/diffusion/typeahead/DiffusionRepositoryFunctionDatasource.php',
'DiffusionRepositoryHistoryManagementPanel' => 'applications/diffusion/management/DiffusionRepositoryHistoryManagementPanel.php',
'DiffusionRepositoryIdentityEditor' => 'applications/diffusion/editor/DiffusionRepositoryIdentityEditor.php',
'DiffusionRepositoryIdentitySearchEngine' => 'applications/diffusion/query/DiffusionRepositoryIdentitySearchEngine.php',
'DiffusionRepositoryListController' => 'applications/diffusion/controller/DiffusionRepositoryListController.php',
'DiffusionRepositoryManageController' => 'applications/diffusion/controller/DiffusionRepositoryManageController.php',
'DiffusionRepositoryManagePanelsController' => 'applications/diffusion/controller/DiffusionRepositoryManagePanelsController.php',
@ -4085,6 +4094,16 @@ phutil_register_library_map(array(
'PhabricatorRepositoryGitLFSRefQuery' => 'applications/repository/query/PhabricatorRepositoryGitLFSRefQuery.php',
'PhabricatorRepositoryGraphCache' => 'applications/repository/graphcache/PhabricatorRepositoryGraphCache.php',
'PhabricatorRepositoryGraphStream' => 'applications/repository/daemon/PhabricatorRepositoryGraphStream.php',
'PhabricatorRepositoryIdentity' => 'applications/repository/storage/PhabricatorRepositoryIdentity.php',
'PhabricatorRepositoryIdentityAssignTransaction' => 'applications/repository/xaction/PhabricatorRepositoryIdentityAssignTransaction.php',
'PhabricatorRepositoryIdentityChangeWorker' => 'applications/repository/worker/PhabricatorRepositoryIdentityChangeWorker.php',
'PhabricatorRepositoryIdentityEditEngine' => 'applications/repository/engine/PhabricatorRepositoryIdentityEditEngine.php',
'PhabricatorRepositoryIdentityFerretEngine' => 'applications/repository/search/PhabricatorRepositoryIdentityFerretEngine.php',
'PhabricatorRepositoryIdentityPHIDType' => 'applications/repository/phid/PhabricatorRepositoryIdentityPHIDType.php',
'PhabricatorRepositoryIdentityQuery' => 'applications/repository/query/PhabricatorRepositoryIdentityQuery.php',
'PhabricatorRepositoryIdentityTransaction' => 'applications/repository/storage/PhabricatorRepositoryIdentityTransaction.php',
'PhabricatorRepositoryIdentityTransactionQuery' => 'applications/repository/query/PhabricatorRepositoryIdentityTransactionQuery.php',
'PhabricatorRepositoryIdentityTransactionType' => 'applications/repository/xaction/PhabricatorRepositoryIdentityTransactionType.php',
'PhabricatorRepositoryManagementCacheWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementCacheWorkflow.php',
'PhabricatorRepositoryManagementClusterizeWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementClusterizeWorkflow.php',
'PhabricatorRepositoryManagementDiscoverWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementDiscoverWorkflow.php',
@ -4099,6 +4118,7 @@ phutil_register_library_map(array(
'PhabricatorRepositoryManagementMovePathsWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementMovePathsWorkflow.php',
'PhabricatorRepositoryManagementParentsWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementParentsWorkflow.php',
'PhabricatorRepositoryManagementPullWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementPullWorkflow.php',
'PhabricatorRepositoryManagementRebuildIdentitiesWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementRebuildIdentitiesWorkflow.php',
'PhabricatorRepositoryManagementRefsWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementRefsWorkflow.php',
'PhabricatorRepositoryManagementReparseWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementReparseWorkflow.php',
'PhabricatorRepositoryManagementThawWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementThawWorkflow.php',
@ -6152,6 +6172,13 @@ phutil_register_library_map(array(
'DiffusionHistoryTableView' => 'DiffusionHistoryView',
'DiffusionHistoryView' => 'DiffusionView',
'DiffusionHovercardEngineExtension' => 'PhabricatorHovercardEngineExtension',
'DiffusionIdentityAssigneeDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
'DiffusionIdentityAssigneeEditField' => 'PhabricatorTokenizerEditField',
'DiffusionIdentityAssigneeSearchField' => 'PhabricatorSearchTokenizerField',
'DiffusionIdentityEditController' => 'DiffusionController',
'DiffusionIdentityListController' => 'DiffusionController',
'DiffusionIdentityUnassignedDatasource' => 'PhabricatorTypeaheadDatasource',
'DiffusionIdentityViewController' => 'DiffusionController',
'DiffusionInlineCommentController' => 'PhabricatorInlineCommentController',
'DiffusionInlineCommentPreviewController' => 'PhabricatorInlineCommentPreviewController',
'DiffusionInternalAncestorsConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod',
@ -6273,6 +6300,8 @@ phutil_register_library_map(array(
'DiffusionRepositoryEditUpdateController' => 'DiffusionRepositoryManageController',
'DiffusionRepositoryFunctionDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
'DiffusionRepositoryHistoryManagementPanel' => 'DiffusionRepositoryManagementPanel',
'DiffusionRepositoryIdentityEditor' => 'PhabricatorApplicationTransactionEditor',
'DiffusionRepositoryIdentitySearchEngine' => 'PhabricatorApplicationSearchEngine',
'DiffusionRepositoryListController' => 'DiffusionController',
'DiffusionRepositoryManageController' => 'DiffusionController',
'DiffusionRepositoryManagePanelsController' => 'DiffusionRepositoryManageController',
@ -9975,6 +10004,20 @@ phutil_register_library_map(array(
'PhabricatorRepositoryGitLFSRefQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorRepositoryGraphCache' => 'Phobject',
'PhabricatorRepositoryGraphStream' => 'Phobject',
'PhabricatorRepositoryIdentity' => array(
'PhabricatorRepositoryDAO',
'PhabricatorPolicyInterface',
'PhabricatorApplicationTransactionInterface',
),
'PhabricatorRepositoryIdentityAssignTransaction' => 'PhabricatorRepositoryIdentityTransactionType',
'PhabricatorRepositoryIdentityChangeWorker' => 'PhabricatorWorker',
'PhabricatorRepositoryIdentityEditEngine' => 'PhabricatorEditEngine',
'PhabricatorRepositoryIdentityFerretEngine' => 'PhabricatorFerretEngine',
'PhabricatorRepositoryIdentityPHIDType' => 'PhabricatorPHIDType',
'PhabricatorRepositoryIdentityQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorRepositoryIdentityTransaction' => 'PhabricatorModularTransaction',
'PhabricatorRepositoryIdentityTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
'PhabricatorRepositoryIdentityTransactionType' => 'PhabricatorModularTransactionType',
'PhabricatorRepositoryManagementCacheWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
'PhabricatorRepositoryManagementClusterizeWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
'PhabricatorRepositoryManagementDiscoverWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
@ -9989,6 +10032,7 @@ phutil_register_library_map(array(
'PhabricatorRepositoryManagementMovePathsWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
'PhabricatorRepositoryManagementParentsWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
'PhabricatorRepositoryManagementPullWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
'PhabricatorRepositoryManagementRebuildIdentitiesWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
'PhabricatorRepositoryManagementRefsWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
'PhabricatorRepositoryManagementReparseWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
'PhabricatorRepositoryManagementThawWorkflow' => 'PhabricatorRepositoryManagementWorkflow',

View file

@ -124,6 +124,15 @@ final class PhabricatorDiffusionApplication extends PhabricatorApplication {
'(?P<repositoryCallsign>[A-Z]+)' => $repository_routes,
'(?P<repositoryID>[1-9]\d*)' => $repository_routes,
'identity/' => array(
$this->getQueryRoutePattern() =>
'DiffusionIdentityListController',
$this->getEditRoutePattern('edit/') =>
'DiffusionIdentityEditController',
'view/(?P<id>[^/]+)/' =>
'DiffusionIdentityViewController',
),
'inline/' => array(
'edit/(?P<phid>[^/]+)/' => 'DiffusionInlineCommentController',
'preview/(?P<phid>[^/]+)/'

View file

@ -0,0 +1,12 @@
<?php
final class DiffusionIdentityEditController
extends DiffusionController {
public function handleRequest(AphrontRequest $request) {
return id(new PhabricatorRepositoryIdentityEditEngine())
->setController($this)
->buildResponse();
}
}

View file

@ -0,0 +1,22 @@
<?php
final class DiffusionIdentityListController
extends DiffusionController {
public function handleRequest(AphrontRequest $request) {
return id(new DiffusionRepositoryIdentitySearchEngine())
->setController($this)
->buildResponse();
}
protected function buildApplicationCrumbs() {
$crumbs = parent::buildApplicationCrumbs();
id(new PhabricatorRepositoryIdentityEditEngine())
->setViewer($this->getViewer())
->addActionToCrumbs($crumbs);
return $crumbs;
}
}

View file

@ -0,0 +1,135 @@
<?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);
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb($identity->getID());
$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);
$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'),
$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;
} else {
return $viewer->renderHandle($value);
}
}
}

View file

@ -0,0 +1,22 @@
<?php
final class DiffusionIdentityAssigneeEditField
extends PhabricatorTokenizerEditField {
protected function newDatasource() {
return new DiffusionIdentityAssigneeDatasource();
}
protected function newHTTPParameterType() {
return new AphrontUserListHTTPParameterType();
}
protected function newConduitParameterType() {
if ($this->getIsSingleValue()) {
return new ConduitUserParameterType();
} else {
return new ConduitUserListParameterType();
}
}
}

View file

@ -0,0 +1,26 @@
<?php
final class DiffusionRepositoryIdentityEditor
extends PhabricatorApplicationTransactionEditor {
public function getEditorObjectsDescription() {
return pht('Repository Identity');
}
public function getCreateObjectTitle($author, $object) {
return pht('%s created this identity.', $author);
}
public function getCreateObjectTitleForFeed($author, $object) {
return pht('%s created %s.', $author, $object);
}
protected function supportsSearch() {
return true;
}
public function getEditorApplicationClass() {
return 'PhabricatorDiffusionApplication';
}
}

View file

@ -0,0 +1,108 @@
<?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 DiffusionIdentityAssigneeSearchField())
->setLabel(pht('Assigned To'))
->setKey('assignee')
->setDescription(pht('Search for identities by assignee.')),
id(new PhabricatorSearchTextField())
->setLabel(pht('Identity Contains'))
->setKey('match')
->setDescription(pht('Search for identities by substring.')),
id(new PhabricatorSearchThreeStateField())
->setLabel(pht('Is Assigned'))
->setKey('hasEffectivePHID')
->setOptions(
pht('(Show All)'),
pht('Show Only Assigned Identities'),
pht('Show Only Unassigned Identities')),
);
}
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']);
}
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);
foreach ($identities as $identity) {
$item = id(new PHUIObjectItemView())
->setObjectName(pht('Identity %d', $identity->getID()))
->setHeader($identity->getIdentityShortName())
->setHref($identity->getURI())
->setObject($identity);
$list->addItem($item);
}
$result = new PhabricatorApplicationSearchResultView();
$result->setObjectList($list);
$result->setNoDataString(pht('No Identities found.'));
return $result;
}
}

View file

@ -0,0 +1,22 @@
<?php
final class DiffusionIdentityAssigneeSearchField
extends PhabricatorSearchTokenizerField {
protected function getDefaultValue() {
return array();
}
protected function getValueFromRequest(AphrontRequest $request, $key) {
return $this->getUsersFromRequest($request, $key);
}
protected function newDatasource() {
return new DiffusionIdentityAssigneeDatasource();
}
protected function newConduitParameterType() {
return new ConduitUserListParameterType();
}
}

View file

@ -0,0 +1,21 @@
<?php
final class DiffusionIdentityAssigneeDatasource
extends PhabricatorTypeaheadCompositeDatasource {
public function getBrowseTitle() {
return pht('Browse Assignee');
}
public function getPlaceholderText() {
return pht('Type a username or function...');
}
public function getComponentDatasources() {
return array(
new PhabricatorPeopleDatasource(),
new DiffusionIdentityUnassignedDatasource(),
);
}
}

View file

@ -0,0 +1,77 @@
<?php
final class DiffusionIdentityUnassignedDatasource
extends PhabricatorTypeaheadDatasource {
const FUNCTION_TOKEN = 'unassigned()';
public function getBrowseTitle() {
return pht('Browse Explicitly Unassigned');
}
public function getPlaceholderText() {
return pht('Type "unassigned"...');
}
public function getDatasourceApplicationClass() {
return 'PhabricatorDiffusionApplication';
}
public function getDatasourceFunctions() {
return array(
'unassigned' => array(
'name' => pht('Explicitly Unassigned'),
'summary' => pht('Find results which are not assigned.'),
'description' => pht(
"This function includes results which have been explicitly ".
"unassigned. Use a query like this to find explicitly ".
"unassigned results:\n\n%s\n\n".
"If you combine this function with other functions, the query will ".
"return results which match the other selectors //or// have no ".
"assignee. For example, this query will find results which are ".
"assigned to `alincoln`, and will also find results which have been ".
"unassigned:\n\n%s",
'> unassigned()',
'> alincoln, unassigned()'),
),
);
}
public function loadResults() {
$results = array(
$this->buildUnassignedResult(),
);
return $this->filterResultsAgainstTokens($results);
}
protected function evaluateFunction($function, array $argv_list) {
$results = array();
foreach ($argv_list as $argv) {
$results[] = self::FUNCTION_TOKEN;
}
return $results;
}
public function renderFunctionTokens($function, array $argv_list) {
$results = array();
foreach ($argv_list as $argv) {
$results[] = PhabricatorTypeaheadTokenView::newFromTypeaheadResult(
$this->buildUnassignedResult());
}
return $results;
}
private function buildUnassignedResult() {
$name = pht('Unassigned');
return $this->newFunctionResult()
->setName($name.' unassigned')
->setDisplayName($name)
->setIcon('fa-ban')
->setPHID('unassigned()')
->setUnique(true)
->addAttribute(pht('Select results with no owner.'));
}
}

View file

@ -420,6 +420,12 @@ final class PhabricatorUserEditor extends PhabricatorEditor {
$user->endWriteLocking();
$user->saveTransaction();
// Try and match this new address against unclaimed `RepositoryIdentity`s
PhabricatorWorker::scheduleTask(
'PhabricatorRepositoryIdentityChangeWorker',
array('userPHID' => $user->getPHID()),
array('objectPHID' => $user->getPHID()));
return $this;
}

View file

@ -83,7 +83,11 @@ final class PhortunePaymentMethod extends PhortuneDAO
public function getDescription() {
$provider = $this->buildPaymentProvider();
return $provider->getPaymentMethodProviderDescription();
$expires = $this->getDisplayExpires();
$description = $provider->getPaymentMethodProviderDescription();
return pht("Expires %s \xC2\xB7 %s", $expires, $description);
}
public function getMetadataValue($key, $default = null) {

View file

@ -0,0 +1,91 @@
<?php
final class PhabricatorRepositoryIdentityEditEngine
extends PhabricatorEditEngine {
const ENGINECONST = 'repository.identity';
public function isEngineConfigurable() {
return false;
}
public function getEngineName() {
return pht('Repository Identities');
}
public function getSummaryHeader() {
return pht('Edit Repository Identity Configurations');
}
public function getSummaryText() {
return pht('This engine is used to edit Repository identities.');
}
public function getEngineApplicationClass() {
return 'PhabricatorDiffusionApplication';
}
protected function newEditableObject() {
return new PhabricatorRepositoryIdentity();
}
protected function newObjectQuery() {
return new PhabricatorRepositoryIdentityQuery();
}
protected function getObjectCreateTitleText($object) {
return pht('Create Identity');
}
protected function getObjectCreateButtonText($object) {
return pht('Create Identity');
}
protected function getObjectEditTitleText($object) {
return pht('Edit Identity: %s', $object->getIdentityShortName());
}
protected function getObjectEditShortText($object) {
return pht('Edit Identity');
}
protected function getObjectCreateShortText() {
return pht('Create Identity');
}
protected function getObjectName() {
return pht('Identity');
}
protected function getEditorURI() {
return '/diffusion/identity/edit/';
}
protected function getObjectCreateCancelURI($object) {
return '/diffusion/identity/';
}
protected function getObjectViewURI($object) {
return $object->getURI();
}
protected function getCreateNewObjectPolicy() {
return PhabricatorPolicies::POLICY_USER;
}
protected function buildCustomEditFields($object) {
return array(
id(new DiffusionIdentityAssigneeEditField())
->setKey('manuallySetUserPHID')
->setLabel(pht('Assigned To'))
->setDescription(pht('Override this identity\'s assignment.'))
->setTransactionType(
PhabricatorRepositoryIdentityAssignTransaction::TRANSACTIONTYPE)
->setIsCopyable(true)
->setIsNullable(true)
->setSingleValue($object->getManuallySetUserPHID()),
);
}
}

View file

@ -0,0 +1,101 @@
<?php
final class PhabricatorRepositoryManagementRebuildIdentitiesWorkflow
extends PhabricatorRepositoryManagementWorkflow {
protected function didConstruct() {
$this
->setName('rebuild-identities')
->setExamples(
'**rebuild-identities** [__options__] __repository__')
->setSynopsis(pht('Rebuild repository identities from commits.'))
->setArguments(
array(
array(
'name' => 'repositories',
'wildcard' => true,
),
array(
'name' => 'all',
'help' => pht('Rebuild identities across all repositories.'),
),
));
}
public function execute(PhutilArgumentParser $args) {
$console = PhutilConsole::getConsole();
$all = $args->getArg('all');
$repositories = $args->getArg('repositories');
if ($all xor empty($repositories)) {
throw new PhutilArgumentUsageException(
pht('Specify --all or a list of repositories, but not both.'));
}
$query = id(new DiffusionCommitQuery())
->setViewer(PhabricatorUser::getOmnipotentUser())
->needCommitData(true);
if ($repositories) {
$repos = $this->loadRepositories($args, 'repositories');
$query->withRepositoryIDs(mpull($repos, 'getID'));
}
$iterator = new PhabricatorQueryIterator($query);
foreach ($iterator as $commit) {
$data = $commit->getCommitData();
$author_name = $data->getAuthorName();
$author_identity = $this->getIdentityForCommit(
$commit, $author_name);
$commit->setAuthorIdentityPHID($author_identity->getPHID());
$data->setCommitDetail(
'authorIdentityPHID', $author_identity->getPHID());
$committer_name = $data->getCommitDetail('committer', null);
if ($committer_name) {
$committer_identity = $this->getIdentityForCommit(
$commit, $committer_name);
$commit->setCommitterIdentityPHID($committer_identity->getPHID());
$data->setCommitDetail(
'committerIdentityPHID', $committer_identity->getPHID());
}
$commit->save();
$data->save();
}
}
private function getIdentityForCommit(
PhabricatorRepositoryCommit $commit, $identity_name) {
static $seen = array();
$identity_key = PhabricatorHash::digestForIndex($identity_name);
if (empty($seen[$identity_key])) {
try {
$user_phid = id(new DiffusionResolveUserQuery())
->withCommit($commit)
->withName($identity_name)
->execute();
$identity = id(new PhabricatorRepositoryIdentity())
->setAuthorPHID($commit->getPHID())
->setIdentityName($identity_name)
->setAutomaticGuessedUserPHID($user_phid)
->save();
} catch (AphrontDuplicateKeyQueryException $ex) {
// Somehow this identity already exists?
$identity = id(new PhabricatorRepositoryIdentityQuery())
->setViewer(PhabricatorUser::getOmnipotentUser())
->withIdentityNames(array($identity_name))
->executeOne();
}
$seen[$identity_key] = $identity;
}
return $seen[$identity_key];
}
}

View file

@ -6,7 +6,7 @@ final class PhabricatorRepositoryManagementReparseWorkflow
protected function didConstruct() {
$this
->setName('reparse')
->setExamples('**reparse** [options] __repository__')
->setExamples('**reparse** [options] __commit__')
->setSynopsis(
pht(
'**reparse** __what__ __which_parts__ [--trace] [--force]'."\n\n".

View file

@ -0,0 +1,33 @@
<?php
final class PhabricatorRepositoryIdentityPHIDType
extends PhabricatorPHIDType {
const TYPECONST = 'RIDT';
public function getTypeName() {
return pht('Repository Identity');
}
public function newObject() {
return new PhabricatorRepositoryIdentity();
}
public function getPHIDTypeApplicationClass() {
return 'PhabricatorDiffusionApplication';
}
protected function buildQueryForObjects(
PhabricatorObjectQuery $query,
array $phids) {
return id(new PhabricatorRepositoryIdentityQuery())
->withPHIDs($phids);
}
public function loadHandles(
PhabricatorHandleQuery $query,
array $handles,
array $objects) {}
}

View file

@ -0,0 +1,131 @@
<?php
final class PhabricatorRepositoryIdentityQuery
extends PhabricatorCursorPagedPolicyAwareQuery {
private $ids;
private $phids;
private $identityNames;
private $emailAddress;
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;
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}>";
$where[] = qsprintf(
$conn,
'repository_identity.identityNameRaw LIKE %<',
$identity_style);
}
if ($this->identityNameLike != null) {
$where[] = qsprintf(
$conn,
'repository_identity.identityNameRaw LIKE %~',
$this->identityNameLike);
}
return $where;
}
public function getQueryApplicationClass() {
return 'PhabricatorDiffusionApplication';
}
}

View file

@ -0,0 +1,10 @@
<?php
final class PhabricatorRepositoryIdentityTransactionQuery
extends PhabricatorApplicationTransactionQuery {
public function getTemplateApplicationTransaction() {
return new PhabricatorRepositoryIdentityTransaction();
}
}

View file

@ -0,0 +1,18 @@
<?php
final class PhabricatorRepositoryIdentityFerretEngine
extends PhabricatorFerretEngine {
public function getApplicationName() {
return 'repository';
}
public function getScopeName() {
return 'identity';
}
public function newSearchEngine() {
return new DiffusionRepositoryIdentitySearchEngine();
}
}

View file

@ -21,6 +21,8 @@ final class PhabricatorRepositoryCommit
protected $repositoryID;
protected $phid;
protected $authorIdentityPHID;
protected $committerIdentityPHID;
protected $commitIdentifier;
protected $epoch;
protected $mailKey;
@ -113,6 +115,8 @@ final class PhabricatorRepositoryCommit
'commitIdentifier' => 'text40',
'mailKey' => 'bytes20',
'authorPHID' => 'phid?',
'authorIdentityPHID' => 'phid?',
'committerIdentityPHID' => 'phid?',
'auditStatus' => 'uint32',
'summary' => 'text255',
'importStatus' => 'uint32',

View file

@ -0,0 +1,119 @@
<?php
final class PhabricatorRepositoryIdentity
extends PhabricatorRepositoryDAO
implements
PhabricatorPolicyInterface,
PhabricatorApplicationTransactionInterface {
protected $authorPHID;
protected $identityNameHash;
protected $identityNameRaw;
protected $identityNameEncoding;
protected $automaticGuessedUserPHID;
protected $manuallySetUserPHID;
protected $currentEffectiveUserPHID;
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?',
),
self::CONFIG_KEY_SCHEMA => array(
'key_identity' => array(
'columns' => array('identityNameHash'),
'unique' => true,
),
),
) + 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 getIdentityShortName() {
// TODO
return $this->getIdentityName();
}
public function getURI() {
return '/diffusion/identity/view/'.$this->getID().'/';
}
public function save() {
if ($this->manuallySetUserPHID) {
$this->currentEffectiveUserPHID = $this->manuallySetUserPHID;
} else {
$this->currentEffectiveUserPHID = $this->automaticGuessedUserPHID;
}
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 getApplicationTransactionObject() {
return $this;
}
public function getApplicationTransactionTemplate() {
return new PhabricatorRepositoryIdentityTransaction();
}
public function willRenderTimeline(
PhabricatorApplicationTransactionView $timeline,
AphrontRequest $request) {
return $timeline;
}
}

View file

@ -0,0 +1,18 @@
<?php
final class PhabricatorRepositoryIdentityTransaction
extends PhabricatorModularTransaction {
public function getApplicationTransactionType() {
return PhabricatorRepositoryIdentityPHIDType::TYPECONST;
}
public function getBaseTransactionClass() {
return 'PhabricatorRepositoryIdentityTransactionType';
}
public function getApplicationName() {
return 'repository';
}
}

View file

@ -0,0 +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())
->execute();
foreach ($identities as $identity) {
$identity->setAutomaticGuessedUserPHID($user->getPHID())
->save();
}
}
}
}

View file

@ -66,6 +66,34 @@ abstract class PhabricatorRepositoryCommitMessageParserWorker
$committer = $ref->getCommitter();
$hashes = $ref->getHashes();
$author_identity = id(new PhabricatorRepositoryIdentityQuery())
->setViewer(PhabricatorUser::getOmnipotentUser())
->withIdentityNames(array($author))
->executeOne();
if (!$author_identity) {
$author_identity = id(new PhabricatorRepositoryIdentity())
->setAuthorPHID($commit->getPHID())
->setIdentityName($author)
->setAutomaticGuessedUserPHID(
$this->resolveUserPHID($commit, $author))
->save();
}
$committer_identity = id(new PhabricatorRepositoryIdentityQuery())
->setViewer(PhabricatorUser::getOmnipotentUser())
->withIdentityNames(array($committer))
->executeOne();
if (!$committer_identity) {
$committer_identity = id(new PhabricatorRepositoryIdentity())
->setAuthorPHID($commit->getPHID())
->setIdentityName($committer)
->setAutomaticGuessedUserPHID(
$this->resolveUserPHID($commit, $committer))
->save();
}
$data = id(new PhabricatorRepositoryCommitData())->loadOneWhere(
'commitID = %d',
$commit->getID());
@ -81,6 +109,8 @@ abstract class PhabricatorRepositoryCommitMessageParserWorker
$data->setCommitDetail('authorName', $ref->getAuthorName());
$data->setCommitDetail('authorEmail', $ref->getAuthorEmail());
$data->setCommitDetail(
'authorIdentityPHID', $author_identity->getPHID());
$data->setCommitDetail(
'authorPHID',
$this->resolveUserPHID($commit, $author));
@ -96,6 +126,8 @@ abstract class PhabricatorRepositoryCommitMessageParserWorker
$data->setCommitDetail(
'committerPHID',
$this->resolveUserPHID($commit, $committer));
$data->setCommitDetail(
'committerIdentityPHID', $committer_identity->getPHID());
}
$repository = $this->repository;
@ -133,6 +165,9 @@ abstract class PhabricatorRepositoryCommitMessageParserWorker
$commit->setAuthorPHID($author_phid);
}
$commit->setAuthorIdentityPHID($author_identity->getPHID());
$commit->setCommitterIdentityPHID($committer_identity->getPHID());
$commit->setSummary($data->getSummary());
$commit->save();

View file

@ -0,0 +1,81 @@
<?php
final class PhabricatorRepositoryIdentityAssignTransaction
extends PhabricatorRepositoryIdentityTransactionType {
const TRANSACTIONTYPE = 'repository:identity:assign';
public function generateOldValue($object) {
return nonempty($object->getManuallySetUserPHID(), null);
}
public function applyInternalEffects($object, $value) {
$object->setManuallySetUserPHID($value);
}
public function getTitle() {
$old = $this->getOldValue();
$new = $this->getNewValue();
if (!$old) {
return pht(
'%s assigned this identity to %s.',
$this->renderAuthor(),
$this->renderIdentityHandle($new));
} else if (!$new) {
return pht(
'%s removed %s as the assignee of this identity.',
$this->renderAuthor(),
$this->renderIdentityHandle($old));
} else {
return pht(
'%s changed the assigned user for this identity from %s to %s.',
$this->renderAuthor(),
$this->renderIdentityHandle($old),
$this->renderIdentityHandle($new));
}
}
private function renderIdentityHandle($handle) {
$unassigned_token = DiffusionIdentityUnassignedDatasource::FUNCTION_TOKEN;
if ($handle === $unassigned_token) {
return phutil_tag('em', array(), pht('Explicitly Unassigned'));
} else {
return $this->renderHandle($handle);
}
}
public function validateTransactions($object, array $xactions) {
$errors = array();
$unassigned_token = DiffusionIdentityUnassignedDatasource::FUNCTION_TOKEN;
foreach ($xactions as $xaction) {
$old = $xaction->getOldValue();
$new = $xaction->getNewValue();
if (!strlen($new)) {
continue;
}
if ($new === $old) {
continue;
}
if ($new === $unassigned_token) {
continue;
}
$assignee_list = id(new PhabricatorPeopleQuery())
->setViewer($this->getActor())
->withPHIDs(array($new))
->execute();
if (!$assignee_list) {
$errors[] = $this->newInvalidError(
pht('User "%s" is not a valid user.',
$new));
}
}
return $errors;
}
}

View file

@ -0,0 +1,4 @@
<?php
abstract class PhabricatorRepositoryIdentityTransactionType
extends PhabricatorModularTransactionType {}

View file

@ -207,6 +207,7 @@ div.phui-property-list-stacked .phui-property-list-properties
.document-engine-image img {
margin: 20px auto;
background: url('/rsrc/image/checker_light.png');
max-width: 100%;
}
.device-desktop .document-engine-image img:hover {

View file

@ -400,7 +400,8 @@ JX.install('Tokenizer', {
// this unusual token.
var tok;
while ((tok = this._tokens.pop()) !== null) {
while (this._tokens.length) {
tok = this._tokens.pop();
if (this._remove(tok, true)) {
break;
}