1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-22 14:52:41 +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:
epriestley 2014-06-03 17:19:40 -07:00
parent 0d87fef573
commit 4cda3e5811
6 changed files with 121 additions and 7 deletions

View file

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

View file

@ -32,6 +32,12 @@ final class PhabricatorApplicationProject extends PhabricatorApplication {
);
}
public function getEventListeners() {
return array(
new PhabricatorProjectUIEventListener(),
);
}
public function getRoutes() {
return array(
'/project/' => array(

View file

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

View file

@ -0,0 +1,5 @@
<?php
interface PhabricatorProjectInterface {
}

View file

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

View file

@ -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']];