Implement PhabricatorProjectInterface for marking that objects can be tagged with projects
Summary: Ref T2628. This makes Transactions understand objects that can have project relationships, extract project mentions, and handle watching. Test Plan: See next diff. Reviewers: btrahan Reviewed By: btrahan Subscribers: epriestley Maniphest Tasks: T2628 Differential Revision: https://secure.phabricator.com/D9340
This commit is contained in:
@@ -1957,6 +1957,7 @@ phutil_register_library_map(array(
|
|||||||
'PhabricatorProjectEditPictureController' => 'applications/project/controller/PhabricatorProjectEditPictureController.php',
|
'PhabricatorProjectEditPictureController' => 'applications/project/controller/PhabricatorProjectEditPictureController.php',
|
||||||
'PhabricatorProjectEditorTestCase' => 'applications/project/editor/__tests__/PhabricatorProjectEditorTestCase.php',
|
'PhabricatorProjectEditorTestCase' => 'applications/project/editor/__tests__/PhabricatorProjectEditorTestCase.php',
|
||||||
'PhabricatorProjectIcon' => 'applications/project/icon/PhabricatorProjectIcon.php',
|
'PhabricatorProjectIcon' => 'applications/project/icon/PhabricatorProjectIcon.php',
|
||||||
|
'PhabricatorProjectInterface' => 'applications/project/interface/PhabricatorProjectInterface.php',
|
||||||
'PhabricatorProjectListController' => 'applications/project/controller/PhabricatorProjectListController.php',
|
'PhabricatorProjectListController' => 'applications/project/controller/PhabricatorProjectListController.php',
|
||||||
'PhabricatorProjectMembersEditController' => 'applications/project/controller/PhabricatorProjectMembersEditController.php',
|
'PhabricatorProjectMembersEditController' => 'applications/project/controller/PhabricatorProjectMembersEditController.php',
|
||||||
'PhabricatorProjectMembersRemoveController' => 'applications/project/controller/PhabricatorProjectMembersRemoveController.php',
|
'PhabricatorProjectMembersRemoveController' => 'applications/project/controller/PhabricatorProjectMembersRemoveController.php',
|
||||||
@@ -1975,6 +1976,7 @@ phutil_register_library_map(array(
|
|||||||
'PhabricatorProjectTransaction' => 'applications/project/storage/PhabricatorProjectTransaction.php',
|
'PhabricatorProjectTransaction' => 'applications/project/storage/PhabricatorProjectTransaction.php',
|
||||||
'PhabricatorProjectTransactionEditor' => 'applications/project/editor/PhabricatorProjectTransactionEditor.php',
|
'PhabricatorProjectTransactionEditor' => 'applications/project/editor/PhabricatorProjectTransactionEditor.php',
|
||||||
'PhabricatorProjectTransactionQuery' => 'applications/project/query/PhabricatorProjectTransactionQuery.php',
|
'PhabricatorProjectTransactionQuery' => 'applications/project/query/PhabricatorProjectTransactionQuery.php',
|
||||||
|
'PhabricatorProjectUIEventListener' => 'applications/project/events/PhabricatorProjectUIEventListener.php',
|
||||||
'PhabricatorProjectUpdateController' => 'applications/project/controller/PhabricatorProjectUpdateController.php',
|
'PhabricatorProjectUpdateController' => 'applications/project/controller/PhabricatorProjectUpdateController.php',
|
||||||
'PhabricatorProjectWatchController' => 'applications/project/controller/PhabricatorProjectWatchController.php',
|
'PhabricatorProjectWatchController' => 'applications/project/controller/PhabricatorProjectWatchController.php',
|
||||||
'PhabricatorQuery' => 'infrastructure/query/PhabricatorQuery.php',
|
'PhabricatorQuery' => 'infrastructure/query/PhabricatorQuery.php',
|
||||||
@@ -4809,6 +4811,7 @@ phutil_register_library_map(array(
|
|||||||
'PhabricatorProjectTransaction' => 'PhabricatorApplicationTransaction',
|
'PhabricatorProjectTransaction' => 'PhabricatorApplicationTransaction',
|
||||||
'PhabricatorProjectTransactionEditor' => 'PhabricatorApplicationTransactionEditor',
|
'PhabricatorProjectTransactionEditor' => 'PhabricatorApplicationTransactionEditor',
|
||||||
'PhabricatorProjectTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
|
'PhabricatorProjectTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
|
||||||
|
'PhabricatorProjectUIEventListener' => 'PhabricatorEventListener',
|
||||||
'PhabricatorProjectUpdateController' => 'PhabricatorProjectController',
|
'PhabricatorProjectUpdateController' => 'PhabricatorProjectController',
|
||||||
'PhabricatorProjectWatchController' => 'PhabricatorProjectController',
|
'PhabricatorProjectWatchController' => 'PhabricatorProjectController',
|
||||||
'PhabricatorRecaptchaConfigOptions' => 'PhabricatorApplicationConfigOptions',
|
'PhabricatorRecaptchaConfigOptions' => 'PhabricatorApplicationConfigOptions',
|
||||||
|
|||||||
@@ -32,6 +32,12 @@ final class PhabricatorApplicationProject extends PhabricatorApplication {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getEventListeners() {
|
||||||
|
return array(
|
||||||
|
new PhabricatorProjectUIEventListener(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public function getRoutes() {
|
public function getRoutes() {
|
||||||
return array(
|
return array(
|
||||||
'/project/' => array(
|
'/project/' => array(
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorProjectUIEventListener
|
||||||
|
extends PhabricatorEventListener {
|
||||||
|
|
||||||
|
public function register() {
|
||||||
|
$this->listen(PhabricatorEventType::TYPE_UI_WILLRENDERPROPERTIES);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handleEvent(PhutilEvent $event) {
|
||||||
|
switch ($event->getType()) {
|
||||||
|
case PhabricatorEventType::TYPE_UI_WILLRENDERPROPERTIES:
|
||||||
|
$this->handlePropertyEvent($event);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function handlePropertyEvent($event) {
|
||||||
|
$user = $event->getUser();
|
||||||
|
$object = $event->getValue('object');
|
||||||
|
|
||||||
|
if (!$object || !$object->getPHID()) {
|
||||||
|
// No object, or the object has no PHID yet..
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!($object instanceof PhabricatorProjectInterface)) {
|
||||||
|
// This object doesn't have projects.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$project_phids = PhabricatorEdgeQuery::loadDestinationPHIDs(
|
||||||
|
$object->getPHID(),
|
||||||
|
PhabricatorEdgeConfig::TYPE_OBJECT_HAS_PROJECT);
|
||||||
|
if ($project_phids) {
|
||||||
|
$project_phids = array_reverse($project_phids);
|
||||||
|
$handles = id(new PhabricatorHandleQuery())
|
||||||
|
->setViewer($user)
|
||||||
|
->withPHIDs($project_phids)
|
||||||
|
->execute();
|
||||||
|
} else {
|
||||||
|
$handles = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($handles) {
|
||||||
|
$list = array();
|
||||||
|
foreach ($handles as $handle) {
|
||||||
|
$list[] = $handle->renderLink();
|
||||||
|
}
|
||||||
|
$list = phutil_implode_html(phutil_tag('br'), $list);
|
||||||
|
} else {
|
||||||
|
$list = phutil_tag('em', array(), pht('None'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$view = $event->getValue('view');
|
||||||
|
$view->addProperty(pht('Projects'), $list);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
interface PhabricatorProjectInterface {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -163,6 +163,10 @@ abstract class PhabricatorApplicationTransactionEditor
|
|||||||
$types[] = PhabricatorTransactions::TYPE_TOKEN;
|
$types[] = PhabricatorTransactions::TYPE_TOKEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($this->object instanceof PhabricatorProjectInterface) {
|
||||||
|
$types[] = PhabricatorTransactions::TYPE_EDGE;
|
||||||
|
}
|
||||||
|
|
||||||
return $types;
|
return $types;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1079,6 +1083,7 @@ abstract class PhabricatorApplicationTransactionEditor
|
|||||||
|
|
||||||
// TODO: For now, this is just a placeholder.
|
// TODO: For now, this is just a placeholder.
|
||||||
$engine = PhabricatorMarkupEngine::getEngine('extract');
|
$engine = PhabricatorMarkupEngine::getEngine('extract');
|
||||||
|
$engine->setConfig('viewer', $this->requireActor());
|
||||||
|
|
||||||
$block_xactions = $this->expandRemarkupBlockTransactions(
|
$block_xactions = $this->expandRemarkupBlockTransactions(
|
||||||
$object,
|
$object,
|
||||||
@@ -1098,11 +1103,41 @@ abstract class PhabricatorApplicationTransactionEditor
|
|||||||
array $xactions,
|
array $xactions,
|
||||||
$blocks,
|
$blocks,
|
||||||
PhutilMarkupEngine $engine) {
|
PhutilMarkupEngine $engine) {
|
||||||
return $this->expandCustomRemarkupBlockTransactions(
|
|
||||||
|
$block_xactions = $this->expandCustomRemarkupBlockTransactions(
|
||||||
$object,
|
$object,
|
||||||
$xactions,
|
$xactions,
|
||||||
$blocks,
|
$blocks,
|
||||||
$engine);
|
$engine);
|
||||||
|
|
||||||
|
if ($object instanceof PhabricatorProjectInterface) {
|
||||||
|
$phids = array();
|
||||||
|
foreach ($blocks as $key => $xaction_blocks) {
|
||||||
|
foreach ($xaction_blocks as $block) {
|
||||||
|
$engine->markupText($block);
|
||||||
|
$phids += $engine->getTextMetadata(
|
||||||
|
PhabricatorRemarkupRuleObject::KEY_MENTIONED_OBJECTS,
|
||||||
|
array());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$project_type = PhabricatorProjectPHIDTypeProject::TYPECONST;
|
||||||
|
foreach ($phids as $key => $phid) {
|
||||||
|
if (phid_get_type($phid) != $project_type) {
|
||||||
|
unset($phids[$key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($phids) {
|
||||||
|
$edge_type = PhabricatorEdgeConfig::TYPE_OBJECT_HAS_PROJECT;
|
||||||
|
$block_xactions[] = newv(get_class(head($xactions)), array())
|
||||||
|
->setTransactionType(PhabricatorTransactions::TYPE_EDGE)
|
||||||
|
->setMetadataValue('edge:type', $edge_type)
|
||||||
|
->setNewValue(array('+' => $phids));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $block_xactions;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function expandCustomRemarkupBlockTransactions(
|
protected function expandCustomRemarkupBlockTransactions(
|
||||||
@@ -1899,13 +1934,12 @@ abstract class PhabricatorApplicationTransactionEditor
|
|||||||
$has_support = true;
|
$has_support = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: This should be some interface which specifies that the object
|
// TODO: The Maniphest legacy stuff should get cleaned up here.
|
||||||
// has project associations.
|
|
||||||
if ($object instanceof ManiphestTask) {
|
|
||||||
|
|
||||||
// TODO: This is what normal objects would do, but Maniphest is still
|
if (($object instanceof ManiphestTask) ||
|
||||||
// behind the times.
|
($object instanceof PhabricatorProjectInterface)) {
|
||||||
if (false) {
|
|
||||||
|
if ($object instanceof PhabricatorProjectInterface) {
|
||||||
$project_phids = PhabricatorEdgeQuery::loadDestinationPHIDs(
|
$project_phids = PhabricatorEdgeQuery::loadDestinationPHIDs(
|
||||||
$object->getPHID(),
|
$object->getPHID(),
|
||||||
PhabricatorEdgeConfig::TYPE_OBJECT_HAS_PROJECT);
|
PhabricatorEdgeConfig::TYPE_OBJECT_HAS_PROJECT);
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ abstract class PhabricatorRemarkupRuleObject
|
|||||||
extends PhutilRemarkupRule {
|
extends PhutilRemarkupRule {
|
||||||
|
|
||||||
const KEY_RULE_OBJECT = 'rule.object';
|
const KEY_RULE_OBJECT = 'rule.object';
|
||||||
|
const KEY_MENTIONED_OBJECTS = 'rule.object.mentioned';
|
||||||
|
|
||||||
abstract protected function getObjectNamePrefix();
|
abstract protected function getObjectNamePrefix();
|
||||||
abstract protected function loadObjects(array $ids);
|
abstract protected function loadObjects(array $ids);
|
||||||
@@ -188,6 +189,12 @@ abstract class PhabricatorRemarkupRuleObject
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$phids = $engine->getTextMetadata(self::KEY_MENTIONED_OBJECTS, array());
|
||||||
|
foreach ($objects as $object) {
|
||||||
|
$phids[$object->getPHID()] = $object->getPHID();
|
||||||
|
}
|
||||||
|
$engine->setTextMetadata(self::KEY_MENTIONED_OBJECTS, $phids);
|
||||||
|
|
||||||
$handles = $this->loadHandles($objects);
|
$handles = $this->loadHandles($objects);
|
||||||
foreach ($metadata as $key => $spec) {
|
foreach ($metadata as $key => $spec) {
|
||||||
$handle = $handles[$spec['id']];
|
$handle = $handles[$spec['id']];
|
||||||
|
|||||||
Reference in New Issue
Block a user