mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-29 10:12:41 +01:00
Introduce "bridged" objects
Summary: Ref T10537. These are objects which are bound to some external object, like a Maniphest task which is a representation of a GitHub issue. This doesn't do much yet and may change, but my thinking is: - I'm putting these on-object instead of on edges because I think we want to actively change the UI for them (e.g., clearly call out that the object is bridged) but don't want every page to need to do extra queries in the common case where zero bridged objects exist anywhere in the system. - I'm making these one-to-one, more or less: an issue can't be bridged to a bunch of tasks, nor can a bunch of tasks be bridged to a single issue. Pretty sure this makes sense? I can't come up with any reasonable, realistic cases where you want a single GitHub issue to publish to multiple different tasks in Maniphest. - Technically, one type of each bridgable object could be bridged, but I expect this to never actually occur. Hopefully. Test Plan: Ran storage upgrade, loaded some pages. Reviewers: chad Reviewed By: chad Subscribers: Luke081515.2 Maniphest Tasks: T10537 Differential Revision: https://secure.phabricator.com/D15502
This commit is contained in:
parent
44c3f06ab9
commit
47dedfb152
6 changed files with 99 additions and 1 deletions
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE {$NAMESPACE}_maniphest.maniphest_task
|
||||
ADD bridgedObjectPHID VARBINARY(64);
|
|
@ -845,6 +845,7 @@ phutil_register_library_map(array(
|
|||
'DoorkeeperBridgeGitHubIssue' => 'applications/doorkeeper/bridge/DoorkeeperBridgeGitHubIssue.php',
|
||||
'DoorkeeperBridgeJIRA' => 'applications/doorkeeper/bridge/DoorkeeperBridgeJIRA.php',
|
||||
'DoorkeeperBridgeJIRATestCase' => 'applications/doorkeeper/bridge/__tests__/DoorkeeperBridgeJIRATestCase.php',
|
||||
'DoorkeeperBridgedObjectInterface' => 'applications/doorkeeper/bridge/DoorkeeperBridgedObjectInterface.php',
|
||||
'DoorkeeperDAO' => 'applications/doorkeeper/storage/DoorkeeperDAO.php',
|
||||
'DoorkeeperExternalObject' => 'applications/doorkeeper/storage/DoorkeeperExternalObject.php',
|
||||
'DoorkeeperExternalObjectQuery' => 'applications/doorkeeper/query/DoorkeeperExternalObjectQuery.php',
|
||||
|
@ -5636,6 +5637,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorSpacesInterface',
|
||||
'PhabricatorConduitResultInterface',
|
||||
'PhabricatorFulltextInterface',
|
||||
'DoorkeeperBridgedObjectInterface',
|
||||
),
|
||||
'ManiphestTaskAssignHeraldAction' => 'HeraldAction',
|
||||
'ManiphestTaskAssignOtherHeraldAction' => 'ManiphestTaskAssignHeraldAction',
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
<?php
|
||||
|
||||
interface DoorkeeperBridgedObjectInterface {
|
||||
|
||||
public function getBridgedObject();
|
||||
public function attachBridgedObject(DoorkeeperExternalObject $object = null);
|
||||
|
||||
}
|
|
@ -19,6 +19,7 @@ final class ManiphestTaskQuery extends PhabricatorCursorPagedPolicyAwareQuery {
|
|||
private $dateModifiedBefore;
|
||||
private $subpriorityMin;
|
||||
private $subpriorityMax;
|
||||
private $bridgedObjectPHIDs;
|
||||
|
||||
private $fullTextSearch = '';
|
||||
|
||||
|
@ -208,6 +209,11 @@ final class ManiphestTaskQuery extends PhabricatorCursorPagedPolicyAwareQuery {
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function withBridgedObjectPHIDs(array $phids) {
|
||||
$this->bridgedObjectPHIDs = $phids;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function newResultObject() {
|
||||
return new ManiphestTask();
|
||||
}
|
||||
|
@ -417,6 +423,13 @@ final class ManiphestTaskQuery extends PhabricatorCursorPagedPolicyAwareQuery {
|
|||
$this->subpriorityMax);
|
||||
}
|
||||
|
||||
if ($this->bridgedObjectPHIDs !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
'task.bridgedObjectPHID IN (%Ls)',
|
||||
$this->bridgedObjectPHIDs);
|
||||
}
|
||||
|
||||
return $where;
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,8 @@ final class ManiphestTask extends ManiphestDAO
|
|||
PhabricatorProjectInterface,
|
||||
PhabricatorSpacesInterface,
|
||||
PhabricatorConduitResultInterface,
|
||||
PhabricatorFulltextInterface {
|
||||
PhabricatorFulltextInterface,
|
||||
DoorkeeperBridgedObjectInterface {
|
||||
|
||||
const MARKUP_FIELD_DESCRIPTION = 'markup:desc';
|
||||
|
||||
|
@ -36,6 +37,7 @@ final class ManiphestTask extends ManiphestDAO
|
|||
|
||||
protected $ownerOrdering;
|
||||
protected $spacePHID;
|
||||
protected $bridgedObjectPHID;
|
||||
protected $properties = array();
|
||||
protected $points;
|
||||
|
||||
|
@ -43,6 +45,7 @@ final class ManiphestTask extends ManiphestDAO
|
|||
private $groupByProjectPHID = self::ATTACHABLE;
|
||||
private $customFields = self::ATTACHABLE;
|
||||
private $edgeProjectPHIDs = self::ATTACHABLE;
|
||||
private $bridgedObject = self::ATTACHABLE;
|
||||
|
||||
public static function initializeNewTask(PhabricatorUser $actor) {
|
||||
$app = id(new PhabricatorApplicationQuery())
|
||||
|
@ -82,6 +85,7 @@ final class ManiphestTask extends ManiphestDAO
|
|||
'originalEmailSource' => 'text255?',
|
||||
'subpriority' => 'double',
|
||||
'points' => 'double?',
|
||||
'bridgedObjectPHID' => 'phid?',
|
||||
),
|
||||
self::CONFIG_KEY_SCHEMA => array(
|
||||
'key_phid' => null,
|
||||
|
@ -116,6 +120,10 @@ final class ManiphestTask extends ManiphestDAO
|
|||
'key_title' => array(
|
||||
'columns' => array('title(64)'),
|
||||
),
|
||||
'key_bridgedobject' => array(
|
||||
'columns' => array('bridgedObjectPHID'),
|
||||
'unique' => true,
|
||||
),
|
||||
),
|
||||
) + parent::getConfiguration();
|
||||
}
|
||||
|
@ -504,4 +512,18 @@ final class ManiphestTask extends ManiphestDAO
|
|||
return new ManiphestTaskFulltextEngine();
|
||||
}
|
||||
|
||||
|
||||
/* -( DoorkeeperBridgedObjectInterface )----------------------------------- */
|
||||
|
||||
|
||||
public function getBridgedObject() {
|
||||
return $this->assertAttached($this->bridgedObject);
|
||||
}
|
||||
|
||||
public function attachBridgedObject(
|
||||
DoorkeeperExternalObject $object = null) {
|
||||
$this->bridgedObject = $object;
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -234,6 +234,9 @@ abstract class PhabricatorPolicyAwareQuery extends PhabricatorOffsetPagedQuery {
|
|||
|
||||
if ($page) {
|
||||
$maybe_visible = $this->willFilterPage($page);
|
||||
if ($maybe_visible) {
|
||||
$maybe_visible = $this->applyWillFilterPageExtensions($maybe_visible);
|
||||
}
|
||||
} else {
|
||||
$maybe_visible = array();
|
||||
}
|
||||
|
@ -672,4 +675,52 @@ abstract class PhabricatorPolicyAwareQuery extends PhabricatorOffsetPagedQuery {
|
|||
return PhabricatorApplication::isClassInstalledForViewer($class, $viewer);
|
||||
}
|
||||
|
||||
private function applyWillFilterPageExtensions(array $page) {
|
||||
$bridges = array();
|
||||
foreach ($page as $key => $object) {
|
||||
if ($object instanceof DoorkeeperBridgedObjectInterface) {
|
||||
$bridges[$key] = $object;
|
||||
}
|
||||
}
|
||||
|
||||
if ($bridges) {
|
||||
$external_phids = array();
|
||||
foreach ($bridges as $bridge) {
|
||||
$external_phid = $bridge->getBridgedObjectPHID();
|
||||
if ($external_phid) {
|
||||
$external_phids[$key] = $external_phid;
|
||||
}
|
||||
}
|
||||
|
||||
if ($external_phids) {
|
||||
$external_objects = id(new DoorkeeperExternalObjectQuery())
|
||||
->setViewer($this->getViewer())
|
||||
->withPHIDs($external_phids)
|
||||
->execute();
|
||||
$external_objects = mpull($external_objects, null, 'getPHID');
|
||||
} else {
|
||||
$external_objects = array();
|
||||
}
|
||||
|
||||
foreach ($bridges as $key => $bridge) {
|
||||
$external_phid = idx($external_phids, $key);
|
||||
if (!$external_phid) {
|
||||
$bridge->attachBridgedObject(null);
|
||||
continue;
|
||||
}
|
||||
|
||||
$external_object = idx($external_objects, $external_phid);
|
||||
if (!$external_object) {
|
||||
$this->didRejectResult($bridge);
|
||||
unset($page[$key]);
|
||||
continue;
|
||||
}
|
||||
|
||||
$bridge->attachBridgedObject($external_object);
|
||||
}
|
||||
}
|
||||
|
||||
return $page;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue