2011-02-08 19:53:59 +01:00
|
|
|
<?php
|
|
|
|
|
2012-07-11 20:40:10 +02:00
|
|
|
final class ManiphestTask extends ManiphestDAO
|
2013-02-15 16:47:14 +01:00
|
|
|
implements
|
2014-12-11 01:27:30 +01:00
|
|
|
PhabricatorSubscribableInterface,
|
2013-02-15 16:47:14 +01:00
|
|
|
PhabricatorMarkupInterface,
|
|
|
|
PhabricatorPolicyInterface,
|
2013-03-30 17:32:29 +01:00
|
|
|
PhabricatorTokenReceiverInterface,
|
2013-10-25 21:52:00 +02:00
|
|
|
PhabricatorFlaggableInterface,
|
2014-09-09 23:21:13 +02:00
|
|
|
PhabricatorMentionableInterface,
|
2013-09-17 00:58:35 +02:00
|
|
|
PhrequentTrackableInterface,
|
2014-05-05 19:55:19 +02:00
|
|
|
PhabricatorCustomFieldInterface,
|
2014-07-21 15:59:22 +02:00
|
|
|
PhabricatorDestructibleInterface,
|
2014-08-08 00:44:12 +02:00
|
|
|
PhabricatorApplicationTransactionInterface,
|
2015-06-11 00:53:04 +02:00
|
|
|
PhabricatorProjectInterface,
|
2015-12-13 11:31:09 +01:00
|
|
|
PhabricatorSpacesInterface,
|
2015-12-21 18:02:55 +01:00
|
|
|
PhabricatorConduitResultInterface,
|
2016-03-09 17:40:19 +01:00
|
|
|
PhabricatorFulltextInterface,
|
2017-03-02 00:37:26 +01:00
|
|
|
DoorkeeperBridgedObjectInterface,
|
2017-03-02 21:46:17 +01:00
|
|
|
PhabricatorEditEngineSubtypeInterface,
|
|
|
|
PhabricatorEditEngineLockableInterface {
|
2012-07-11 20:40:10 +02:00
|
|
|
|
|
|
|
const MARKUP_FIELD_DESCRIPTION = 'markup:desc';
|
2011-02-08 19:53:59 +01:00
|
|
|
|
|
|
|
protected $authorPHID;
|
|
|
|
protected $ownerPHID;
|
|
|
|
|
2014-02-18 00:59:31 +01:00
|
|
|
protected $status;
|
2011-02-08 19:53:59 +01:00
|
|
|
protected $priority;
|
2013-09-24 21:03:14 +02:00
|
|
|
protected $subpriority = 0;
|
2011-02-08 19:53:59 +01:00
|
|
|
|
2013-09-25 20:16:55 +02:00
|
|
|
protected $title = '';
|
2013-10-14 20:46:14 +02:00
|
|
|
protected $originalTitle = '';
|
2013-09-25 20:16:55 +02:00
|
|
|
protected $description = '';
|
2011-10-14 22:11:58 +02:00
|
|
|
protected $originalEmailSource;
|
2011-05-05 08:09:42 +02:00
|
|
|
protected $mailKey;
|
2013-09-25 20:18:47 +02:00
|
|
|
protected $viewPolicy = PhabricatorPolicies::POLICY_USER;
|
|
|
|
protected $editPolicy = PhabricatorPolicies::POLICY_USER;
|
2011-05-05 08:09:42 +02:00
|
|
|
|
Allow Maniphest to scale to a massive size
Summary:
Maniphest is missing some keys and some query strategy which will make it
cumbersome to manage more than a few tens of thousands of tasks.
Test Plan:
Handily manipulated 100k-scale task groups. Maniphest takes about 250ms to
select and render pages of 1,000 tasks and has no problem paging and filtering
them, etc. We should be good to scale to multiple millions of tasks with these
changes.
Reviewed By: gc3
Reviewers: fratrik, jungejason, aran, tuomaspelkonen, gc3
Commenters: jungejason
CC: anjali, aran, epriestley, gc3, jungejason
Differential Revision: 534
2011-06-27 03:50:17 +02:00
|
|
|
protected $ownerOrdering;
|
2015-06-11 00:53:04 +02:00
|
|
|
protected $spacePHID;
|
2016-03-09 17:40:19 +01:00
|
|
|
protected $bridgedObjectPHID;
|
2016-02-06 22:02:13 +01:00
|
|
|
protected $properties = array();
|
2016-02-08 23:16:51 +01:00
|
|
|
protected $points;
|
2017-03-02 00:37:26 +01:00
|
|
|
protected $subtype;
|
Allow Maniphest to scale to a massive size
Summary:
Maniphest is missing some keys and some query strategy which will make it
cumbersome to manage more than a few tens of thousands of tasks.
Test Plan:
Handily manipulated 100k-scale task groups. Maniphest takes about 250ms to
select and render pages of 1,000 tasks and has no problem paging and filtering
them, etc. We should be good to scale to multiple millions of tasks with these
changes.
Reviewed By: gc3
Reviewers: fratrik, jungejason, aran, tuomaspelkonen, gc3
Commenters: jungejason
CC: anjali, aran, epriestley, gc3, jungejason
Differential Revision: 534
2011-06-27 03:50:17 +02:00
|
|
|
|
2014-12-11 01:27:30 +01:00
|
|
|
private $subscriberPHIDs = self::ATTACHABLE;
|
2013-09-12 22:08:25 +02:00
|
|
|
private $groupByProjectPHID = self::ATTACHABLE;
|
2013-09-17 00:58:35 +02:00
|
|
|
private $customFields = self::ATTACHABLE;
|
2014-07-18 00:42:53 +02:00
|
|
|
private $edgeProjectPHIDs = self::ATTACHABLE;
|
2016-03-09 17:40:19 +01:00
|
|
|
private $bridgedObject = self::ATTACHABLE;
|
2011-12-24 04:03:28 +01:00
|
|
|
|
2013-10-09 22:53:17 +02:00
|
|
|
public static function initializeNewTask(PhabricatorUser $actor) {
|
|
|
|
$app = id(new PhabricatorApplicationQuery())
|
|
|
|
->setViewer($actor)
|
2014-07-23 02:03:09 +02:00
|
|
|
->withClasses(array('PhabricatorManiphestApplication'))
|
2013-10-09 22:53:17 +02:00
|
|
|
->executeOne();
|
|
|
|
|
2014-07-25 00:20:39 +02:00
|
|
|
$view_policy = $app->getPolicy(ManiphestDefaultViewCapability::CAPABILITY);
|
|
|
|
$edit_policy = $app->getPolicy(ManiphestDefaultEditCapability::CAPABILITY);
|
2013-10-09 22:53:17 +02:00
|
|
|
|
|
|
|
return id(new ManiphestTask())
|
2014-02-18 00:59:31 +01:00
|
|
|
->setStatus(ManiphestTaskStatus::getDefaultStatus())
|
2013-10-09 22:53:17 +02:00
|
|
|
->setPriority(ManiphestTaskPriority::getDefaultPriority())
|
|
|
|
->setAuthorPHID($actor->getPHID())
|
|
|
|
->setViewPolicy($view_policy)
|
2014-07-18 00:42:53 +02:00
|
|
|
->setEditPolicy($edit_policy)
|
2015-06-11 19:23:56 +02:00
|
|
|
->setSpacePHID($actor->getDefaultSpacePHID())
|
2017-03-02 00:37:26 +01:00
|
|
|
->setSubtype(PhabricatorEditEngineSubtype::SUBTYPE_DEFAULT)
|
2014-12-11 01:27:30 +01:00
|
|
|
->attachProjectPHIDs(array())
|
|
|
|
->attachSubscriberPHIDs(array());
|
2013-10-09 22:53:17 +02:00
|
|
|
}
|
|
|
|
|
2015-01-13 20:47:05 +01:00
|
|
|
protected function getConfiguration() {
|
2011-02-08 19:53:59 +01:00
|
|
|
return array(
|
|
|
|
self::CONFIG_AUX_PHID => true,
|
|
|
|
self::CONFIG_SERIALIZATION => array(
|
2016-02-06 22:02:13 +01:00
|
|
|
'properties' => self::SERIALIZATION_JSON,
|
2011-02-08 19:53:59 +01:00
|
|
|
),
|
2014-09-19 20:46:44 +02:00
|
|
|
self::CONFIG_COLUMN_SCHEMA => array(
|
|
|
|
'ownerPHID' => 'phid?',
|
|
|
|
'status' => 'text12',
|
|
|
|
'priority' => 'uint32',
|
2014-10-01 17:18:53 +02:00
|
|
|
'title' => 'sort',
|
2014-09-19 20:46:44 +02:00
|
|
|
'originalTitle' => 'text',
|
|
|
|
'description' => 'text',
|
|
|
|
'mailKey' => 'bytes20',
|
|
|
|
'ownerOrdering' => 'text64?',
|
|
|
|
'originalEmailSource' => 'text255?',
|
|
|
|
'subpriority' => 'double',
|
2016-02-08 23:16:51 +01:00
|
|
|
'points' => 'double?',
|
2016-03-09 17:40:19 +01:00
|
|
|
'bridgedObjectPHID' => 'phid?',
|
2017-03-02 00:37:26 +01:00
|
|
|
'subtype' => 'text64',
|
2014-09-19 20:46:44 +02:00
|
|
|
),
|
|
|
|
self::CONFIG_KEY_SCHEMA => array(
|
|
|
|
'key_phid' => null,
|
|
|
|
'phid' => array(
|
|
|
|
'columns' => array('phid'),
|
|
|
|
'unique' => true,
|
|
|
|
),
|
|
|
|
'priority' => array(
|
|
|
|
'columns' => array('priority', 'status'),
|
|
|
|
),
|
|
|
|
'status' => array(
|
|
|
|
'columns' => array('status'),
|
|
|
|
),
|
|
|
|
'ownerPHID' => array(
|
|
|
|
'columns' => array('ownerPHID', 'status'),
|
|
|
|
),
|
|
|
|
'authorPHID' => array(
|
|
|
|
'columns' => array('authorPHID', 'status'),
|
|
|
|
),
|
|
|
|
'ownerOrdering' => array(
|
|
|
|
'columns' => array('ownerOrdering'),
|
|
|
|
),
|
|
|
|
'priority_2' => array(
|
|
|
|
'columns' => array('priority', 'subpriority'),
|
|
|
|
),
|
|
|
|
'key_dateCreated' => array(
|
|
|
|
'columns' => array('dateCreated'),
|
|
|
|
),
|
|
|
|
'key_dateModified' => array(
|
|
|
|
'columns' => array('dateModified'),
|
|
|
|
),
|
2014-10-01 17:18:53 +02:00
|
|
|
'key_title' => array(
|
|
|
|
'columns' => array('title(64)'),
|
|
|
|
),
|
2016-03-09 17:40:19 +01:00
|
|
|
'key_bridgedobject' => array(
|
|
|
|
'columns' => array('bridgedObjectPHID'),
|
|
|
|
'unique' => true,
|
|
|
|
),
|
2017-03-02 00:37:26 +01:00
|
|
|
'key_subtype' => array(
|
|
|
|
'columns' => array('subtype'),
|
|
|
|
),
|
2014-09-19 20:46:44 +02:00
|
|
|
),
|
2011-02-08 19:53:59 +01:00
|
|
|
) + parent::getConfiguration();
|
|
|
|
}
|
|
|
|
|
2012-07-19 05:41:42 +02:00
|
|
|
public function loadDependsOnTaskPHIDs() {
|
|
|
|
return PhabricatorEdgeQuery::loadDestinationPHIDs(
|
|
|
|
$this->getPHID(),
|
2014-12-28 15:10:49 +01:00
|
|
|
ManiphestTaskDependsOnTaskEdgeType::EDGECONST);
|
2012-07-19 05:41:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public function loadDependedOnByTaskPHIDs() {
|
|
|
|
return PhabricatorEdgeQuery::loadDestinationPHIDs(
|
|
|
|
$this->getPHID(),
|
2014-12-28 15:10:49 +01:00
|
|
|
ManiphestTaskDependedOnByTaskEdgeType::EDGECONST);
|
2012-07-19 05:41:42 +02:00
|
|
|
}
|
|
|
|
|
2011-02-08 19:53:59 +01:00
|
|
|
public function generatePHID() {
|
2014-07-24 00:05:46 +02:00
|
|
|
return PhabricatorPHID::generateNewPHID(ManiphestTaskPHIDType::TYPECONST);
|
2011-02-08 19:53:59 +01:00
|
|
|
}
|
|
|
|
|
2014-12-11 01:27:30 +01:00
|
|
|
public function getSubscriberPHIDs() {
|
|
|
|
return $this->assertAttached($this->subscriberPHIDs);
|
2011-02-09 21:47:24 +01:00
|
|
|
}
|
|
|
|
|
2014-07-18 00:42:53 +02:00
|
|
|
public function getProjectPHIDs() {
|
|
|
|
return $this->assertAttached($this->edgeProjectPHIDs);
|
2011-06-30 01:16:33 +02:00
|
|
|
}
|
|
|
|
|
2014-07-18 00:42:53 +02:00
|
|
|
public function attachProjectPHIDs(array $phids) {
|
|
|
|
$this->edgeProjectPHIDs = $phids;
|
|
|
|
return $this;
|
2011-11-16 18:21:11 +01:00
|
|
|
}
|
|
|
|
|
2014-12-11 01:27:30 +01:00
|
|
|
public function attachSubscriberPHIDs(array $phids) {
|
|
|
|
$this->subscriberPHIDs = $phids;
|
2011-07-07 19:24:49 +02:00
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function setOwnerPHID($phid) {
|
2013-05-23 18:22:18 +02:00
|
|
|
$this->ownerPHID = nonempty($phid, null);
|
2011-07-07 19:24:49 +02:00
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2012-06-14 05:52:10 +02:00
|
|
|
public function setTitle($title) {
|
|
|
|
$this->title = $title;
|
|
|
|
if (!$this->getID()) {
|
|
|
|
$this->originalTitle = $title;
|
|
|
|
}
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2014-03-14 23:13:51 +01:00
|
|
|
public function getMonogram() {
|
|
|
|
return 'T'.$this->getID();
|
|
|
|
}
|
|
|
|
|
2016-07-01 17:50:16 +02:00
|
|
|
public function getURI() {
|
|
|
|
return '/'.$this->getMonogram();
|
|
|
|
}
|
|
|
|
|
2013-09-12 22:08:25 +02:00
|
|
|
public function attachGroupByProjectPHID($phid) {
|
|
|
|
$this->groupByProjectPHID = $phid;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getGroupByProjectPHID() {
|
|
|
|
return $this->assertAttached($this->groupByProjectPHID);
|
|
|
|
}
|
|
|
|
|
2011-05-05 08:09:42 +02:00
|
|
|
public function save() {
|
|
|
|
if (!$this->mailKey) {
|
Replace callsites to sha1() that use it to asciify entropy with
Filesystem::readRandomCharacters()
Summary: See T547. To improve auditability of use of crypto-sensitive hash
functions, use Filesystem::readRandomCharacters() in place of
sha1(Filesystem::readRandomBytes()) when we're just generating random ASCII
strings.
Test Plan:
- Generated a new PHID.
- Logged out and logged back in (to test sessions).
- Regenerated Conduit certificate.
- Created a new task, verified mail key generated sensibly.
- Created a new revision, verified mail key generated sensibly.
- Ran "arc list", got blocked, installed new certificate, ran "arc list"
again.
Reviewers: jungejason, nh, tuomaspelkonen, aran, benmathews
Reviewed By: jungejason
CC: aran, epriestley, jungejason
Differential Revision: 1000
2011-10-11 04:22:30 +02:00
|
|
|
$this->mailKey = Filesystem::readRandomCharacters(20);
|
2011-05-05 08:09:42 +02:00
|
|
|
}
|
2011-06-30 01:16:33 +02:00
|
|
|
|
|
|
|
$result = parent::save();
|
|
|
|
|
|
|
|
return $result;
|
2011-05-05 08:09:42 +02:00
|
|
|
}
|
|
|
|
|
2014-03-25 21:47:42 +01:00
|
|
|
public function isClosed() {
|
|
|
|
return ManiphestTaskStatus::isClosedStatus($this->getStatus());
|
|
|
|
}
|
2011-12-24 04:03:28 +01:00
|
|
|
|
2017-03-02 21:46:17 +01:00
|
|
|
public function isLocked() {
|
|
|
|
return ManiphestTaskStatus::isLockedStatus($this->getStatus());
|
|
|
|
}
|
|
|
|
|
2016-02-06 22:02:13 +01:00
|
|
|
public function setProperty($key, $value) {
|
|
|
|
$this->properties[$key] = $value;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getProperty($key, $default = null) {
|
|
|
|
return idx($this->properties, $key, $default);
|
|
|
|
}
|
|
|
|
|
2016-02-06 23:05:15 +01:00
|
|
|
public function getCoverImageFilePHID() {
|
|
|
|
return idx($this->properties, 'cover.filePHID');
|
|
|
|
}
|
|
|
|
|
2016-02-06 22:02:13 +01:00
|
|
|
public function getCoverImageThumbnailPHID() {
|
|
|
|
return idx($this->properties, 'cover.thumbnailPHID');
|
|
|
|
}
|
|
|
|
|
2016-02-10 14:59:46 +01:00
|
|
|
public function getWorkboardOrderVectors() {
|
|
|
|
return array(
|
|
|
|
PhabricatorProjectColumn::ORDER_PRIORITY => array(
|
|
|
|
(int)-$this->getPriority(),
|
|
|
|
(double)-$this->getSubpriority(),
|
|
|
|
(int)-$this->getID(),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2016-02-11 00:39:08 +01:00
|
|
|
private function comparePriorityTo(ManiphestTask $other) {
|
|
|
|
$upri = $this->getPriority();
|
|
|
|
$vpri = $other->getPriority();
|
|
|
|
|
|
|
|
if ($upri != $vpri) {
|
|
|
|
return ($upri - $vpri);
|
|
|
|
}
|
|
|
|
|
|
|
|
$usub = $this->getSubpriority();
|
|
|
|
$vsub = $other->getSubpriority();
|
|
|
|
|
|
|
|
if ($usub != $vsub) {
|
|
|
|
return ($usub - $vsub);
|
|
|
|
}
|
|
|
|
|
|
|
|
$uid = $this->getID();
|
|
|
|
$vid = $other->getID();
|
|
|
|
|
|
|
|
if ($uid != $vid) {
|
|
|
|
return ($uid - $vid);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function isLowerPriorityThan(ManiphestTask $other) {
|
|
|
|
return ($this->comparePriorityTo($other) < 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function isHigherPriorityThan(ManiphestTask $other) {
|
|
|
|
return ($this->comparePriorityTo($other) > 0);
|
|
|
|
}
|
|
|
|
|
2016-02-10 22:53:36 +01:00
|
|
|
public function getWorkboardProperties() {
|
|
|
|
return array(
|
|
|
|
'status' => $this->getStatus(),
|
|
|
|
'points' => (double)$this->getPoints(),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2012-07-11 20:40:10 +02:00
|
|
|
|
2014-12-11 01:27:30 +01:00
|
|
|
/* -( PhabricatorSubscribableInterface )----------------------------------- */
|
|
|
|
|
|
|
|
|
|
|
|
public function isAutomaticallySubscribed($phid) {
|
|
|
|
return ($phid == $this->getOwnerPHID());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-07-11 20:40:10 +02:00
|
|
|
/* -( Markup Interface )--------------------------------------------------- */
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @task markup
|
|
|
|
*/
|
|
|
|
public function getMarkupFieldKey($field) {
|
|
|
|
$hash = PhabricatorHash::digest($this->getMarkupText($field));
|
|
|
|
$id = $this->getID();
|
|
|
|
return "maniphest:T{$id}:{$field}:{$hash}";
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @task markup
|
|
|
|
*/
|
|
|
|
public function getMarkupText($field) {
|
|
|
|
return $this->getDescription();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @task markup
|
|
|
|
*/
|
|
|
|
public function newMarkupEngine($field) {
|
|
|
|
return PhabricatorMarkupEngine::newManiphestMarkupEngine();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @task markup
|
|
|
|
*/
|
|
|
|
public function didMarkupText(
|
|
|
|
$field,
|
|
|
|
$output,
|
|
|
|
PhutilMarkupEngine $engine) {
|
|
|
|
return $output;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @task markup
|
|
|
|
*/
|
|
|
|
public function shouldUseMarkupCache($field) {
|
|
|
|
return (bool)$this->getID();
|
|
|
|
}
|
|
|
|
|
2013-02-15 16:47:14 +01:00
|
|
|
|
|
|
|
/* -( Policy Interface )--------------------------------------------------- */
|
|
|
|
|
|
|
|
|
|
|
|
public function getCapabilities() {
|
|
|
|
return array(
|
|
|
|
PhabricatorPolicyCapability::CAN_VIEW,
|
2017-03-02 21:46:17 +01:00
|
|
|
PhabricatorPolicyCapability::CAN_INTERACT,
|
2013-02-15 16:47:14 +01:00
|
|
|
PhabricatorPolicyCapability::CAN_EDIT,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getPolicy($capability) {
|
2013-09-25 22:44:45 +02:00
|
|
|
switch ($capability) {
|
|
|
|
case PhabricatorPolicyCapability::CAN_VIEW:
|
|
|
|
return $this->getViewPolicy();
|
2017-03-02 21:46:17 +01:00
|
|
|
case PhabricatorPolicyCapability::CAN_INTERACT:
|
|
|
|
if ($this->isLocked()) {
|
|
|
|
return PhabricatorPolicies::POLICY_NOONE;
|
|
|
|
} else {
|
2017-03-09 17:41:03 +01:00
|
|
|
return $this->getViewPolicy();
|
2017-03-02 21:46:17 +01:00
|
|
|
}
|
2013-09-25 22:44:45 +02:00
|
|
|
case PhabricatorPolicyCapability::CAN_EDIT:
|
|
|
|
return $this->getEditPolicy();
|
|
|
|
}
|
2013-02-15 16:47:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
public function hasAutomaticCapability($capability, PhabricatorUser $user) {
|
2013-09-25 22:44:45 +02:00
|
|
|
// The owner of a task can always view and edit it.
|
|
|
|
$owner_phid = $this->getOwnerPHID();
|
|
|
|
if ($owner_phid) {
|
|
|
|
$user_phid = $user->getPHID();
|
|
|
|
if ($user_phid == $owner_phid) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-15 16:47:14 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-09-27 17:43:41 +02:00
|
|
|
public function describeAutomaticCapability($capability) {
|
2014-07-23 02:03:09 +02:00
|
|
|
return pht('The owner of a task can always view and edit it.');
|
2013-09-27 17:43:41 +02:00
|
|
|
}
|
|
|
|
|
2013-02-19 02:44:45 +01:00
|
|
|
|
|
|
|
/* -( PhabricatorTokenReceiverInterface )---------------------------------- */
|
|
|
|
|
2014-03-25 21:47:42 +01:00
|
|
|
|
2013-02-19 02:44:45 +01:00
|
|
|
public function getUsersToNotifyOfTokenGiven() {
|
|
|
|
// Sort of ambiguous who this was intended for; just let them both know.
|
|
|
|
return array_filter(
|
|
|
|
array_unique(
|
|
|
|
array(
|
|
|
|
$this->getAuthorPHID(),
|
|
|
|
$this->getOwnerPHID(),
|
|
|
|
)));
|
|
|
|
}
|
|
|
|
|
2013-09-17 00:58:35 +02:00
|
|
|
|
|
|
|
/* -( PhabricatorCustomFieldInterface )------------------------------------ */
|
|
|
|
|
|
|
|
|
|
|
|
public function getCustomFieldSpecificationForRole($role) {
|
|
|
|
return PhabricatorEnv::getEnvConfig('maniphest.fields');
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getCustomFieldBaseClass() {
|
|
|
|
return 'ManiphestCustomField';
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getCustomFields() {
|
|
|
|
return $this->assertAttached($this->customFields);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function attachCustomFields(PhabricatorCustomFieldAttachment $fields) {
|
|
|
|
$this->customFields = $fields;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2014-05-05 19:55:19 +02:00
|
|
|
|
2014-07-21 15:59:22 +02:00
|
|
|
/* -( PhabricatorDestructibleInterface )----------------------------------- */
|
2014-05-05 19:55:19 +02:00
|
|
|
|
|
|
|
|
|
|
|
public function destroyObjectPermanently(
|
|
|
|
PhabricatorDestructionEngine $engine) {
|
|
|
|
|
|
|
|
$this->openTransaction();
|
2015-06-02 14:12:45 +02:00
|
|
|
$this->delete();
|
2014-05-05 19:55:19 +02:00
|
|
|
$this->saveTransaction();
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
|
|
|
/* -( PhabricatorApplicationTransactionInterface )------------------------- */
|
|
|
|
|
|
|
|
|
|
|
|
public function getApplicationTransactionEditor() {
|
|
|
|
return new ManiphestTransactionEditor();
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getApplicationTransactionObject() {
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getApplicationTransactionTemplate() {
|
|
|
|
return new ManiphestTransaction();
|
|
|
|
}
|
|
|
|
|
2014-12-04 22:58:52 +01:00
|
|
|
public function willRenderTimeline(
|
|
|
|
PhabricatorApplicationTransactionView $timeline,
|
|
|
|
AphrontRequest $request) {
|
|
|
|
|
|
|
|
return $timeline;
|
|
|
|
}
|
|
|
|
|
2015-06-11 00:53:04 +02:00
|
|
|
|
|
|
|
/* -( PhabricatorSpacesInterface )----------------------------------------- */
|
|
|
|
|
|
|
|
|
|
|
|
public function getSpacePHID() {
|
|
|
|
return $this->spacePHID;
|
|
|
|
}
|
|
|
|
|
2015-12-13 11:31:09 +01:00
|
|
|
|
|
|
|
/* -( PhabricatorConduitResultInterface )---------------------------------- */
|
|
|
|
|
|
|
|
|
|
|
|
public function getFieldSpecificationsForConduit() {
|
|
|
|
return array(
|
2015-12-14 15:42:21 +01:00
|
|
|
id(new PhabricatorConduitSearchFieldSpecification())
|
|
|
|
->setKey('title')
|
|
|
|
->setType('string')
|
|
|
|
->setDescription(pht('The title of the task.')),
|
2017-04-03 02:12:18 +02:00
|
|
|
id(new PhabricatorConduitSearchFieldSpecification())
|
|
|
|
->setKey('description')
|
|
|
|
->setType('remarkup')
|
|
|
|
->setDescription(pht('The task description.')),
|
2015-12-14 15:42:21 +01:00
|
|
|
id(new PhabricatorConduitSearchFieldSpecification())
|
|
|
|
->setKey('authorPHID')
|
|
|
|
->setType('phid')
|
|
|
|
->setDescription(pht('Original task author.')),
|
|
|
|
id(new PhabricatorConduitSearchFieldSpecification())
|
|
|
|
->setKey('ownerPHID')
|
|
|
|
->setType('phid?')
|
|
|
|
->setDescription(pht('Current task owner, if task is assigned.')),
|
|
|
|
id(new PhabricatorConduitSearchFieldSpecification())
|
|
|
|
->setKey('status')
|
2015-12-14 15:53:07 +01:00
|
|
|
->setType('map<string, wild>')
|
|
|
|
->setDescription(pht('Information about task status.')),
|
2015-12-14 15:42:21 +01:00
|
|
|
id(new PhabricatorConduitSearchFieldSpecification())
|
|
|
|
->setKey('priority')
|
2015-12-14 15:53:07 +01:00
|
|
|
->setType('map<string, wild>')
|
|
|
|
->setDescription(pht('Information about task priority.')),
|
2016-02-11 19:10:50 +01:00
|
|
|
id(new PhabricatorConduitSearchFieldSpecification())
|
|
|
|
->setKey('points')
|
|
|
|
->setType('points')
|
|
|
|
->setDescription(pht('Point value of the task.')),
|
2017-03-02 00:37:26 +01:00
|
|
|
id(new PhabricatorConduitSearchFieldSpecification())
|
|
|
|
->setKey('subtype')
|
|
|
|
->setType('string')
|
|
|
|
->setDescription(pht('Subtype of the task.')),
|
2015-12-13 11:31:09 +01:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getFieldValuesForConduit() {
|
2015-12-14 15:53:07 +01:00
|
|
|
$status_value = $this->getStatus();
|
|
|
|
$status_info = array(
|
|
|
|
'value' => $status_value,
|
|
|
|
'name' => ManiphestTaskStatus::getTaskStatusName($status_value),
|
|
|
|
'color' => ManiphestTaskStatus::getStatusColor($status_value),
|
|
|
|
);
|
|
|
|
|
|
|
|
$priority_value = (int)$this->getPriority();
|
|
|
|
$priority_info = array(
|
|
|
|
'value' => $priority_value,
|
|
|
|
'subpriority' => (double)$this->getSubpriority(),
|
|
|
|
'name' => ManiphestTaskPriority::getTaskPriorityName($priority_value),
|
|
|
|
'color' => ManiphestTaskPriority::getTaskPriorityColor($priority_value),
|
|
|
|
);
|
|
|
|
|
2015-12-13 11:31:09 +01:00
|
|
|
return array(
|
|
|
|
'name' => $this->getTitle(),
|
2017-04-03 02:12:18 +02:00
|
|
|
'description' => array(
|
|
|
|
'raw' => $this->getDescription(),
|
|
|
|
),
|
2015-12-13 11:31:09 +01:00
|
|
|
'authorPHID' => $this->getAuthorPHID(),
|
|
|
|
'ownerPHID' => $this->getOwnerPHID(),
|
2015-12-14 15:53:07 +01:00
|
|
|
'status' => $status_info,
|
|
|
|
'priority' => $priority_info,
|
2016-02-11 19:10:50 +01:00
|
|
|
'points' => $this->getPoints(),
|
2017-03-02 00:37:26 +01:00
|
|
|
'subtype' => $this->getSubtype(),
|
2015-12-13 11:31:09 +01:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2015-12-14 15:01:04 +01:00
|
|
|
public function getConduitSearchAttachments() {
|
Add a "columns" attachment to the maniphest.search API method
Summary:
Ref T12074. This allows callers to identify which columns an object appears in (currently, always tasks).
There are a few major cases:
- Object is in a normal column: we return column information.
- Object is in a proxy column (subproject or milestone). For example, when you look at the board for "Some Parent Project", the task might show up in a milestone column. I've chosen to not return anything in this case: you can figure out that the task is there by looking at the project structure, and this is kind of an internal artifact of the implementation and probably not useful to callers.
- Project does not have a workboard: we return nothing.
These seem fairly reasonable, I think?
Test Plan:
- Queried for tasks, using the "columns" attachment.
- Dragged a task across a board, querying it repeatedly. Got expected results for normal column (the column), subprojects with no board (nothing), milestones with no board (nothing) and mielstones/subprojects with a board (the column on //that// board, only, not the proxy column on the parent).
Reviewers: chad
Reviewed By: chad
Maniphest Tasks: T12074
Differential Revision: https://secure.phabricator.com/D17156
2017-01-08 21:12:12 +01:00
|
|
|
return array(
|
|
|
|
id(new PhabricatorBoardColumnsSearchEngineAttachment())
|
|
|
|
->setAttachmentKey('columns'),
|
|
|
|
);
|
2015-12-14 15:01:04 +01:00
|
|
|
}
|
|
|
|
|
2015-12-21 18:02:55 +01:00
|
|
|
|
|
|
|
/* -( PhabricatorFulltextInterface )--------------------------------------- */
|
|
|
|
|
|
|
|
|
|
|
|
public function newFulltextEngine() {
|
|
|
|
return new ManiphestTaskFulltextEngine();
|
|
|
|
}
|
|
|
|
|
2016-03-09 17:40:19 +01:00
|
|
|
|
|
|
|
/* -( DoorkeeperBridgedObjectInterface )----------------------------------- */
|
|
|
|
|
|
|
|
|
|
|
|
public function getBridgedObject() {
|
|
|
|
return $this->assertAttached($this->bridgedObject);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function attachBridgedObject(
|
|
|
|
DoorkeeperExternalObject $object = null) {
|
|
|
|
$this->bridgedObject = $object;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2017-03-02 00:37:26 +01:00
|
|
|
|
|
|
|
/* -( PhabricatorEditEngineSubtypeInterface )------------------------------ */
|
|
|
|
|
|
|
|
|
|
|
|
public function getEditEngineSubtype() {
|
|
|
|
return $this->getSubtype();
|
|
|
|
}
|
|
|
|
|
|
|
|
public function setEditEngineSubtype($value) {
|
|
|
|
return $this->setSubtype($value);
|
|
|
|
}
|
|
|
|
|
2017-03-02 01:04:25 +01:00
|
|
|
public function newEditEngineSubtypeMap() {
|
|
|
|
$config = PhabricatorEnv::getEnvConfig('maniphest.subtypes');
|
|
|
|
return PhabricatorEditEngineSubtype::newSubtypeMap($config);
|
|
|
|
}
|
|
|
|
|
2017-03-02 21:46:17 +01:00
|
|
|
|
|
|
|
/* -( PhabricatorEditEngineLockableInterface )----------------------------- */
|
|
|
|
|
|
|
|
|
|
|
|
public function newEditEngineLock() {
|
|
|
|
return new ManiphestTaskEditEngineLock();
|
|
|
|
}
|
|
|
|
|
2011-02-08 19:53:59 +01:00
|
|
|
}
|