1
0
Fork 0
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:
epriestley 2016-03-09 08:40:19 -08:00
parent 44c3f06ab9
commit 47dedfb152
6 changed files with 99 additions and 1 deletions

View file

@ -0,0 +1,2 @@
ALTER TABLE {$NAMESPACE}_maniphest.maniphest_task
ADD bridgedObjectPHID VARBINARY(64);

View file

@ -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',

View file

@ -0,0 +1,8 @@
<?php
interface DoorkeeperBridgedObjectInterface {
public function getBridgedObject();
public function attachBridgedObject(DoorkeeperExternalObject $object = null);
}

View file

@ -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;
}

View file

@ -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;
}
}

View file

@ -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;
}
}