2011-02-08 19:53:59 +01:00
|
|
|
<?php
|
|
|
|
|
2013-10-22 01:58:37 +02:00
|
|
|
final class ManiphestTransactionEditor
|
|
|
|
extends PhabricatorApplicationTransactionEditor {
|
2011-02-08 19:53:59 +01:00
|
|
|
|
2014-03-14 19:52:31 +01:00
|
|
|
private $heraldEmailPHIDs = array();
|
|
|
|
|
2013-10-22 01:58:37 +02:00
|
|
|
public function getTransactionTypes() {
|
|
|
|
$types = parent::getTransactionTypes();
|
2011-05-10 01:31:26 +02:00
|
|
|
|
2013-10-22 01:58:37 +02:00
|
|
|
$types[] = PhabricatorTransactions::TYPE_COMMENT;
|
Implement PhabricatorApplicationTransactionInterface on ManiphestTask
Summary:
Ref T5245. A very long time ago I had this terrible idea that we'd let objects react to edges being added and insert transactions in response.
This turned out to be a clearly bad idea very quickly, for like 15 different reasons. A big issue is that it inverts the responsibilities of editors. It's also just clumsy and messy.
We now have `PhabricatorApplicationTransactionInterface` instead, which mostly provides a cleaner way to deal with this.
Implement `PhabricatorApplicationTransactionInterface`, implicitly moving all the attach actions (task/task, task/revision, task/commit, task/mock) to proper edge transactions.
The cost of this is that the inverse edges don't write transactions -- if you attach an object to another object, only the object you were acting on posts a transaction record. This is sort of buggy anyway already. I'll fix this in the next diff.
Test Plan: Attached tasks, revisions and mocks to a task, then detached them.
Reviewers: chad, btrahan, joshuaspence
Reviewed By: joshuaspence
Subscribers: epriestley
Maniphest Tasks: T5245
Differential Revision: https://secure.phabricator.com/D9838
2014-07-18 00:40:52 +02:00
|
|
|
$types[] = PhabricatorTransactions::TYPE_EDGE;
|
2013-10-22 01:58:37 +02:00
|
|
|
$types[] = ManiphestTransaction::TYPE_PRIORITY;
|
|
|
|
$types[] = ManiphestTransaction::TYPE_STATUS;
|
|
|
|
$types[] = ManiphestTransaction::TYPE_TITLE;
|
|
|
|
$types[] = ManiphestTransaction::TYPE_DESCRIPTION;
|
|
|
|
$types[] = ManiphestTransaction::TYPE_OWNER;
|
|
|
|
$types[] = ManiphestTransaction::TYPE_CCS;
|
|
|
|
$types[] = ManiphestTransaction::TYPE_PROJECTS;
|
2014-02-27 18:39:59 +01:00
|
|
|
$types[] = ManiphestTransaction::TYPE_SUBPRIORITY;
|
2014-03-04 00:58:00 +01:00
|
|
|
$types[] = ManiphestTransaction::TYPE_PROJECT_COLUMN;
|
2014-05-19 21:23:17 +02:00
|
|
|
$types[] = ManiphestTransaction::TYPE_UNBLOCK;
|
2013-10-22 01:58:37 +02:00
|
|
|
$types[] = PhabricatorTransactions::TYPE_VIEW_POLICY;
|
|
|
|
$types[] = PhabricatorTransactions::TYPE_EDIT_POLICY;
|
|
|
|
|
|
|
|
return $types;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function getCustomTransactionOldValue(
|
|
|
|
PhabricatorLiskDAO $object,
|
|
|
|
PhabricatorApplicationTransaction $xaction) {
|
|
|
|
|
|
|
|
switch ($xaction->getTransactionType()) {
|
|
|
|
case ManiphestTransaction::TYPE_PRIORITY:
|
|
|
|
if ($this->getIsNewObject()) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
return (int)$object->getPriority();
|
|
|
|
case ManiphestTransaction::TYPE_STATUS:
|
|
|
|
if ($this->getIsNewObject()) {
|
|
|
|
return null;
|
|
|
|
}
|
Use string constants, not integer constants, to represent task status internally
Summary:
Ref T1812. I think integer constants are going to be confusing and error prone for users to interact with. For example, because we use 0-5, adding a second "open" status like "needs verification" without disrupting the existing statuses would require users to define a status with, e.g., constant `6`, but order it between constants `0` and `1`. And if they later remove statuses, they need to avoid reusing existing constants.
Instead, use more manageable string constants like "open", "resolved", etc.
We must migrate three tables:
- The task table itself, to update task status.
- The transaction table, to update historic status changes.
- The saved query table, to update saved queries which specify status sets.
Test Plan:
- Saved a query with complicated status filters.
- Ran migrations.
- Looked at the query, at existing tasks, and at task transactions.
- Forced migrations to run again to verify idempotentcy/safety.
Reviewers: btrahan
Reviewed By: btrahan
Subscribers: epriestley
Maniphest Tasks: T1812
Differential Revision: https://secure.phabricator.com/D8583
2014-03-25 21:58:14 +01:00
|
|
|
return $object->getStatus();
|
2013-10-22 01:58:37 +02:00
|
|
|
case ManiphestTransaction::TYPE_TITLE:
|
|
|
|
if ($this->getIsNewObject()) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
return $object->getTitle();
|
|
|
|
case ManiphestTransaction::TYPE_DESCRIPTION:
|
|
|
|
if ($this->getIsNewObject()) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
return $object->getDescription();
|
|
|
|
case ManiphestTransaction::TYPE_OWNER:
|
|
|
|
return nonempty($object->getOwnerPHID(), null);
|
|
|
|
case ManiphestTransaction::TYPE_CCS:
|
|
|
|
return array_values(array_unique($object->getCCPHIDs()));
|
|
|
|
case ManiphestTransaction::TYPE_PROJECTS:
|
|
|
|
return array_values(array_unique($object->getProjectPHIDs()));
|
2014-03-04 00:58:00 +01:00
|
|
|
case ManiphestTransaction::TYPE_PROJECT_COLUMN:
|
2013-10-22 01:58:37 +02:00
|
|
|
// These are pre-populated.
|
|
|
|
return $xaction->getOldValue();
|
2014-02-27 18:39:59 +01:00
|
|
|
case ManiphestTransaction::TYPE_SUBPRIORITY:
|
|
|
|
return $object->getSubpriority();
|
2013-10-22 01:58:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function getCustomTransactionNewValue(
|
|
|
|
PhabricatorLiskDAO $object,
|
|
|
|
PhabricatorApplicationTransaction $xaction) {
|
|
|
|
|
|
|
|
switch ($xaction->getTransactionType()) {
|
|
|
|
case ManiphestTransaction::TYPE_PRIORITY:
|
|
|
|
return (int)$xaction->getNewValue();
|
|
|
|
case ManiphestTransaction::TYPE_CCS:
|
|
|
|
case ManiphestTransaction::TYPE_PROJECTS:
|
|
|
|
return array_values(array_unique($xaction->getNewValue()));
|
|
|
|
case ManiphestTransaction::TYPE_OWNER:
|
|
|
|
return nonempty($xaction->getNewValue(), null);
|
Use string constants, not integer constants, to represent task status internally
Summary:
Ref T1812. I think integer constants are going to be confusing and error prone for users to interact with. For example, because we use 0-5, adding a second "open" status like "needs verification" without disrupting the existing statuses would require users to define a status with, e.g., constant `6`, but order it between constants `0` and `1`. And if they later remove statuses, they need to avoid reusing existing constants.
Instead, use more manageable string constants like "open", "resolved", etc.
We must migrate three tables:
- The task table itself, to update task status.
- The transaction table, to update historic status changes.
- The saved query table, to update saved queries which specify status sets.
Test Plan:
- Saved a query with complicated status filters.
- Ran migrations.
- Looked at the query, at existing tasks, and at task transactions.
- Forced migrations to run again to verify idempotentcy/safety.
Reviewers: btrahan
Reviewed By: btrahan
Subscribers: epriestley
Maniphest Tasks: T1812
Differential Revision: https://secure.phabricator.com/D8583
2014-03-25 21:58:14 +01:00
|
|
|
case ManiphestTransaction::TYPE_STATUS:
|
2013-10-22 01:58:37 +02:00
|
|
|
case ManiphestTransaction::TYPE_TITLE:
|
|
|
|
case ManiphestTransaction::TYPE_DESCRIPTION:
|
2014-02-27 18:39:59 +01:00
|
|
|
case ManiphestTransaction::TYPE_SUBPRIORITY:
|
2014-03-04 00:58:00 +01:00
|
|
|
case ManiphestTransaction::TYPE_PROJECT_COLUMN:
|
2014-05-19 21:23:17 +02:00
|
|
|
case ManiphestTransaction::TYPE_UNBLOCK:
|
2013-10-22 01:58:37 +02:00
|
|
|
return $xaction->getNewValue();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Add capabilities for editing task triage details (priority, assignee, etc)
Summary:
This is primarily a client request, and a little bit use-case specific, but policies seem to be holding up well and I'm getting more comfortable about maintaining this. Much if it can run through ApplicationTransactions.
Allow the ability to edit status, policies, priorities, assignees and projects of a task to be restricted to some subset of users. Also allow bulk edit to be locked. This affects the editor itself and the edit, view and list interfaces.
Test Plan: As a restricted user, created, edited and commented on tasks. Tried to drag them around.
Reviewers: btrahan
Reviewed By: btrahan
CC: aran
Differential Revision: https://secure.phabricator.com/D7357
2013-10-22 01:59:06 +02:00
|
|
|
|
2013-10-22 01:58:37 +02:00
|
|
|
protected function transactionHasEffect(
|
|
|
|
PhabricatorLiskDAO $object,
|
|
|
|
PhabricatorApplicationTransaction $xaction) {
|
|
|
|
|
|
|
|
$old = $xaction->getOldValue();
|
|
|
|
$new = $xaction->getNewValue();
|
|
|
|
|
|
|
|
switch ($xaction->getTransactionType()) {
|
|
|
|
case ManiphestTransaction::TYPE_PROJECTS:
|
|
|
|
case ManiphestTransaction::TYPE_CCS:
|
|
|
|
sort($old);
|
|
|
|
sort($new);
|
|
|
|
return ($old !== $new);
|
2014-03-04 00:58:00 +01:00
|
|
|
case ManiphestTransaction::TYPE_PROJECT_COLUMN:
|
|
|
|
$new_column_phids = $new['columnPHIDs'];
|
|
|
|
$old_column_phids = $old['columnPHIDs'];
|
|
|
|
sort($new_column_phids);
|
|
|
|
sort($old_column_phids);
|
|
|
|
return ($old !== $new);
|
2013-10-22 01:58:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return parent::transactionHasEffect($object, $xaction);
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function applyCustomInternalTransaction(
|
|
|
|
PhabricatorLiskDAO $object,
|
|
|
|
PhabricatorApplicationTransaction $xaction) {
|
|
|
|
|
|
|
|
switch ($xaction->getTransactionType()) {
|
|
|
|
case ManiphestTransaction::TYPE_PRIORITY:
|
|
|
|
return $object->setPriority($xaction->getNewValue());
|
|
|
|
case ManiphestTransaction::TYPE_STATUS:
|
|
|
|
return $object->setStatus($xaction->getNewValue());
|
|
|
|
case ManiphestTransaction::TYPE_TITLE:
|
|
|
|
return $object->setTitle($xaction->getNewValue());
|
|
|
|
case ManiphestTransaction::TYPE_DESCRIPTION:
|
|
|
|
return $object->setDescription($xaction->getNewValue());
|
|
|
|
case ManiphestTransaction::TYPE_OWNER:
|
2013-11-19 23:10:54 +01:00
|
|
|
$phid = $xaction->getNewValue();
|
|
|
|
|
|
|
|
// Update the "ownerOrdering" column to contain the full name of the
|
|
|
|
// owner, if the task is assigned.
|
|
|
|
|
|
|
|
$handle = null;
|
|
|
|
if ($phid) {
|
|
|
|
$handle = id(new PhabricatorHandleQuery())
|
|
|
|
->setViewer($this->getActor())
|
|
|
|
->withPHIDs(array($phid))
|
|
|
|
->executeOne();
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($handle) {
|
|
|
|
$object->setOwnerOrdering($handle->getName());
|
|
|
|
} else {
|
|
|
|
$object->setOwnerOrdering(null);
|
|
|
|
}
|
|
|
|
|
|
|
|
return $object->setOwnerPHID($phid);
|
2013-10-22 01:58:37 +02:00
|
|
|
case ManiphestTransaction::TYPE_CCS:
|
|
|
|
return $object->setCCPHIDs($xaction->getNewValue());
|
|
|
|
case ManiphestTransaction::TYPE_PROJECTS:
|
2014-07-18 00:40:19 +02:00
|
|
|
$object->setProjectPHIDs($xaction->getNewValue());
|
|
|
|
ManiphestTaskProject::updateTaskProjects($object);
|
|
|
|
return $object;
|
2014-02-27 18:39:59 +01:00
|
|
|
case ManiphestTransaction::TYPE_SUBPRIORITY:
|
|
|
|
$data = $xaction->getNewValue();
|
|
|
|
$new_sub = $this->getNextSubpriority(
|
|
|
|
$data['newPriority'],
|
2014-03-27 18:50:54 +01:00
|
|
|
$data['newSubpriorityBase'],
|
|
|
|
$data['direction']);
|
2014-02-27 18:39:59 +01:00
|
|
|
$object->setSubpriority($new_sub);
|
|
|
|
return;
|
2014-03-04 00:58:00 +01:00
|
|
|
case ManiphestTransaction::TYPE_PROJECT_COLUMN:
|
|
|
|
// these do external (edge) updates
|
|
|
|
return;
|
2013-10-22 01:58:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2014-02-27 18:39:59 +01:00
|
|
|
protected function expandTransaction(
|
|
|
|
PhabricatorLiskDAO $object,
|
|
|
|
PhabricatorApplicationTransaction $xaction) {
|
|
|
|
|
|
|
|
$xactions = parent::expandTransaction($object, $xaction);
|
|
|
|
switch ($xaction->getTransactionType()) {
|
|
|
|
case ManiphestTransaction::TYPE_SUBPRIORITY:
|
|
|
|
$data = $xaction->getNewValue();
|
|
|
|
$new_pri = $data['newPriority'];
|
|
|
|
if ($new_pri != $object->getPriority()) {
|
|
|
|
$xactions[] = id(new ManiphestTransaction())
|
|
|
|
->setTransactionType(ManiphestTransaction::TYPE_PRIORITY)
|
|
|
|
->setNewValue($new_pri);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return $xactions;
|
|
|
|
}
|
|
|
|
|
2013-10-22 01:58:37 +02:00
|
|
|
protected function applyCustomExternalTransaction(
|
|
|
|
PhabricatorLiskDAO $object,
|
|
|
|
PhabricatorApplicationTransaction $xaction) {
|
2014-03-04 00:58:00 +01:00
|
|
|
|
|
|
|
switch ($xaction->getTransactionType()) {
|
|
|
|
case ManiphestTransaction::TYPE_PROJECT_COLUMN:
|
|
|
|
$new = $xaction->getNewValue();
|
|
|
|
$old = $xaction->getOldValue();
|
|
|
|
$src = $object->getPHID();
|
|
|
|
$dst = head($new['columnPHIDs']);
|
|
|
|
$edges = $old['columnPHIDs'];
|
|
|
|
$edge_type = PhabricatorEdgeConfig::TYPE_OBJECT_HAS_COLUMN;
|
|
|
|
// NOTE: Normally, we expect only one edge to exist, but this works in
|
|
|
|
// a general way so it will repair any stray edges.
|
|
|
|
$remove = array();
|
|
|
|
$edge_missing = true;
|
|
|
|
foreach ($edges as $phid) {
|
|
|
|
if ($phid == $dst) {
|
|
|
|
$edge_missing = false;
|
|
|
|
} else {
|
|
|
|
$remove[] = $phid;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$add = array();
|
|
|
|
if ($edge_missing) {
|
|
|
|
$add[] = $dst;
|
|
|
|
}
|
|
|
|
|
|
|
|
// This should never happen because of the code in
|
|
|
|
// transactionHasEffect, but keep it for maximum conservativeness
|
|
|
|
if (!$add && !$remove) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-07-18 00:41:42 +02:00
|
|
|
$editor = new PhabricatorEdgeEditor();
|
2014-03-04 00:58:00 +01:00
|
|
|
foreach ($add as $phid) {
|
|
|
|
$editor->addEdge($src, $edge_type, $phid);
|
|
|
|
}
|
|
|
|
foreach ($remove as $phid) {
|
|
|
|
$editor->removeEdge($src, $edge_type, $phid);
|
|
|
|
}
|
|
|
|
$editor->save();
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2013-10-22 01:58:37 +02:00
|
|
|
}
|
|
|
|
|
2014-05-19 21:23:17 +02:00
|
|
|
protected function applyFinalEffects(
|
|
|
|
PhabricatorLiskDAO $object,
|
|
|
|
array $xactions) {
|
|
|
|
|
|
|
|
// When we change the status of a task, update tasks this tasks blocks
|
|
|
|
// with a message to the effect of "alincoln resolved blocking task Txxx."
|
|
|
|
$unblock_xaction = null;
|
|
|
|
foreach ($xactions as $xaction) {
|
|
|
|
switch ($xaction->getTransactionType()) {
|
|
|
|
case ManiphestTransaction::TYPE_STATUS:
|
|
|
|
$unblock_xaction = $xaction;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($unblock_xaction !== null) {
|
|
|
|
$blocked_phids = PhabricatorEdgeQuery::loadDestinationPHIDs(
|
|
|
|
$object->getPHID(),
|
|
|
|
PhabricatorEdgeConfig::TYPE_TASK_DEPENDED_ON_BY_TASK);
|
|
|
|
if ($blocked_phids) {
|
|
|
|
// In theory we could apply these through policies, but that seems a
|
|
|
|
// little bit surprising. For now, use the actor's vision.
|
|
|
|
$blocked_tasks = id(new ManiphestTaskQuery())
|
|
|
|
->setViewer($this->getActor())
|
|
|
|
->withPHIDs($blocked_phids)
|
|
|
|
->execute();
|
|
|
|
|
|
|
|
$old = $unblock_xaction->getOldValue();
|
|
|
|
$new = $unblock_xaction->getNewValue();
|
|
|
|
|
|
|
|
foreach ($blocked_tasks as $blocked_task) {
|
|
|
|
$xactions = array();
|
|
|
|
|
|
|
|
$xactions[] = id(new ManiphestTransaction())
|
|
|
|
->setTransactionType(ManiphestTransaction::TYPE_UNBLOCK)
|
|
|
|
->setOldValue(array($object->getPHID() => $old))
|
|
|
|
->setNewValue(array($object->getPHID() => $new));
|
|
|
|
|
|
|
|
// TODO: We should avoid notifiying users about these indirect
|
|
|
|
// changes if they are getting a notification about the current
|
|
|
|
// change, so you don't get a pile of extra notifications if you are
|
|
|
|
// subscribed to this task.
|
|
|
|
|
|
|
|
id(new ManiphestTransactionEditor())
|
|
|
|
->setActor($this->getActor())
|
|
|
|
->setContentSource($this->getContentSource())
|
|
|
|
->setContinueOnNoEffect(true)
|
|
|
|
->setContinueOnMissingFields(true)
|
|
|
|
->applyTransactions($blocked_task, $xactions);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return $xactions;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-10-22 01:58:37 +02:00
|
|
|
protected function shouldSendMail(
|
|
|
|
PhabricatorLiskDAO $object,
|
|
|
|
array $xactions) {
|
2014-03-04 00:58:00 +01:00
|
|
|
|
2014-03-05 02:01:33 +01:00
|
|
|
$xactions = mfilter($xactions, 'shouldHide', true);
|
|
|
|
return $xactions;
|
2013-10-22 01:58:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
protected function getMailSubjectPrefix() {
|
|
|
|
return PhabricatorEnv::getEnvConfig('metamta.maniphest.subject-prefix');
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function getMailThreadID(PhabricatorLiskDAO $object) {
|
|
|
|
return 'maniphest-task-'.$object->getPHID();
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function getMailTo(PhabricatorLiskDAO $object) {
|
|
|
|
return array(
|
|
|
|
$object->getOwnerPHID(),
|
|
|
|
$this->requireActor()->getPHID(),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function getMailCC(PhabricatorLiskDAO $object) {
|
2014-03-14 19:52:31 +01:00
|
|
|
$phids = array();
|
|
|
|
|
|
|
|
foreach ($object->getCCPHIDs() as $phid) {
|
|
|
|
$phids[] = $phid;
|
|
|
|
}
|
|
|
|
|
2014-05-19 21:40:57 +02:00
|
|
|
foreach (parent::getMailCC($object) as $phid) {
|
|
|
|
$phids[] = $phid;
|
|
|
|
}
|
|
|
|
|
2014-03-14 19:52:31 +01:00
|
|
|
foreach ($this->heraldEmailPHIDs as $phid) {
|
|
|
|
$phids[] = $phid;
|
|
|
|
}
|
|
|
|
|
|
|
|
return $phids;
|
2013-10-22 01:58:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
protected function buildReplyHandler(PhabricatorLiskDAO $object) {
|
|
|
|
return id(new ManiphestReplyHandler())
|
|
|
|
->setMailReceiver($object);
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function buildMailTemplate(PhabricatorLiskDAO $object) {
|
|
|
|
$id = $object->getID();
|
|
|
|
$title = $object->getTitle();
|
|
|
|
|
|
|
|
return id(new PhabricatorMetaMTAMail())
|
|
|
|
->setSubject("T{$id}: {$title}")
|
|
|
|
->addHeader('Thread-Topic', "T{$id}: ".$object->getOriginalTitle());
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function buildMailBody(
|
|
|
|
PhabricatorLiskDAO $object,
|
|
|
|
array $xactions) {
|
|
|
|
|
|
|
|
$body = parent::buildMailBody($object, $xactions);
|
|
|
|
|
|
|
|
if ($this->getIsNewObject()) {
|
|
|
|
$body->addTextSection(
|
|
|
|
pht('TASK DESCRIPTION'),
|
|
|
|
$object->getDescription());
|
|
|
|
}
|
|
|
|
|
|
|
|
$body->addTextSection(
|
|
|
|
pht('TASK DETAIL'),
|
|
|
|
PhabricatorEnv::getProductionURI('/T'.$object->getID()));
|
|
|
|
|
|
|
|
return $body;
|
|
|
|
}
|
|
|
|
|
2014-03-05 02:01:33 +01:00
|
|
|
protected function shouldPublishFeedStory(
|
|
|
|
PhabricatorLiskDAO $object,
|
|
|
|
array $xactions) {
|
|
|
|
return $this->shouldSendMail($object, $xactions);
|
2013-10-22 01:58:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
protected function supportsSearch() {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-03-05 21:06:59 +01:00
|
|
|
protected function shouldApplyHeraldRules(
|
|
|
|
PhabricatorLiskDAO $object,
|
|
|
|
array $xactions) {
|
2013-10-22 01:58:37 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function buildHeraldAdapter(
|
|
|
|
PhabricatorLiskDAO $object,
|
|
|
|
array $xactions) {
|
|
|
|
|
|
|
|
return id(new HeraldManiphestTaskAdapter())
|
|
|
|
->setTask($object);
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function didApplyHeraldRules(
|
|
|
|
PhabricatorLiskDAO $object,
|
|
|
|
HeraldAdapter $adapter,
|
|
|
|
HeraldTranscript $transcript) {
|
|
|
|
|
2014-03-05 21:06:59 +01:00
|
|
|
// TODO: Convert these to transactions. The way Maniphest deals with these
|
|
|
|
// transactions is currently unconventional and messy.
|
|
|
|
|
2013-10-22 01:58:37 +02:00
|
|
|
$save_again = false;
|
|
|
|
$cc_phids = $adapter->getCcPHIDs();
|
|
|
|
if ($cc_phids) {
|
|
|
|
$existing_cc = $object->getCCPHIDs();
|
|
|
|
$new_cc = array_unique(array_merge($cc_phids, $existing_cc));
|
|
|
|
$object->setCCPHIDs($new_cc);
|
|
|
|
$object->save();
|
|
|
|
}
|
2014-03-05 21:06:59 +01:00
|
|
|
|
2014-03-14 19:52:31 +01:00
|
|
|
$this->heraldEmailPHIDs = $adapter->getEmailPHIDs();
|
|
|
|
|
2014-03-05 21:06:59 +01:00
|
|
|
$xactions = array();
|
|
|
|
|
|
|
|
$assign_phid = $adapter->getAssignPHID();
|
|
|
|
if ($assign_phid) {
|
|
|
|
$xactions[] = id(new ManiphestTransaction())
|
|
|
|
->setTransactionType(ManiphestTransaction::TYPE_OWNER)
|
|
|
|
->setNewValue($assign_phid);
|
|
|
|
}
|
|
|
|
|
2014-07-18 00:40:19 +02:00
|
|
|
$project_phids = $adapter->getProjectPHIDs();
|
|
|
|
if ($project_phids) {
|
|
|
|
$existing_projects = $object->getProjectPHIDs();
|
|
|
|
$new_projects = array_unique(
|
|
|
|
array_merge(
|
|
|
|
$project_phids,
|
|
|
|
$existing_projects));
|
|
|
|
|
|
|
|
$xactions[] = id(new ManiphestTransaction())
|
|
|
|
->setTransactionType(ManiphestTransaction::TYPE_PROJECTS)
|
|
|
|
->setNewValue($new_projects);
|
|
|
|
}
|
|
|
|
|
2014-03-05 21:06:59 +01:00
|
|
|
return $xactions;
|
2011-02-08 19:53:59 +01:00
|
|
|
}
|
2011-12-17 22:27:11 +01:00
|
|
|
|
Add capabilities for editing task triage details (priority, assignee, etc)
Summary:
This is primarily a client request, and a little bit use-case specific, but policies seem to be holding up well and I'm getting more comfortable about maintaining this. Much if it can run through ApplicationTransactions.
Allow the ability to edit status, policies, priorities, assignees and projects of a task to be restricted to some subset of users. Also allow bulk edit to be locked. This affects the editor itself and the edit, view and list interfaces.
Test Plan: As a restricted user, created, edited and commented on tasks. Tried to drag them around.
Reviewers: btrahan
Reviewed By: btrahan
CC: aran
Differential Revision: https://secure.phabricator.com/D7357
2013-10-22 01:59:06 +02:00
|
|
|
protected function requireCapabilities(
|
|
|
|
PhabricatorLiskDAO $object,
|
|
|
|
PhabricatorApplicationTransaction $xaction) {
|
|
|
|
|
|
|
|
parent::requireCapabilities($object, $xaction);
|
|
|
|
|
|
|
|
$app_capability_map = array(
|
|
|
|
ManiphestTransaction::TYPE_PRIORITY =>
|
|
|
|
ManiphestCapabilityEditPriority::CAPABILITY,
|
|
|
|
ManiphestTransaction::TYPE_STATUS =>
|
|
|
|
ManiphestCapabilityEditStatus::CAPABILITY,
|
|
|
|
ManiphestTransaction::TYPE_PROJECTS =>
|
|
|
|
ManiphestCapabilityEditProjects::CAPABILITY,
|
|
|
|
ManiphestTransaction::TYPE_OWNER =>
|
|
|
|
ManiphestCapabilityEditAssign::CAPABILITY,
|
|
|
|
PhabricatorTransactions::TYPE_EDIT_POLICY =>
|
|
|
|
ManiphestCapabilityEditPolicies::CAPABILITY,
|
|
|
|
PhabricatorTransactions::TYPE_VIEW_POLICY =>
|
|
|
|
ManiphestCapabilityEditPolicies::CAPABILITY,
|
|
|
|
);
|
|
|
|
|
|
|
|
$transaction_type = $xaction->getTransactionType();
|
|
|
|
$app_capability = idx($app_capability_map, $transaction_type);
|
|
|
|
|
|
|
|
if ($app_capability) {
|
|
|
|
$app = id(new PhabricatorApplicationQuery())
|
|
|
|
->setViewer($this->getActor())
|
|
|
|
->withClasses(array('PhabricatorApplicationManiphest'))
|
|
|
|
->executeOne();
|
|
|
|
PhabricatorPolicyFilter::requireCapability(
|
|
|
|
$this->getActor(),
|
|
|
|
$app,
|
|
|
|
$app_capability);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-13 21:50:08 +01:00
|
|
|
protected function adjustObjectForPolicyChecks(
|
|
|
|
PhabricatorLiskDAO $object,
|
|
|
|
array $xactions) {
|
|
|
|
|
|
|
|
$copy = parent::adjustObjectForPolicyChecks($object, $xactions);
|
|
|
|
foreach ($xactions as $xaction) {
|
|
|
|
switch ($xaction->getTransactionType()) {
|
|
|
|
case ManiphestTransaction::TYPE_OWNER:
|
|
|
|
$copy->setOwnerPHID($xaction->getNewValue());
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return $copy;
|
|
|
|
}
|
Add capabilities for editing task triage details (priority, assignee, etc)
Summary:
This is primarily a client request, and a little bit use-case specific, but policies seem to be holding up well and I'm getting more comfortable about maintaining this. Much if it can run through ApplicationTransactions.
Allow the ability to edit status, policies, priorities, assignees and projects of a task to be restricted to some subset of users. Also allow bulk edit to be locked. This affects the editor itself and the edit, view and list interfaces.
Test Plan: As a restricted user, created, edited and commented on tasks. Tried to drag them around.
Reviewers: btrahan
Reviewed By: btrahan
CC: aran
Differential Revision: https://secure.phabricator.com/D7357
2013-10-22 01:59:06 +02:00
|
|
|
|
2014-03-27 18:50:54 +01:00
|
|
|
private function getNextSubpriority($pri, $sub, $dir = '>') {
|
|
|
|
|
|
|
|
switch ($dir) {
|
|
|
|
case '>':
|
|
|
|
$order = 'ASC';
|
|
|
|
break;
|
|
|
|
case '<':
|
|
|
|
$order = 'DESC';
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
throw new Exception('$dir must be ">" or "<".');
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($sub === null) {
|
|
|
|
$base = 0;
|
|
|
|
} else {
|
|
|
|
$base = $sub;
|
|
|
|
}
|
2013-09-25 22:44:14 +02:00
|
|
|
|
2012-04-02 21:12:04 +02:00
|
|
|
if ($sub === null) {
|
|
|
|
$next = id(new ManiphestTask())->loadOneWhere(
|
2014-03-27 18:50:54 +01:00
|
|
|
'priority = %d ORDER BY subpriority %Q LIMIT 1',
|
|
|
|
$pri,
|
|
|
|
$order);
|
2012-04-02 21:12:04 +02:00
|
|
|
if ($next) {
|
2014-03-27 18:50:54 +01:00
|
|
|
if ($dir == '>') {
|
|
|
|
return $next->getSubpriority() - ((double)(2 << 16));
|
|
|
|
} else {
|
|
|
|
return $next->getSubpriority() + ((double)(2 << 16));
|
|
|
|
}
|
2012-04-02 21:12:04 +02:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
$next = id(new ManiphestTask())->loadOneWhere(
|
2014-03-27 18:50:54 +01:00
|
|
|
'priority = %d AND subpriority %Q %f ORDER BY subpriority %Q LIMIT 1',
|
2012-04-02 21:12:04 +02:00
|
|
|
$pri,
|
2014-03-27 18:50:54 +01:00
|
|
|
$dir,
|
|
|
|
$sub,
|
|
|
|
$order);
|
2012-04-02 21:12:04 +02:00
|
|
|
if ($next) {
|
|
|
|
return ($sub + $next->getSubpriority()) / 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-27 18:50:54 +01:00
|
|
|
if ($dir == '>') {
|
|
|
|
return $base + (double)(2 << 32);
|
|
|
|
} else {
|
|
|
|
return $base - (double)(2 << 32);
|
|
|
|
}
|
2012-04-02 21:12:04 +02:00
|
|
|
}
|
|
|
|
|
2011-02-08 19:53:59 +01:00
|
|
|
}
|