1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2025-03-19 07:40:09 +01:00

Maniphest - use subscribers framework properly

Summary: Fixes T5604. This should fix some random bugs, lets us move forward more easily, and all that good stuff about killing code debt.

Test Plan:
- Conduit method maniphest.createtask
  - verified creating user subscribed
  - verified subscription transaction
- Conduit method maniphest.update
  - verified subscribers set as specified to ccPHIDs parameter
  - verified subscription transaction
- Herald
  - verified herald rule to add subscriber worked
  - verified no subscribers removed accidentally
- edit controller
  - test create and verify author gets added IFF they put themselves in subscribers control box
  - test update gets set to exactly what user enters
- lipsum generator'd tasks work
- bulk add subscribers works
- bulk remove subscriber works
- detail controller
  - added myself by leaving a comment
  - added another user via explicit action
  - added another user via implicit mention
- task merge via search attach controller
- mail reply handler
  - add subscriber via ./bin/mail receive-test
  - unsubscribe via ./bin/mail receive-test

Reviewers: epriestley

Reviewed By: epriestley

Subscribers: Korvin, epriestley

Maniphest Tasks: T5604

Differential Revision: https://secure.phabricator.com/D10965
This commit is contained in:
Bob Trahan 2014-12-10 16:27:30 -08:00
parent 3297bc2ed9
commit 7d96870570
27 changed files with 195 additions and 230 deletions

View file

@ -0,0 +1,9 @@
INSERT IGNORE INTO {$NAMESPACE}_maniphest.edge (src, type, dst)
SELECT taskPHID, 21, subscriberPHID
FROM {$NAMESPACE}_maniphest.maniphest_tasksubscriber
WHERE subscriberPHID != '';
INSERT IGNORE INTO {$NAMESPACE}_maniphest.edge (src, type, dst)
SELECT subscriberPHID, 22, taskPHID
FROM {$NAMESPACE}_maniphest.maniphest_tasksubscriber
WHERE subscriberPHID != '';

View file

@ -0,0 +1,2 @@
ALTER TABLE {$NAMESPACE}_maniphest.maniphest_task
DROP ccPHIDs;

View file

@ -1001,7 +1001,6 @@ phutil_register_library_map(array(
'ManiphestSearchIndexer' => 'applications/maniphest/search/ManiphestSearchIndexer.php', 'ManiphestSearchIndexer' => 'applications/maniphest/search/ManiphestSearchIndexer.php',
'ManiphestStatusConfigOptionType' => 'applications/maniphest/config/ManiphestStatusConfigOptionType.php', 'ManiphestStatusConfigOptionType' => 'applications/maniphest/config/ManiphestStatusConfigOptionType.php',
'ManiphestSubpriorityController' => 'applications/maniphest/controller/ManiphestSubpriorityController.php', 'ManiphestSubpriorityController' => 'applications/maniphest/controller/ManiphestSubpriorityController.php',
'ManiphestSubscribeController' => 'applications/maniphest/controller/ManiphestSubscribeController.php',
'ManiphestTask' => 'applications/maniphest/storage/ManiphestTask.php', 'ManiphestTask' => 'applications/maniphest/storage/ManiphestTask.php',
'ManiphestTaskDescriptionPreviewController' => 'applications/maniphest/controller/ManiphestTaskDescriptionPreviewController.php', 'ManiphestTaskDescriptionPreviewController' => 'applications/maniphest/controller/ManiphestTaskDescriptionPreviewController.php',
'ManiphestTaskDetailController' => 'applications/maniphest/controller/ManiphestTaskDetailController.php', 'ManiphestTaskDetailController' => 'applications/maniphest/controller/ManiphestTaskDetailController.php',
@ -4071,9 +4070,9 @@ phutil_register_library_map(array(
'ManiphestSearchIndexer' => 'PhabricatorSearchDocumentIndexer', 'ManiphestSearchIndexer' => 'PhabricatorSearchDocumentIndexer',
'ManiphestStatusConfigOptionType' => 'PhabricatorConfigJSONOptionType', 'ManiphestStatusConfigOptionType' => 'PhabricatorConfigJSONOptionType',
'ManiphestSubpriorityController' => 'ManiphestController', 'ManiphestSubpriorityController' => 'ManiphestController',
'ManiphestSubscribeController' => 'ManiphestController',
'ManiphestTask' => array( 'ManiphestTask' => array(
'ManiphestDAO', 'ManiphestDAO',
'PhabricatorSubscribableInterface',
'PhabricatorMarkupInterface', 'PhabricatorMarkupInterface',
'PhabricatorPolicyInterface', 'PhabricatorPolicyInterface',
'PhabricatorTokenReceiverInterface', 'PhabricatorTokenReceiverInterface',

View file

@ -139,7 +139,7 @@ final class HeraldManiphestTaskAdapter extends HeraldAdapter {
case self::FIELD_ASSIGNEE: case self::FIELD_ASSIGNEE:
return $this->getTask()->getOwnerPHID(); return $this->getTask()->getOwnerPHID();
case self::FIELD_CC: case self::FIELD_CC:
return $this->getTask()->getCCPHIDs(); return $this->getTask()->getSubscriberPHIDs();
case self::FIELD_PROJECTS: case self::FIELD_PROJECTS:
return PhabricatorEdgeQuery::loadDestinationPHIDs( return PhabricatorEdgeQuery::loadDestinationPHIDs(
$this->getTask()->getPHID(), $this->getTask()->getPHID(),

View file

@ -66,8 +66,6 @@ final class PhabricatorManiphestApplication extends PhabricatorApplication {
), ),
'export/(?P<key>[^/]+)/' => 'ManiphestExportController', 'export/(?P<key>[^/]+)/' => 'ManiphestExportController',
'subpriority/' => 'ManiphestSubpriorityController', 'subpriority/' => 'ManiphestSubpriorityController',
'subscribe/(?P<action>add|rem)/(?P<id>[1-9]\d*)/'
=> 'ManiphestSubscribeController',
), ),
); );
} }

View file

@ -62,6 +62,8 @@ abstract class ManiphestConduitAPIMethod extends ConduitAPIMethod {
$task->setDescription((string)$request->getValue('description')); $task->setDescription((string)$request->getValue('description'));
$changes[ManiphestTransaction::TYPE_STATUS] = $changes[ManiphestTransaction::TYPE_STATUS] =
ManiphestTaskStatus::getDefaultStatus(); ManiphestTaskStatus::getDefaultStatus();
$changes[PhabricatorTransactions::TYPE_SUBSCRIBERS] =
array('+' => array($request->getUser()->getPHID()));
} else { } else {
$comments = $request->getValue('comments'); $comments = $request->getValue('comments');
@ -111,7 +113,8 @@ abstract class ManiphestConduitAPIMethod extends ConduitAPIMethod {
$ccs = $request->getValue('ccPHIDs'); $ccs = $request->getValue('ccPHIDs');
if ($ccs !== null) { if ($ccs !== null) {
$changes[ManiphestTransaction::TYPE_CCS] = $ccs; $changes[PhabricatorTransactions::TYPE_SUBSCRIBERS] =
array('=' => array_fuse($ccs));
} }
$transactions = array(); $transactions = array();
@ -228,6 +231,13 @@ abstract class ManiphestConduitAPIMethod extends ConduitAPIMethod {
$event->setUser($request->getUser()); $event->setUser($request->getUser());
$event->setConduitRequest($request); $event->setConduitRequest($request);
PhutilEventEngine::dispatchEvent($event); PhutilEventEngine::dispatchEvent($event);
// reload the task now that we've done all the fun stuff
return id(new ManiphestTaskQuery())
->setViewer($request->getUser())
->withPHIDs(array($task->getPHID()))
->needSubscriberPHIDs(true)
->executeOne();
} }
protected function buildTaskInfoDictionaries(array $tasks) { protected function buildTaskInfoDictionaries(array $tasks) {
@ -265,7 +275,7 @@ abstract class ManiphestConduitAPIMethod extends ConduitAPIMethod {
'phid' => $task->getPHID(), 'phid' => $task->getPHID(),
'authorPHID' => $task->getAuthorPHID(), 'authorPHID' => $task->getAuthorPHID(),
'ownerPHID' => $task->getOwnerPHID(), 'ownerPHID' => $task->getOwnerPHID(),
'ccPHIDs' => $task->getCCPHIDs(), 'ccPHIDs' => $task->getSubscriberPHIDs(),
'status' => $task->getStatus(), 'status' => $task->getStatus(),
'statusName' => ManiphestTaskStatus::getTaskStatusName( 'statusName' => ManiphestTaskStatus::getTaskStatusName(
$task->getStatus()), $task->getStatus()),

View file

@ -28,7 +28,7 @@ final class ManiphestCreateTaskConduitAPIMethod
protected function execute(ConduitAPIRequest $request) { protected function execute(ConduitAPIRequest $request) {
$task = ManiphestTask::initializeNewTask($request->getUser()); $task = ManiphestTask::initializeNewTask($request->getUser());
$this->applyRequest($task, $request, $is_new = true); $task = $this->applyRequest($task, $request, $is_new = true);
return $this->buildTaskInfoDictionary($task); return $this->buildTaskInfoDictionary($task);
} }

View file

@ -32,6 +32,7 @@ final class ManiphestInfoConduitAPIMethod extends ManiphestConduitAPIMethod {
$task = id(new ManiphestTaskQuery()) $task = id(new ManiphestTaskQuery())
->setViewer($request->getUser()) ->setViewer($request->getUser())
->withIDs(array($task_id)) ->withIDs(array($task_id))
->needSubscriberPHIDs(true)
->executeOne(); ->executeOne();
if (!$task) { if (!$task) {
throw new ConduitException('ERR_BAD_TASK'); throw new ConduitException('ERR_BAD_TASK');

View file

@ -64,6 +64,7 @@ class ManiphestQueryConduitAPIMethod extends ManiphestConduitAPIMethod {
$query = new ManiphestTaskQuery(); $query = new ManiphestTaskQuery();
$query->setViewer($request->getUser()); $query->setViewer($request->getUser());
$query->needSubscriberPHIDs(true);
$task_ids = $request->getValue('ids'); $task_ids = $request->getValue('ids');
if ($task_ids) { if ($task_ids) {

View file

@ -38,11 +38,13 @@ final class ManiphestUpdateConduitAPIMethod extends ManiphestConduitAPIMethod {
$task = id(new ManiphestTaskQuery()) $task = id(new ManiphestTaskQuery())
->setViewer($request->getUser()) ->setViewer($request->getUser())
->withIDs(array($id)) ->withIDs(array($id))
->needSubscriberPHIDs(true)
->executeOne(); ->executeOne();
} else { } else {
$task = id(new ManiphestTaskQuery()) $task = id(new ManiphestTaskQuery())
->setViewer($request->getUser()) ->setViewer($request->getUser())
->withPHIDs(array($phid)) ->withPHIDs(array($phid))
->needSubscriberPHIDs(true)
->executeOne(); ->executeOne();
} }
@ -58,7 +60,7 @@ final class ManiphestUpdateConduitAPIMethod extends ManiphestConduitAPIMethod {
throw new ConduitException('ERR-BAD-TASK'); throw new ConduitException('ERR-BAD-TASK');
} }
$this->applyRequest($task, $request, $is_new = false); $task = $this->applyRequest($task, $request, $is_new = false);
return $this->buildTaskInfoDictionary($task); return $this->buildTaskInfoDictionary($task);
} }

View file

@ -18,6 +18,7 @@ final class ManiphestBatchEditController extends ManiphestController {
PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_VIEW,
PhabricatorPolicyCapability::CAN_EDIT, PhabricatorPolicyCapability::CAN_EDIT,
)) ))
->needSubscriberPHIDs(true)
->execute(); ->execute();
$actions = $request->getStr('actions'); $actions = $request->getStr('actions');
@ -171,8 +172,8 @@ final class ManiphestBatchEditController extends ManiphestController {
'priority' => ManiphestTransaction::TYPE_PRIORITY, 'priority' => ManiphestTransaction::TYPE_PRIORITY,
'add_project' => ManiphestTransaction::TYPE_PROJECTS, 'add_project' => ManiphestTransaction::TYPE_PROJECTS,
'remove_project' => ManiphestTransaction::TYPE_PROJECTS, 'remove_project' => ManiphestTransaction::TYPE_PROJECTS,
'add_ccs' => ManiphestTransaction::TYPE_CCS, 'add_ccs' => PhabricatorTransactions::TYPE_SUBSCRIBERS,
'remove_ccs' => ManiphestTransaction::TYPE_CCS, 'remove_ccs' => PhabricatorTransactions::TYPE_SUBSCRIBERS,
); );
$edge_edit_types = array( $edge_edit_types = array(
@ -215,8 +216,8 @@ final class ManiphestBatchEditController extends ManiphestController {
case ManiphestTransaction::TYPE_PROJECTS: case ManiphestTransaction::TYPE_PROJECTS:
$current = $task->getProjectPHIDs(); $current = $task->getProjectPHIDs();
break; break;
case ManiphestTransaction::TYPE_CCS: case PhabricatorTransactions::TYPE_SUBSCRIBERS:
$current = $task->getCCPHIDs(); $current = $task->getSubscriberPHIDs();
break; break;
} }
} }
@ -246,7 +247,7 @@ final class ManiphestBatchEditController extends ManiphestController {
continue 2; continue 2;
} }
break; break;
case ManiphestTransaction::TYPE_CCS: case PhabricatorTransactions::TYPE_SUBSCRIBERS:
if (empty($value)) { if (empty($value)) {
continue 2; continue 2;
} }
@ -274,12 +275,7 @@ final class ManiphestBatchEditController extends ManiphestController {
} }
break; break;
case ManiphestTransaction::TYPE_PROJECTS: case ManiphestTransaction::TYPE_PROJECTS:
case ManiphestTransaction::TYPE_CCS: $is_remove = $action['action'] == 'remove_project';
$remove_actions = array(
'remove_project' => true,
'remove_ccs' => true,
);
$is_remove = isset($remove_actions[$action['action']]);
$current = array_fill_keys($current, true); $current = array_fill_keys($current, true);
$value = array_fill_keys($value, true); $value = array_fill_keys($value, true);
@ -308,6 +304,39 @@ final class ManiphestBatchEditController extends ManiphestController {
} }
$value = array_keys($new); $value = array_keys($new);
break;
case PhabricatorTransactions::TYPE_SUBSCRIBERS:
$is_remove = $action['action'] == 'remove_ccs';
$current = array_fill_keys($current, true);
$new = array();
$did_something = false;
if ($is_remove) {
foreach ($value as $phid) {
if (isset($current[$phid])) {
$new[$phid] = true;
$did_something = true;
}
}
if ($new) {
$value = array('-' => array_keys($new));
}
} else {
$new = array();
foreach ($value as $phid) {
$new[$phid] = true;
$did_something = true;
}
if ($new) {
$value = array('+' => array_keys($new));
}
}
if (!$did_something) {
continue 2;
}
break; break;
} }

View file

@ -1,51 +0,0 @@
<?php
final class ManiphestSubscribeController extends ManiphestController {
private $id;
private $action;
public function willProcessRequest(array $data) {
$this->id = $data['id'];
$this->action = $data['action'];
}
public function processRequest() {
$request = $this->getRequest();
$user = $request->getUser();
$task = id(new ManiphestTaskQuery())
->setViewer($user)
->withIDs(array($this->id))
->executeOne();
if (!$task) {
return new Aphront404Response();
}
$ccs = $task->getCCPHIDs();
switch ($this->action) {
case 'add':
$ccs[] = $user->getPHID();
break;
case 'rem':
$ccs = array_diff($ccs, array($user->getPHID()));
break;
default:
return new Aphront400Response();
}
$xaction = id(new ManiphestTransaction())
->setTransactionType(ManiphestTransaction::TYPE_CCS)
->setNewValue($ccs);
$editor = id(new ManiphestTransactionEditor())
->setActor($user)
->setContentSourceFromRequest($request)
->setContinueOnNoEffect(true)
->setContinueOnMissingFields(true)
->applyTransactions($task, array($xaction));
return id(new AphrontRedirectResponse())->setURI('/T'.$task->getID());
}
}

View file

@ -23,6 +23,7 @@ final class ManiphestTaskDetailController extends ManiphestController {
$task = id(new ManiphestTaskQuery()) $task = id(new ManiphestTaskQuery())
->setViewer($user) ->setViewer($user)
->withIDs(array($this->id)) ->withIDs(array($this->id))
->needSubscriberPHIDs(true)
->executeOne(); ->executeOne();
if (!$task) { if (!$task) {
return new Aphront404Response(); return new Aphront404Response();
@ -65,12 +66,6 @@ final class ManiphestTaskDetailController extends ManiphestController {
$edges = idx($query->execute(), $phid); $edges = idx($query->execute(), $phid);
$phids = array_fill_keys($query->getDestinationPHIDs(), true); $phids = array_fill_keys($query->getDestinationPHIDs(), true);
foreach ($task->getCCPHIDs() as $phid) {
$phids[$phid] = true;
}
foreach ($task->getProjectPHIDs() as $phid) {
$phids[$phid] = true;
}
if ($task->getOwnerPHID()) { if ($task->getOwnerPHID()) {
$phids[$task->getOwnerPHID()] = true; $phids[$task->getOwnerPHID()] = true;
} }
@ -142,7 +137,7 @@ final class ManiphestTaskDetailController extends ManiphestController {
PhabricatorTransactions::TYPE_COMMENT => pht('Comment'), PhabricatorTransactions::TYPE_COMMENT => pht('Comment'),
ManiphestTransaction::TYPE_STATUS => pht('Change Status'), ManiphestTransaction::TYPE_STATUS => pht('Change Status'),
ManiphestTransaction::TYPE_OWNER => pht('Reassign / Claim'), ManiphestTransaction::TYPE_OWNER => pht('Reassign / Claim'),
ManiphestTransaction::TYPE_CCS => pht('Add CCs'), PhabricatorTransactions::TYPE_SUBSCRIBERS => pht('Add CCs'),
ManiphestTransaction::TYPE_PRIORITY => pht('Change Priority'), ManiphestTransaction::TYPE_PRIORITY => pht('Change Priority'),
ManiphestTransaction::TYPE_PROJECTS => pht('Associate Projects'), ManiphestTransaction::TYPE_PROJECTS => pht('Associate Projects'),
); );
@ -267,7 +262,7 @@ final class ManiphestTaskDetailController extends ManiphestController {
$control_map = array( $control_map = array(
ManiphestTransaction::TYPE_STATUS => 'resolution', ManiphestTransaction::TYPE_STATUS => 'resolution',
ManiphestTransaction::TYPE_OWNER => 'assign_to', ManiphestTransaction::TYPE_OWNER => 'assign_to',
ManiphestTransaction::TYPE_CCS => 'ccs', PhabricatorTransactions::TYPE_SUBSCRIBERS => 'ccs',
ManiphestTransaction::TYPE_PRIORITY => 'priority', ManiphestTransaction::TYPE_PRIORITY => 'priority',
ManiphestTransaction::TYPE_PROJECTS => 'projects', ManiphestTransaction::TYPE_PROJECTS => 'projects',
); );
@ -289,7 +284,7 @@ final class ManiphestTaskDetailController extends ManiphestController {
'limit' => 1, 'limit' => 1,
'placeholder' => $users_source->getPlaceholderText(), 'placeholder' => $users_source->getPlaceholderText(),
), ),
ManiphestTransaction::TYPE_CCS => array( PhabricatorTransactions::TYPE_SUBSCRIBERS => array(
'id' => 'cc-tokenizer', 'id' => 'cc-tokenizer',
'src' => $mailable_source->getDatasourceURI(), 'src' => $mailable_source->getDatasourceURI(),
'placeholder' => $mailable_source->getPlaceholderText(), 'placeholder' => $mailable_source->getPlaceholderText(),
@ -397,7 +392,6 @@ final class ManiphestTaskDetailController extends ManiphestController {
private function buildActionView(ManiphestTask $task) { private function buildActionView(ManiphestTask $task) {
$viewer = $this->getRequest()->getUser(); $viewer = $this->getRequest()->getUser();
$viewer_phid = $viewer->getPHID(); $viewer_phid = $viewer->getPHID();
$viewer_is_cc = in_array($viewer_phid, $task->getCCPHIDs());
$id = $task->getID(); $id = $task->getID();
$phid = $task->getPHID(); $phid = $task->getPHID();
@ -420,26 +414,6 @@ final class ManiphestTaskDetailController extends ManiphestController {
->setDisabled(!$can_edit) ->setDisabled(!$can_edit)
->setWorkflow(!$can_edit)); ->setWorkflow(!$can_edit));
if ($task->getOwnerPHID() === $viewer_phid) {
$view->addAction(
id(new PhabricatorActionView())
->setName(pht('Automatically Subscribed'))
->setDisabled(true)
->setIcon('fa-check-circle'));
} else {
$action = $viewer_is_cc ? 'rem' : 'add';
$name = $viewer_is_cc ? pht('Unsubscribe') : pht('Subscribe');
$icon = $viewer_is_cc ? 'fa-minus-circle' : 'fa-plus-circle';
$view->addAction(
id(new PhabricatorActionView())
->setName($name)
->setHref("/maniphest/subscribe/{$action}/{$id}/")
->setRenderAsForm(true)
->setUser($viewer)
->setIcon($icon));
}
$view->addAction( $view->addAction(
id(new PhabricatorActionView()) id(new PhabricatorActionView())
->setName(pht('Merge Duplicates In')) ->setName(pht('Merge Duplicates In'))
@ -490,14 +464,6 @@ final class ManiphestTaskDetailController extends ManiphestController {
pht('Priority'), pht('Priority'),
ManiphestTaskPriority::getTaskPriorityName($task->getPriority())); ManiphestTaskPriority::getTaskPriorityName($task->getPriority()));
$handles = $this->getLoadedHandles();
$cc_handles = array_select_keys($handles, $task->getCCPHIDs());
$subscriber_html = id(new SubscriptionListStringBuilder())
->setObjectPHID($task->getPHID())
->setHandles($cc_handles)
->buildPropertyString();
$view->addProperty(pht('Subscribers'), $subscriber_html);
$view->addProperty( $view->addProperty(
pht('Author'), pht('Author'),
$this->getHandle($task->getAuthorPHID())->renderLink()); $this->getHandle($task->getAuthorPHID())->renderLink());

View file

@ -38,6 +38,7 @@ final class ManiphestTaskEditController extends ManiphestController {
PhabricatorPolicyCapability::CAN_EDIT, PhabricatorPolicyCapability::CAN_EDIT,
)) ))
->withIDs(array($this->id)) ->withIDs(array($this->id))
->needSubscriberPHIDs(true)
->executeOne(); ->executeOne();
if (!$task) { if (!$task) {
return new Aphront404Response(); return new Aphront404Response();
@ -215,7 +216,7 @@ final class ManiphestTaskEditController extends ManiphestController {
$task->setDescription($new_desc); $task->setDescription($new_desc);
$task->setPriority($request->getInt('priority')); $task->setPriority($request->getInt('priority'));
$task->setOwnerPHID($owner_phid); $task->setOwnerPHID($owner_phid);
$task->setCCPHIDs($request->getArr('cc')); $task->attachSubscriberPHIDs($request->getArr('cc'));
$task->attachProjectPHIDs($request->getArr('projects')); $task->attachProjectPHIDs($request->getArr('projects'));
} else { } else {
@ -227,7 +228,8 @@ final class ManiphestTaskEditController extends ManiphestController {
$changes[ManiphestTransaction::TYPE_OWNER] = $owner_phid; $changes[ManiphestTransaction::TYPE_OWNER] = $owner_phid;
} }
$changes[ManiphestTransaction::TYPE_CCS] = $request->getArr('cc'); $changes[PhabricatorTransactions::TYPE_SUBSCRIBERS] =
array('=' => $request->getArr('cc'));
if ($can_edit_projects) { if ($can_edit_projects) {
$projects = $request->getArr('projects'); $projects = $request->getArr('projects');
@ -436,19 +438,20 @@ final class ManiphestTaskEditController extends ManiphestController {
} }
} else { } else {
if (!$task->getID()) { if (!$task->getID()) {
$task->setCCPHIDs(array( $task->attachSubscriberPHIDs(array(
$user->getPHID(), $user->getPHID(),
)); ));
if ($template_id) { if ($template_id) {
$template_task = id(new ManiphestTaskQuery()) $template_task = id(new ManiphestTaskQuery())
->setViewer($user) ->setViewer($user)
->withIDs(array($template_id)) ->withIDs(array($template_id))
->needSubscriberPHIDs(true)
->executeOne(); ->executeOne();
if ($template_task) { if ($template_task) {
$cc_phids = array_unique(array_merge( $cc_phids = array_unique(array_merge(
$template_task->getCCPHIDs(), $template_task->getSubscriberPHIDs(),
array($user->getPHID()))); array($user->getPHID())));
$task->setCCPHIDs($cc_phids); $task->attachSubscriberPHIDs($cc_phids);
$task->attachProjectPHIDs($template_task->getProjectPHIDs()); $task->attachProjectPHIDs($template_task->getProjectPHIDs());
$task->setOwnerPHID($template_task->getOwnerPHID()); $task->setOwnerPHID($template_task->getOwnerPHID());
$task->setPriority($template_task->getPriority()); $task->setPriority($template_task->getPriority());
@ -486,7 +489,7 @@ final class ManiphestTaskEditController extends ManiphestController {
$phids = array_merge( $phids = array_merge(
array($task->getOwnerPHID()), array($task->getOwnerPHID()),
$task->getCCPHIDs(), $task->getSubscriberPHIDs(),
$task->getProjectPHIDs()); $task->getProjectPHIDs());
if ($parent_task) { if ($parent_task) {
@ -512,8 +515,8 @@ final class ManiphestTaskEditController extends ManiphestController {
$assigned_value = array(); $assigned_value = array();
} }
if ($task->getCCPHIDs()) { if ($task->getSubscriberPHIDs()) {
$cc_value = array_select_keys($handles, $task->getCCPHIDs()); $cc_value = array_select_keys($handles, $task->getSubscriberPHIDs());
} else { } else {
$cc_value = array(); $cc_value = array();
} }

View file

@ -58,22 +58,19 @@ final class ManiphestTransactionPreviewController extends ManiphestController {
} }
$transaction->setNewValue($value); $transaction->setNewValue($value);
break; break;
case ManiphestTransaction::TYPE_CCS: case PhabricatorTransactions::TYPE_SUBSCRIBERS:
if ($value) { if ($value) {
$value = json_decode($value); $value = json_decode($value);
} }
if (!$value) { if (!$value) {
$value = array(); $value = array();
} }
$phids = $value; $phids = array();
foreach ($value as $cc_phid) {
foreach ($task->getCCPHIDs() as $cc_phid) {
$phids[] = $cc_phid; $phids[] = $cc_phid;
$value[] = $cc_phid;
} }
$transaction->setOldValue(array());
$transaction->setOldValue($task->getCCPHIDs()); $transaction->setNewValue($phids);
$transaction->setNewValue($value);
break; break;
case ManiphestTransaction::TYPE_PROJECTS: case ManiphestTransaction::TYPE_PROJECTS:
if ($value) { if ($value) {

View file

@ -9,6 +9,7 @@ final class ManiphestTransactionSaveController extends ManiphestController {
$task = id(new ManiphestTaskQuery()) $task = id(new ManiphestTaskQuery())
->setViewer($user) ->setViewer($user)
->withIDs(array($request->getStr('taskID'))) ->withIDs(array($request->getStr('taskID')))
->needSubscriberPHIDs(true)
->executeOne(); ->executeOne();
if (!$task) { if (!$task) {
return new Aphront404Response(); return new Aphront404Response();
@ -33,7 +34,7 @@ final class ManiphestTransactionSaveController extends ManiphestController {
$cc_transaction = new ManiphestTransaction(); $cc_transaction = new ManiphestTransaction();
$cc_transaction $cc_transaction
->setTransactionType(ManiphestTransaction::TYPE_CCS); ->setTransactionType(PhabricatorTransactions::TYPE_SUBSCRIBERS);
$transaction = new ManiphestTransaction(); $transaction = new ManiphestTransaction();
$transaction $transaction
@ -64,7 +65,7 @@ final class ManiphestTransactionSaveController extends ManiphestController {
'+' => array_fuse($projects), '+' => array_fuse($projects),
)); ));
break; break;
case ManiphestTransaction::TYPE_CCS: case PhabricatorTransactions::TYPE_SUBSCRIBERS:
// Accumulate the new explicit CCs into the array that we'll add in // Accumulate the new explicit CCs into the array that we'll add in
// the CC transaction later. // the CC transaction later.
$added_ccs = array_merge($added_ccs, $request->getArr('ccs')); $added_ccs = array_merge($added_ccs, $request->getArr('ccs'));
@ -135,19 +136,21 @@ final class ManiphestTransactionSaveController extends ManiphestController {
if (!$user_owns_task) { if (!$user_owns_task) {
// If we aren't making the user the new task owner and they aren't the // If we aren't making the user the new task owner and they aren't the
// existing task owner, add them to CC unless they're aleady CC'd. // existing task owner, add them to CC unless they're aleady CC'd.
if (!in_array($user->getPHID(), $task->getCCPHIDs())) { if (!in_array($user->getPHID(), $task->getSubscriberPHIDs())) {
$added_ccs[] = $user->getPHID(); $added_ccs[] = $user->getPHID();
} }
} }
// Evade no-effect detection in the new editor stuff until we can switch // Evade no-effect detection in the new editor stuff until we can switch
// to subscriptions. // to subscriptions.
$added_ccs = array_filter(array_diff($added_ccs, $task->getCCPHIDs())); $added_ccs = array_filter(array_diff(
$added_ccs,
$task->getSubscriberPHIDs()));
if ($added_ccs) { if ($added_ccs) {
// We've added CCs, so include a CC transaction. // We've added CCs, so include a CC transaction.
$all_ccs = array_merge($task->getCCPHIDs(), $added_ccs); $all_ccs = array_merge($task->getSubscriberPHIDs(), $added_ccs);
$cc_transaction->setNewValue($all_ccs); $cc_transaction->setNewValue(array('=' => $all_ccs));
$transactions[] = $cc_transaction; $transactions[] = $cc_transaction;
} }

View file

@ -23,7 +23,6 @@ final class ManiphestTransactionEditor
$types[] = ManiphestTransaction::TYPE_TITLE; $types[] = ManiphestTransaction::TYPE_TITLE;
$types[] = ManiphestTransaction::TYPE_DESCRIPTION; $types[] = ManiphestTransaction::TYPE_DESCRIPTION;
$types[] = ManiphestTransaction::TYPE_OWNER; $types[] = ManiphestTransaction::TYPE_OWNER;
$types[] = ManiphestTransaction::TYPE_CCS;
$types[] = ManiphestTransaction::TYPE_SUBPRIORITY; $types[] = ManiphestTransaction::TYPE_SUBPRIORITY;
$types[] = ManiphestTransaction::TYPE_PROJECT_COLUMN; $types[] = ManiphestTransaction::TYPE_PROJECT_COLUMN;
$types[] = ManiphestTransaction::TYPE_MERGED_INTO; $types[] = ManiphestTransaction::TYPE_MERGED_INTO;
@ -62,8 +61,6 @@ final class ManiphestTransactionEditor
return $object->getDescription(); return $object->getDescription();
case ManiphestTransaction::TYPE_OWNER: case ManiphestTransaction::TYPE_OWNER:
return nonempty($object->getOwnerPHID(), null); return nonempty($object->getOwnerPHID(), null);
case ManiphestTransaction::TYPE_CCS:
return array_values(array_unique($object->getCCPHIDs()));
case ManiphestTransaction::TYPE_PROJECT_COLUMN: case ManiphestTransaction::TYPE_PROJECT_COLUMN:
// These are pre-populated. // These are pre-populated.
return $xaction->getOldValue(); return $xaction->getOldValue();
@ -82,8 +79,6 @@ final class ManiphestTransactionEditor
switch ($xaction->getTransactionType()) { switch ($xaction->getTransactionType()) {
case ManiphestTransaction::TYPE_PRIORITY: case ManiphestTransaction::TYPE_PRIORITY:
return (int)$xaction->getNewValue(); return (int)$xaction->getNewValue();
case ManiphestTransaction::TYPE_CCS:
return array_values(array_unique($xaction->getNewValue()));
case ManiphestTransaction::TYPE_OWNER: case ManiphestTransaction::TYPE_OWNER:
return nonempty($xaction->getNewValue(), null); return nonempty($xaction->getNewValue(), null);
case ManiphestTransaction::TYPE_STATUS: case ManiphestTransaction::TYPE_STATUS:
@ -106,10 +101,6 @@ final class ManiphestTransactionEditor
$new = $xaction->getNewValue(); $new = $xaction->getNewValue();
switch ($xaction->getTransactionType()) { switch ($xaction->getTransactionType()) {
case ManiphestTransaction::TYPE_CCS:
sort($old);
sort($new);
return ($old !== $new);
case ManiphestTransaction::TYPE_PROJECT_COLUMN: case ManiphestTransaction::TYPE_PROJECT_COLUMN:
$new_column_phids = $new['columnPHIDs']; $new_column_phids = $new['columnPHIDs'];
$old_column_phids = $old['columnPHIDs']; $old_column_phids = $old['columnPHIDs'];
@ -155,8 +146,6 @@ final class ManiphestTransactionEditor
} }
return $object->setOwnerPHID($phid); return $object->setOwnerPHID($phid);
case ManiphestTransaction::TYPE_CCS:
return $object->setCCPHIDs($xaction->getNewValue());
case ManiphestTransaction::TYPE_SUBPRIORITY: case ManiphestTransaction::TYPE_SUBPRIORITY:
$data = $xaction->getNewValue(); $data = $xaction->getNewValue();
$new_sub = $this->getNextSubpriority( $new_sub = $this->getNextSubpriority(
@ -433,10 +422,6 @@ final class ManiphestTransactionEditor
protected function getMailCC(PhabricatorLiskDAO $object) { protected function getMailCC(PhabricatorLiskDAO $object) {
$phids = array(); $phids = array();
foreach ($object->getCCPHIDs() as $phid) {
$phids[] = $phid;
}
foreach (parent::getMailCC($object) as $phid) { foreach (parent::getMailCC($object) as $phid) {
$phids[] = $phid; $phids[] = $phid;
} }
@ -561,22 +546,16 @@ final class ManiphestTransactionEditor
HeraldAdapter $adapter, HeraldAdapter $adapter,
HeraldTranscript $transcript) { HeraldTranscript $transcript) {
// TODO: Convert these to transactions. The way Maniphest deals with these $this->heraldEmailPHIDs = $adapter->getEmailPHIDs();
// transactions is currently unconventional and messy. $xactions = array();
$save_again = false;
$cc_phids = $adapter->getCcPHIDs(); $cc_phids = $adapter->getCcPHIDs();
if ($cc_phids) { if ($cc_phids) {
$existing_cc = $object->getCCPHIDs(); $xactions[] = id(new ManiphestTransaction())
$new_cc = array_unique(array_merge($cc_phids, $existing_cc)); ->setTransactionType(PhabricatorTransactions::TYPE_SUBSCRIBERS)
$object->setCCPHIDs($new_cc); ->setNewValue(array('+' => $cc_phids));
$object->save();
} }
$this->heraldEmailPHIDs = $adapter->getEmailPHIDs();
$xactions = array();
$assign_phid = $adapter->getAssignPHID(); $assign_phid = $adapter->getAssignPHID();
if ($assign_phid) { if ($assign_phid) {
$xactions[] = id(new ManiphestTransaction()) $xactions[] = id(new ManiphestTransaction())

View file

@ -28,8 +28,8 @@ final class PhabricatorManiphestTaskTestDataGenerator
$this->generateTaskStatus(); $this->generateTaskStatus();
$changes[ManiphestTransaction::TYPE_PRIORITY] = $changes[ManiphestTransaction::TYPE_PRIORITY] =
$this->generateTaskPriority(); $this->generateTaskPriority();
$changes[ManiphestTransaction::TYPE_CCS] = $changes[PhabricatorTransactions::TYPE_SUBSCRIBERS] =
$this->getCCPHIDs(); array('=' => $this->getCCPHIDs());
$transactions = array(); $transactions = array();
foreach ($changes as $type => $value) { foreach ($changes as $type => $value) {
$transaction = clone $template; $transaction = clone $template;

View file

@ -106,14 +106,14 @@ final class ManiphestReplyHandler extends PhabricatorMailReplyHandler {
break; break;
case 'unsubscribe': case 'unsubscribe':
$is_unsub = true; $is_unsub = true;
$ttype = ManiphestTransaction::TYPE_CCS; $ttype = PhabricatorTransactions::TYPE_SUBSCRIBERS;
$ccs = $task->getCCPHIDs(); $ccs = $task->getSubscriberPHIDs();
foreach ($ccs as $k => $phid) { foreach ($ccs as $k => $phid) {
if ($phid == $user->getPHID()) { if ($phid == $user->getPHID()) {
unset($ccs[$k]); unset($ccs[$k]);
} }
} }
$new_value = array_values($ccs); $new_value = array('=' => array_values($ccs));
break; break;
} }
@ -135,7 +135,7 @@ final class ManiphestReplyHandler extends PhabricatorMailReplyHandler {
} }
$ccs = $mail->loadCCPHIDs(); $ccs = $mail->loadCCPHIDs();
$old_ccs = $task->getCCPHIDs(); $old_ccs = $task->getSubscriberPHIDs();
$new_ccs = array_merge($old_ccs, $ccs); $new_ccs = array_merge($old_ccs, $ccs);
if (!$is_unsub) { if (!$is_unsub) {
$new_ccs[] = $user->getPHID(); $new_ccs[] = $user->getPHID();
@ -144,8 +144,9 @@ final class ManiphestReplyHandler extends PhabricatorMailReplyHandler {
if (array_diff($new_ccs, $old_ccs)) { if (array_diff($new_ccs, $old_ccs)) {
$cc_xaction = clone $template; $cc_xaction = clone $template;
$cc_xaction->setTransactionType(ManiphestTransaction::TYPE_CCS); $cc_xaction->setTransactionType(
$cc_xaction->setNewValue($new_ccs); PhabricatorTransactions::TYPE_SUBSCRIBERS);
$cc_xaction->setNewValue(array('=' => $new_ccs));
$xactions[] = $cc_xaction; $xactions[] = $cc_xaction;
} }

View file

@ -17,6 +17,7 @@ final class ManiphestTaskMailReceiver extends PhabricatorObjectMailReceiver {
$results = id(new ManiphestTaskQuery()) $results = id(new ManiphestTaskQuery())
->setViewer($viewer) ->setViewer($viewer)
->withIDs(array($id)) ->withIDs(array($id))
->needSubscriberPHIDs(true)
->execute(); ->execute();
return head($results); return head($results);

View file

@ -50,6 +50,8 @@ final class ManiphestTaskQuery extends PhabricatorCursorPagedPolicyAwareQuery {
const ORDER_MODIFIED = 'order-modified'; const ORDER_MODIFIED = 'order-modified';
const ORDER_TITLE = 'order-title'; const ORDER_TITLE = 'order-title';
private $needSubscriberPHIDs;
const DEFAULT_PAGE_SIZE = 1000; const DEFAULT_PAGE_SIZE = 1000;
public function withAuthors(array $authors) { public function withAuthors(array $authors) {
@ -178,6 +180,11 @@ final class ManiphestTaskQuery extends PhabricatorCursorPagedPolicyAwareQuery {
return $this; return $this;
} }
public function needSubscriberPHIDs($bool) {
$this->needSubscriberPHIDs = $bool;
return $this;
}
public function loadPage() { public function loadPage() {
// TODO: (T603) It is possible for a user to find the PHID of a project // TODO: (T603) It is possible for a user to find the PHID of a project
// they can't see, then query for tasks in that project and deduce the // they can't see, then query for tasks in that project and deduce the
@ -196,7 +203,6 @@ final class ManiphestTaskQuery extends PhabricatorCursorPagedPolicyAwareQuery {
$where[] = $this->buildPrioritiesWhereClause($conn); $where[] = $this->buildPrioritiesWhereClause($conn);
$where[] = $this->buildAuthorWhereClause($conn); $where[] = $this->buildAuthorWhereClause($conn);
$where[] = $this->buildOwnerWhereClause($conn); $where[] = $this->buildOwnerWhereClause($conn);
$where[] = $this->buildSubscriberWhereClause($conn);
$where[] = $this->buildProjectWhereClause($conn); $where[] = $this->buildProjectWhereClause($conn);
$where[] = $this->buildAnyProjectWhereClause($conn); $where[] = $this->buildAnyProjectWhereClause($conn);
$where[] = $this->buildAnyUserProjectWhereClause($conn); $where[] = $this->buildAnyUserProjectWhereClause($conn);
@ -332,12 +338,14 @@ final class ManiphestTaskQuery extends PhabricatorCursorPagedPolicyAwareQuery {
} }
protected function didFilterPage(array $tasks) { protected function didFilterPage(array $tasks) {
$phids = mpull($tasks, 'getPHID');
// TODO: Eventually, we should make this optional and introduce a // TODO: Eventually, we should make this optional and introduce a
// needProjectPHIDs() method, but for now there's a lot of code which // needProjectPHIDs() method, but for now there's a lot of code which
// assumes the data is always populated. // assumes the data is always populated.
$edge_query = id(new PhabricatorEdgeQuery()) $edge_query = id(new PhabricatorEdgeQuery())
->withSourcePHIDs(mpull($tasks, 'getPHID')) ->withSourcePHIDs($phids)
->withEdgeTypes( ->withEdgeTypes(
array( array(
PhabricatorProjectObjectHasProjectEdgeType::EDGECONST, PhabricatorProjectObjectHasProjectEdgeType::EDGECONST,
@ -345,8 +353,19 @@ final class ManiphestTaskQuery extends PhabricatorCursorPagedPolicyAwareQuery {
$edge_query->execute(); $edge_query->execute();
foreach ($tasks as $task) { foreach ($tasks as $task) {
$phids = $edge_query->getDestinationPHIDs(array($task->getPHID())); $project_phids = $edge_query->getDestinationPHIDs(
$task->attachProjectPHIDs($phids); array($task->getPHID()));
$task->attachProjectPHIDs($project_phids);
}
if ($this->needSubscriberPHIDs) {
$subscriber_sets = id(new PhabricatorSubscribersQuery())
->withObjectPHIDs($phids)
->execute();
foreach ($tasks as $task) {
$subscribers = idx($subscriber_sets, $task->getPHID(), array());
$task->attachSubscriberPHIDs($subscribers);
}
} }
return $tasks; return $tasks;
@ -497,17 +516,6 @@ final class ManiphestTaskQuery extends PhabricatorCursorPagedPolicyAwareQuery {
$fulltext_results); $fulltext_results);
} }
private function buildSubscriberWhereClause(AphrontDatabaseConnection $conn) {
if (!$this->subscriberPHIDs) {
return null;
}
return qsprintf(
$conn,
'subscriber.subscriberPHID IN (%Ls)',
$this->subscriberPHIDs);
}
private function buildProjectWhereClause(AphrontDatabaseConnection $conn) { private function buildProjectWhereClause(AphrontDatabaseConnection $conn) {
if (!$this->projectPHIDs && !$this->includeNoProject) { if (!$this->projectPHIDs && !$this->includeNoProject) {
return null; return null;
@ -708,11 +716,14 @@ final class ManiphestTaskQuery extends PhabricatorCursorPagedPolicyAwareQuery {
} }
if ($this->subscriberPHIDs) { if ($this->subscriberPHIDs) {
$subscriber_dao = new ManiphestTaskSubscriber();
$joins[] = qsprintf( $joins[] = qsprintf(
$conn_r, $conn_r,
'JOIN %T subscriber ON subscriber.taskPHID = task.phid', 'JOIN %T e_ccs ON e_ccs.src = task.phid '.
$subscriber_dao->getTableName()); 'AND e_ccs.type = %s '.
'AND e_ccs.dst in (%Ls)',
PhabricatorEdgeConfig::TABLE_NAME_EDGE,
PhabricatorEdgeConfig::TYPE_OBJECT_HAS_SUBSCRIBER,
$this->subscriberPHIDs);
} }
switch ($this->groupBy) { switch ($this->groupBy) {

View file

@ -54,21 +54,6 @@ final class ManiphestSearchIndexer extends PhabricatorSearchDocumentIndexer {
$task->getDateCreated()); $task->getDateCreated());
} }
// We need to load handles here since non-users may subscribe (mailing
// lists, e.g.)
$ccs = $task->getCCPHIDs();
$handles = id(new PhabricatorHandleQuery())
->setViewer(PhabricatorUser::getOmnipotentUser())
->withPHIDs($ccs)
->execute();
foreach ($ccs as $cc) {
$doc->addRelationship(
PhabricatorSearchRelationship::RELATIONSHIP_SUBSCRIBER,
$handles[$cc]->getPHID(),
$handles[$cc]->getType(),
time());
}
return $doc; return $doc;
} }

View file

@ -2,6 +2,7 @@
final class ManiphestTask extends ManiphestDAO final class ManiphestTask extends ManiphestDAO
implements implements
PhabricatorSubscribableInterface,
PhabricatorMarkupInterface, PhabricatorMarkupInterface,
PhabricatorPolicyInterface, PhabricatorPolicyInterface,
PhabricatorTokenReceiverInterface, PhabricatorTokenReceiverInterface,
@ -17,7 +18,6 @@ final class ManiphestTask extends ManiphestDAO
protected $authorPHID; protected $authorPHID;
protected $ownerPHID; protected $ownerPHID;
protected $ccPHIDs = array();
protected $status; protected $status;
protected $priority; protected $priority;
@ -33,10 +33,10 @@ final class ManiphestTask extends ManiphestDAO
protected $attached = array(); protected $attached = array();
protected $projectPHIDs = array(); protected $projectPHIDs = array();
private $subscribersNeedUpdate;
protected $ownerOrdering; protected $ownerOrdering;
private $subscriberPHIDs = self::ATTACHABLE;
private $groupByProjectPHID = self::ATTACHABLE; private $groupByProjectPHID = self::ATTACHABLE;
private $customFields = self::ATTACHABLE; private $customFields = self::ATTACHABLE;
private $edgeProjectPHIDs = self::ATTACHABLE; private $edgeProjectPHIDs = self::ATTACHABLE;
@ -56,7 +56,8 @@ final class ManiphestTask extends ManiphestDAO
->setAuthorPHID($actor->getPHID()) ->setAuthorPHID($actor->getPHID())
->setViewPolicy($view_policy) ->setViewPolicy($view_policy)
->setEditPolicy($edit_policy) ->setEditPolicy($edit_policy)
->attachProjectPHIDs(array()); ->attachProjectPHIDs(array())
->attachSubscriberPHIDs(array());
} }
public function getConfiguration() { public function getConfiguration() {
@ -141,8 +142,8 @@ final class ManiphestTask extends ManiphestDAO
return PhabricatorPHID::generateNewPHID(ManiphestTaskPHIDType::TYPECONST); return PhabricatorPHID::generateNewPHID(ManiphestTaskPHIDType::TYPECONST);
} }
public function getCCPHIDs() { public function getSubscriberPHIDs() {
return array_values(nonempty($this->ccPHIDs, array())); return $this->assertAttached($this->subscriberPHIDs);
} }
public function getProjectPHIDs() { public function getProjectPHIDs() {
@ -154,15 +155,13 @@ final class ManiphestTask extends ManiphestDAO
return $this; return $this;
} }
public function setCCPHIDs(array $phids) { public function attachSubscriberPHIDs(array $phids) {
$this->ccPHIDs = array_values($phids); $this->subscriberPHIDs = $phids;
$this->subscribersNeedUpdate = true;
return $this; return $this;
} }
public function setOwnerPHID($phid) { public function setOwnerPHID($phid) {
$this->ownerPHID = nonempty($phid, null); $this->ownerPHID = nonempty($phid, null);
$this->subscribersNeedUpdate = true;
return $this; return $this;
} }
@ -194,13 +193,6 @@ final class ManiphestTask extends ManiphestDAO
$result = parent::save(); $result = parent::save();
if ($this->subscribersNeedUpdate) {
// If we've changed the subscriber PHIDs for this task, update the link
// table.
ManiphestTaskSubscriber::updateTaskSubscribers($this);
$this->subscribersNeedUpdate = false;
}
return $result; return $result;
} }
@ -217,6 +209,22 @@ final class ManiphestTask extends ManiphestDAO
} }
/* -( PhabricatorSubscribableInterface )----------------------------------- */
public function isAutomaticallySubscribed($phid) {
return ($phid == $this->getOwnerPHID());
}
public function shouldShowSubscribersProperty() {
return true;
}
public function shouldAllowSubscription($phid) {
return true;
}
/* -( Markup Interface )--------------------------------------------------- */ /* -( Markup Interface )--------------------------------------------------- */

View file

@ -1,5 +1,8 @@
<?php <?php
/**
* Deprecated; delete me.
*/
final class ManiphestTaskSubscriber extends ManiphestDAO { final class ManiphestTaskSubscriber extends ManiphestDAO {
protected $taskPHID; protected $taskPHID;

View file

@ -7,7 +7,6 @@ final class ManiphestTransaction
const TYPE_STATUS = 'status'; const TYPE_STATUS = 'status';
const TYPE_DESCRIPTION = 'description'; const TYPE_DESCRIPTION = 'description';
const TYPE_OWNER = 'reassign'; const TYPE_OWNER = 'reassign';
const TYPE_CCS = 'ccs';
const TYPE_PROJECTS = 'projects'; const TYPE_PROJECTS = 'projects';
const TYPE_PRIORITY = 'priority'; const TYPE_PRIORITY = 'priority';
const TYPE_EDGE = 'edge'; const TYPE_EDGE = 'edge';
@ -21,6 +20,12 @@ final class ManiphestTransaction
// NOTE: this type is deprecated. Keep it around for legacy installs // NOTE: this type is deprecated. Keep it around for legacy installs
// so any transactions render correctly. // so any transactions render correctly.
const TYPE_ATTACH = 'attach'; const TYPE_ATTACH = 'attach';
/**
* TYPE_CCS is legacy and depracted in favor of
* PhabricatorTransactions::TYPE_SUBSCRIBERS; keep it around for legacy
* transaction-rendering.
*/
const TYPE_CCS = 'ccs';
const MAILTAG_STATUS = 'maniphest-status'; const MAILTAG_STATUS = 'maniphest-status';

View file

@ -143,6 +143,7 @@ final class PhabricatorSearchAttachController
$targets = id(new ManiphestTaskQuery()) $targets = id(new ManiphestTaskQuery())
->setViewer($user) ->setViewer($user)
->withPHIDs(array_keys($phids)) ->withPHIDs(array_keys($phids))
->needSubscriberPHIDs(true)
->execute(); ->execute();
if (empty($targets)) { if (empty($targets)) {
@ -156,9 +157,13 @@ final class PhabricatorSearchAttachController
->setContinueOnMissingFields(true); ->setContinueOnMissingFields(true);
$cc_vector = array(); $cc_vector = array();
$cc_vector[] = $task->getCCPHIDs(); // since we loaded this via a generic object query, go ahead and get the
// attach the cc phids now
$task->attachSubscriberPHIDs(
PhabricatorSubscribersQuery::loadSubscribersForPHID($task->getPHID()));
$cc_vector[] = $task->getSubscriberPHIDs();
foreach ($targets as $target) { foreach ($targets as $target) {
$cc_vector[] = $target->getCCPHIDs(); $cc_vector[] = $target->getSubscriberPHIDs();
$cc_vector[] = array( $cc_vector[] = array(
$target->getAuthorPHID(), $target->getAuthorPHID(),
$target->getOwnerPHID(), $target->getOwnerPHID(),
@ -178,8 +183,8 @@ final class PhabricatorSearchAttachController
$all_ccs = array_unique($all_ccs); $all_ccs = array_unique($all_ccs);
$add_ccs = id(new ManiphestTransaction()) $add_ccs = id(new ManiphestTransaction())
->setTransactionType(ManiphestTransaction::TYPE_CCS) ->setTransactionType(PhabricatorTransactions::TYPE_SUBSCRIBERS)
->setNewValue($all_ccs); ->setNewValue(array('=' => $all_ccs));
$merged_from_txn = id(new ManiphestTransaction()) $merged_from_txn = id(new ManiphestTransaction())
->setTransactionType(ManiphestTransaction::TYPE_MERGED_FROM) ->setTransactionType(ManiphestTransaction::TYPE_MERGED_FROM)

View file

@ -23,8 +23,6 @@ final class PhabricatorSubscriptionsListController
if ($object instanceof PhabricatorSubscribableInterface) { if ($object instanceof PhabricatorSubscribableInterface) {
$subscriber_phids = PhabricatorSubscribersQuery::loadSubscribersForPHID( $subscriber_phids = PhabricatorSubscribersQuery::loadSubscribersForPHID(
$phid); $phid);
} else if ($object instanceof ManiphestTask) {
$subscriber_phids = $object->getCCPHIDs();
} }
$handle_phids = $subscriber_phids; $handle_phids = $subscriber_phids;