2011-02-08 19:53:59 +01:00
|
|
|
<?php
|
|
|
|
|
|
|
|
/*
|
2012-03-14 00:21:04 +01:00
|
|
|
* Copyright 2012 Facebook, Inc.
|
2011-02-08 19:53:59 +01:00
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
|
|
|
|
2011-07-04 22:04:22 +02:00
|
|
|
/**
|
|
|
|
* @group maniphest
|
|
|
|
*/
|
2012-03-14 00:21:04 +01:00
|
|
|
final class ManiphestTask extends ManiphestDAO {
|
2011-02-08 19:53:59 +01:00
|
|
|
|
|
|
|
protected $phid;
|
|
|
|
protected $authorPHID;
|
|
|
|
protected $ownerPHID;
|
2011-02-21 05:08:16 +01:00
|
|
|
protected $ccPHIDs = array();
|
2011-02-08 19:53:59 +01:00
|
|
|
|
|
|
|
protected $status;
|
|
|
|
protected $priority;
|
2012-04-02 21:12:04 +02:00
|
|
|
protected $subpriority;
|
2011-02-08 19:53:59 +01:00
|
|
|
|
|
|
|
protected $title;
|
2012-06-14 05:52:10 +02:00
|
|
|
protected $originalTitle;
|
2011-02-08 19:53:59 +01:00
|
|
|
protected $description;
|
2011-10-14 22:11:58 +02:00
|
|
|
protected $originalEmailSource;
|
2011-05-05 08:09:42 +02:00
|
|
|
protected $mailKey;
|
|
|
|
|
2011-02-17 23:32:01 +01:00
|
|
|
protected $attached = array();
|
2011-02-21 05:08:16 +01:00
|
|
|
protected $projectPHIDs = array();
|
2011-06-30 01:16:33 +02:00
|
|
|
private $projectsNeedUpdate;
|
2011-07-07 19:24:49 +02:00
|
|
|
private $subscribersNeedUpdate;
|
2011-02-08 19:53:59 +01: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;
|
|
|
|
|
2011-12-24 04:03:28 +01:00
|
|
|
private $auxiliaryAttributes;
|
|
|
|
private $auxiliaryDirty = array();
|
|
|
|
|
2011-02-08 19:53:59 +01:00
|
|
|
public function getConfiguration() {
|
|
|
|
return array(
|
|
|
|
self::CONFIG_AUX_PHID => true,
|
|
|
|
self::CONFIG_SERIALIZATION => array(
|
|
|
|
'ccPHIDs' => self::SERIALIZATION_JSON,
|
2011-02-17 23:32:01 +01:00
|
|
|
'attached' => self::SERIALIZATION_JSON,
|
2011-02-21 05:08:16 +01:00
|
|
|
'projectPHIDs' => self::SERIALIZATION_JSON,
|
2011-02-08 19:53:59 +01:00
|
|
|
),
|
|
|
|
) + parent::getConfiguration();
|
|
|
|
}
|
|
|
|
|
2011-02-17 23:32:01 +01:00
|
|
|
public function getAttachedPHIDs($type) {
|
|
|
|
return array_keys(idx($this->attached, $type, array()));
|
|
|
|
}
|
|
|
|
|
2011-02-08 19:53:59 +01:00
|
|
|
public function generatePHID() {
|
2011-03-03 03:58:21 +01:00
|
|
|
return PhabricatorPHID::generateNewPHID(
|
|
|
|
PhabricatorPHIDConstants::PHID_TYPE_TASK);
|
2011-02-08 19:53:59 +01:00
|
|
|
}
|
|
|
|
|
2011-02-09 21:47:24 +01:00
|
|
|
public function getCCPHIDs() {
|
2011-11-16 18:21:11 +01:00
|
|
|
return array_values(nonempty($this->ccPHIDs, array()));
|
2011-02-09 21:47:24 +01:00
|
|
|
}
|
|
|
|
|
2011-06-30 01:16:33 +02:00
|
|
|
public function setProjectPHIDs(array $phids) {
|
2011-11-16 18:21:11 +01:00
|
|
|
$this->projectPHIDs = array_values($phids);
|
2011-06-30 01:16:33 +02:00
|
|
|
$this->projectsNeedUpdate = true;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2011-11-16 18:21:11 +01:00
|
|
|
public function getProjectPHIDs() {
|
|
|
|
return array_values(nonempty($this->projectPHIDs, array()));
|
|
|
|
}
|
|
|
|
|
2011-07-07 19:24:49 +02:00
|
|
|
public function setCCPHIDs(array $phids) {
|
2011-11-16 18:21:11 +01:00
|
|
|
$this->ccPHIDs = array_values($phids);
|
2011-07-07 19:24:49 +02:00
|
|
|
$this->subscribersNeedUpdate = true;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function setOwnerPHID($phid) {
|
|
|
|
$this->ownerPHID = $phid;
|
|
|
|
$this->subscribersNeedUpdate = true;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2011-12-24 04:03:28 +01:00
|
|
|
public function getAuxiliaryAttribute($key, $default = null) {
|
|
|
|
if ($this->auxiliaryAttributes === null) {
|
|
|
|
throw new Exception("Attach auxiliary attributes before getting them!");
|
|
|
|
}
|
|
|
|
return idx($this->auxiliaryAttributes, $key, $default);
|
2011-07-26 00:34:56 +02:00
|
|
|
}
|
|
|
|
|
2011-12-24 04:03:28 +01:00
|
|
|
public function setAuxiliaryAttribute($key, $val) {
|
|
|
|
if ($this->auxiliaryAttributes === null) {
|
|
|
|
throw new Exception("Attach auxiliary attributes before setting them!");
|
|
|
|
}
|
|
|
|
$this->auxiliaryAttributes[$key] = $val;
|
|
|
|
$this->auxiliaryDirty[$key] = true;
|
|
|
|
return $this;
|
2011-07-26 00:34:56 +02:00
|
|
|
}
|
|
|
|
|
2012-06-14 05:52:10 +02:00
|
|
|
public function setTitle($title) {
|
|
|
|
$this->title = $title;
|
|
|
|
if (!$this->getID()) {
|
|
|
|
$this->originalTitle = $title;
|
|
|
|
}
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2011-12-24 04:03:28 +01:00
|
|
|
public function attachAuxiliaryAttributes(array $attrs) {
|
|
|
|
if ($this->auxiliaryDirty) {
|
|
|
|
throw new Exception(
|
|
|
|
"This object has dirty attributes, you can not attach new attributes ".
|
|
|
|
"without writing or discarding the dirty attributes.");
|
2011-07-26 00:34:56 +02:00
|
|
|
}
|
2011-12-24 04:03:28 +01:00
|
|
|
$this->auxiliaryAttributes = $attrs;
|
|
|
|
return $this;
|
2011-07-26 00:34:56 +02:00
|
|
|
}
|
|
|
|
|
2011-12-24 04:03:28 +01:00
|
|
|
public function loadAndAttachAuxiliaryAttributes() {
|
|
|
|
if (!$this->getPHID()) {
|
|
|
|
$this->auxiliaryAttributes = array();
|
2012-04-03 21:11:51 +02:00
|
|
|
return $this;
|
2011-12-24 04:03:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
$storage = id(new ManiphestTaskAuxiliaryStorage())->loadAllWhere(
|
2011-07-26 00:34:56 +02:00
|
|
|
'taskPHID = %s',
|
|
|
|
$this->getPHID());
|
|
|
|
|
2011-12-24 04:03:28 +01:00
|
|
|
$this->auxiliaryAttributes = mpull($storage, 'getValue', 'getName');
|
|
|
|
|
|
|
|
return $this;
|
2011-07-26 00:34:56 +02:00
|
|
|
}
|
|
|
|
|
2011-12-24 04:03:28 +01:00
|
|
|
|
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();
|
|
|
|
|
|
|
|
if ($this->projectsNeedUpdate) {
|
|
|
|
// If we've changed the project PHIDs for this task, update the link
|
|
|
|
// table.
|
|
|
|
ManiphestTaskProject::updateTaskProjects($this);
|
|
|
|
$this->projectsNeedUpdate = false;
|
|
|
|
}
|
|
|
|
|
2011-07-07 19:24:49 +02:00
|
|
|
if ($this->subscribersNeedUpdate) {
|
|
|
|
// If we've changed the subscriber PHIDs for this task, update the link
|
|
|
|
// table.
|
|
|
|
ManiphestTaskSubscriber::updateTaskSubscribers($this);
|
|
|
|
$this->subscribersNeedUpdate = false;
|
|
|
|
}
|
|
|
|
|
2011-12-24 04:03:28 +01:00
|
|
|
if ($this->auxiliaryDirty) {
|
|
|
|
$this->writeAuxiliaryUpdates();
|
|
|
|
$this->auxiliaryDirty = array();
|
|
|
|
}
|
|
|
|
|
2011-06-30 01:16:33 +02:00
|
|
|
return $result;
|
2011-05-05 08:09:42 +02:00
|
|
|
}
|
|
|
|
|
2011-12-24 04:03:28 +01:00
|
|
|
private function writeAuxiliaryUpdates() {
|
|
|
|
$table = new ManiphestTaskAuxiliaryStorage();
|
|
|
|
$conn_w = $table->establishConnection('w');
|
|
|
|
$update = array();
|
|
|
|
$remove = array();
|
|
|
|
|
|
|
|
foreach ($this->auxiliaryDirty as $key => $dirty) {
|
|
|
|
$value = $this->getAuxiliaryAttribute($key);
|
|
|
|
if ($value === null) {
|
|
|
|
$remove[$key] = true;
|
|
|
|
} else {
|
|
|
|
$update[$key] = $value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($remove) {
|
|
|
|
queryfx(
|
|
|
|
$conn_w,
|
|
|
|
'DELETE FROM %T WHERE taskPHID = %s AND name IN (%Ls)',
|
|
|
|
$table->getTableName(),
|
|
|
|
$this->getPHID(),
|
|
|
|
array_keys($remove));
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($update) {
|
|
|
|
$sql = array();
|
|
|
|
foreach ($update as $key => $val) {
|
|
|
|
$sql[] = qsprintf(
|
|
|
|
$conn_w,
|
|
|
|
'(%s, %s, %s)',
|
|
|
|
$this->getPHID(),
|
|
|
|
$key,
|
|
|
|
$val);
|
|
|
|
}
|
|
|
|
queryfx(
|
|
|
|
$conn_w,
|
|
|
|
'INSERT INTO %T (taskPHID, name, value) VALUES %Q
|
|
|
|
ON DUPLICATE KEY UPDATE value = VALUES(value)',
|
|
|
|
$table->getTableName(),
|
|
|
|
implode(', ', $sql));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-08 19:53:59 +01:00
|
|
|
}
|