mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-22 23:02:42 +01:00
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:
parent
0d87fef573
commit
4cda3e5811
6 changed files with 121 additions and 7 deletions
|
@ -1957,6 +1957,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorProjectEditPictureController' => 'applications/project/controller/PhabricatorProjectEditPictureController.php',
|
||||
'PhabricatorProjectEditorTestCase' => 'applications/project/editor/__tests__/PhabricatorProjectEditorTestCase.php',
|
||||
'PhabricatorProjectIcon' => 'applications/project/icon/PhabricatorProjectIcon.php',
|
||||
'PhabricatorProjectInterface' => 'applications/project/interface/PhabricatorProjectInterface.php',
|
||||
'PhabricatorProjectListController' => 'applications/project/controller/PhabricatorProjectListController.php',
|
||||
'PhabricatorProjectMembersEditController' => 'applications/project/controller/PhabricatorProjectMembersEditController.php',
|
||||
'PhabricatorProjectMembersRemoveController' => 'applications/project/controller/PhabricatorProjectMembersRemoveController.php',
|
||||
|
@ -1975,6 +1976,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorProjectTransaction' => 'applications/project/storage/PhabricatorProjectTransaction.php',
|
||||
'PhabricatorProjectTransactionEditor' => 'applications/project/editor/PhabricatorProjectTransactionEditor.php',
|
||||
'PhabricatorProjectTransactionQuery' => 'applications/project/query/PhabricatorProjectTransactionQuery.php',
|
||||
'PhabricatorProjectUIEventListener' => 'applications/project/events/PhabricatorProjectUIEventListener.php',
|
||||
'PhabricatorProjectUpdateController' => 'applications/project/controller/PhabricatorProjectUpdateController.php',
|
||||
'PhabricatorProjectWatchController' => 'applications/project/controller/PhabricatorProjectWatchController.php',
|
||||
'PhabricatorQuery' => 'infrastructure/query/PhabricatorQuery.php',
|
||||
|
@ -4809,6 +4811,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorProjectTransaction' => 'PhabricatorApplicationTransaction',
|
||||
'PhabricatorProjectTransactionEditor' => 'PhabricatorApplicationTransactionEditor',
|
||||
'PhabricatorProjectTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
|
||||
'PhabricatorProjectUIEventListener' => 'PhabricatorEventListener',
|
||||
'PhabricatorProjectUpdateController' => 'PhabricatorProjectController',
|
||||
'PhabricatorProjectWatchController' => 'PhabricatorProjectController',
|
||||
'PhabricatorRecaptchaConfigOptions' => 'PhabricatorApplicationConfigOptions',
|
||||
|
|
|
@ -32,6 +32,12 @@ final class PhabricatorApplicationProject extends PhabricatorApplication {
|
|||
);
|
||||
}
|
||||
|
||||
public function getEventListeners() {
|
||||
return array(
|
||||
new PhabricatorProjectUIEventListener(),
|
||||
);
|
||||
}
|
||||
|
||||
public function getRoutes() {
|
||||
return 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;
|
||||
}
|
||||
|
||||
if ($this->object instanceof PhabricatorProjectInterface) {
|
||||
$types[] = PhabricatorTransactions::TYPE_EDGE;
|
||||
}
|
||||
|
||||
return $types;
|
||||
}
|
||||
|
||||
|
@ -1079,6 +1083,7 @@ abstract class PhabricatorApplicationTransactionEditor
|
|||
|
||||
// TODO: For now, this is just a placeholder.
|
||||
$engine = PhabricatorMarkupEngine::getEngine('extract');
|
||||
$engine->setConfig('viewer', $this->requireActor());
|
||||
|
||||
$block_xactions = $this->expandRemarkupBlockTransactions(
|
||||
$object,
|
||||
|
@ -1098,11 +1103,41 @@ abstract class PhabricatorApplicationTransactionEditor
|
|||
array $xactions,
|
||||
$blocks,
|
||||
PhutilMarkupEngine $engine) {
|
||||
return $this->expandCustomRemarkupBlockTransactions(
|
||||
|
||||
$block_xactions = $this->expandCustomRemarkupBlockTransactions(
|
||||
$object,
|
||||
$xactions,
|
||||
$blocks,
|
||||
$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(
|
||||
|
@ -1899,13 +1934,12 @@ abstract class PhabricatorApplicationTransactionEditor
|
|||
$has_support = true;
|
||||
}
|
||||
|
||||
// TODO: This should be some interface which specifies that the object
|
||||
// has project associations.
|
||||
if ($object instanceof ManiphestTask) {
|
||||
// TODO: The Maniphest legacy stuff should get cleaned up here.
|
||||
|
||||
// TODO: This is what normal objects would do, but Maniphest is still
|
||||
// behind the times.
|
||||
if (false) {
|
||||
if (($object instanceof ManiphestTask) ||
|
||||
($object instanceof PhabricatorProjectInterface)) {
|
||||
|
||||
if ($object instanceof PhabricatorProjectInterface) {
|
||||
$project_phids = PhabricatorEdgeQuery::loadDestinationPHIDs(
|
||||
$object->getPHID(),
|
||||
PhabricatorEdgeConfig::TYPE_OBJECT_HAS_PROJECT);
|
||||
|
|
|
@ -7,6 +7,7 @@ abstract class PhabricatorRemarkupRuleObject
|
|||
extends PhutilRemarkupRule {
|
||||
|
||||
const KEY_RULE_OBJECT = 'rule.object';
|
||||
const KEY_MENTIONED_OBJECTS = 'rule.object.mentioned';
|
||||
|
||||
abstract protected function getObjectNamePrefix();
|
||||
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);
|
||||
foreach ($metadata as $key => $spec) {
|
||||
$handle = $handles[$spec['id']];
|
||||
|
|
Loading…
Reference in a new issue