Page MenuHomestyx hydra

No OneTemporary

diff --git a/src/applications/maniphest/constants/ManiphestTaskPriority.php b/src/applications/maniphest/constants/ManiphestTaskPriority.php
index 8bc682f7e4..86c7adbcb7 100644
--- a/src/applications/maniphest/constants/ManiphestTaskPriority.php
+++ b/src/applications/maniphest/constants/ManiphestTaskPriority.php
@@ -1,197 +1,249 @@
<?php
final class ManiphestTaskPriority extends ManiphestConstants {
const UNKNOWN_PRIORITY_KEYWORD = '!!unknown!!';
/**
* Get the priorities and their full descriptions.
*
* @return map Priorities to descriptions.
*/
public static function getTaskPriorityMap() {
$map = self::getConfig();
foreach ($map as $key => $spec) {
$map[$key] = idx($spec, 'name', $key);
}
return $map;
}
/**
* Get the priorities and their command keywords.
*
* @return map Priorities to lists of command keywords.
*/
public static function getTaskPriorityKeywordsMap() {
$map = self::getConfig();
foreach ($map as $key => $spec) {
$words = idx($spec, 'keywords', array());
if (!is_array($words)) {
$words = array($words);
}
foreach ($words as $word_key => $word) {
$words[$word_key] = phutil_utf8_strtolower($word);
}
$words = array_unique($words);
$map[$key] = $words;
}
return $map;
}
+ /**
+ * Get the canonical keyword for a given priority constant.
+ *
+ * @return string|null Keyword, or `null` if no keyword is configured.
+ */
+ public static function getKeywordForTaskPriority($priority) {
+ $map = self::getConfig();
+
+ $spec = idx($map, $priority);
+ if (!$spec) {
+ return null;
+ }
+
+ $keywords = idx($spec, 'keywords');
+ if (!$keywords) {
+ return null;
+ }
+
+ return head($keywords);
+ }
+
+
+ /**
+ * Get a map of supported alternate names for each priority.
+ *
+ * Keys are aliases, like "wish" and "wishlist". Values are canonical
+ * priority keywords, like "wishlist".
+ *
+ * @return map<string, string> Map of aliases to canonical priority keywords.
+ */
+ public static function getTaskPriorityAliasMap() {
+ $keyword_map = self::getTaskPriorityKeywordsMap();
+
+ $result = array();
+ foreach ($keyword_map as $key => $keywords) {
+ $target = self::getKeywordForTaskPriority($key);
+ if ($target === null) {
+ continue;
+ }
+
+ // NOTE: Include the raw priority value, like "25", in the list of
+ // aliases. This supports legacy sources like saved EditEngine forms.
+ $result[$key] = $target;
+
+ foreach ($keywords as $keyword) {
+ $result[$keyword] = $target;
+ }
+ }
+
+ return $result;
+ }
+
/**
* Get the priorities and their related short (one-word) descriptions.
*
* @return map Priorities to short descriptions.
*/
public static function getShortNameMap() {
$map = self::getConfig();
foreach ($map as $key => $spec) {
$map[$key] = idx($spec, 'short', idx($spec, 'name', $key));
}
return $map;
}
/**
* Get a map from priority constants to their colors.
*
* @return map<int, string> Priorities to colors.
*/
public static function getColorMap() {
$map = self::getConfig();
foreach ($map as $key => $spec) {
$map[$key] = idx($spec, 'color', 'grey');
}
return $map;
}
/**
* Return the default priority for this instance of Phabricator.
*
* @return int The value of the default priority constant.
*/
public static function getDefaultPriority() {
return PhabricatorEnv::getEnvConfig('maniphest.default-priority');
}
/**
* Retrieve the full name of the priority level provided.
*
* @param int A priority level.
* @return string The priority name if the level is a valid one.
*/
public static function getTaskPriorityName($priority) {
return idx(self::getTaskPriorityMap(), $priority, $priority);
}
/**
* Retrieve the color of the priority level given
*
* @param int A priority level.
* @return string The color of the priority if the level is valid,
* or black if it is not.
*/
public static function getTaskPriorityColor($priority) {
return idx(self::getColorMap(), $priority, 'black');
}
public static function getTaskPriorityIcon($priority) {
return 'fa-arrow-right';
}
public static function getTaskPriorityFromKeyword($keyword) {
$map = self::getTaskPriorityKeywordsMap();
foreach ($map as $priority => $keywords) {
if (in_array($keyword, $keywords)) {
return $priority;
}
}
return null;
}
public static function isDisabledPriority($priority) {
$config = idx(self::getConfig(), $priority, array());
return idx($config, 'disabled', false);
}
public static function getConfig() {
$config = PhabricatorEnv::getEnvConfig('maniphest.priorities');
krsort($config);
return $config;
}
private static function isValidPriorityKeyword($keyword) {
if (!strlen($keyword) || strlen($keyword) > 64) {
return false;
}
// Alphanumeric, but not exclusively numeric
if (!preg_match('/^(?![0-9]*$)[a-zA-Z0-9]+$/', $keyword)) {
return false;
}
return true;
}
public static function validateConfiguration($config) {
if (!is_array($config)) {
throw new Exception(
pht(
'Configuration is not valid. Maniphest priority configurations '.
'must be dictionaries.',
$config));
}
foreach ($config as $key => $value) {
if (!ctype_digit((string)$key)) {
throw new Exception(
pht(
'Key "%s" is not a valid priority constant. Priority constants '.
'must be nonnegative integers.',
$key));
}
if (!is_array($value)) {
throw new Exception(
pht(
'Value for key "%s" should be a dictionary.',
$key));
}
PhutilTypeSpec::checkMap(
$value,
array(
'name' => 'string',
'short' => 'optional string',
'color' => 'optional string',
'keywords' => 'list<string>',
'disabled' => 'optional bool',
));
$keywords = $value['keywords'];
foreach ($keywords as $keyword) {
if (!self::isValidPriorityKeyword($keyword)) {
throw new Exception(
pht(
'Key "%s" is not a valid priority keyword. Priority keywords '.
'must be 1-64 alphanumeric characters and cannot be '.
'exclusively digits. For example, "%s" or "%s" are '.
'reasonable choices.',
$keyword,
'low',
'critical'));
}
}
}
}
}
diff --git a/src/applications/maniphest/editor/ManiphestEditEngine.php b/src/applications/maniphest/editor/ManiphestEditEngine.php
index acd27fc908..9f5e647ca9 100644
--- a/src/applications/maniphest/editor/ManiphestEditEngine.php
+++ b/src/applications/maniphest/editor/ManiphestEditEngine.php
@@ -1,469 +1,472 @@
<?php
final class ManiphestEditEngine
extends PhabricatorEditEngine {
const ENGINECONST = 'maniphest.task';
public function getEngineName() {
return pht('Maniphest Tasks');
}
public function getSummaryHeader() {
return pht('Configure Maniphest Task Forms');
}
public function getSummaryText() {
return pht('Configure how users create and edit tasks.');
}
public function getEngineApplicationClass() {
return 'PhabricatorManiphestApplication';
}
public function isDefaultQuickCreateEngine() {
return true;
}
public function getQuickCreateOrderVector() {
return id(new PhutilSortVector())->addInt(100);
}
protected function newEditableObject() {
return ManiphestTask::initializeNewTask($this->getViewer());
}
protected function newObjectQuery() {
return id(new ManiphestTaskQuery());
}
protected function getObjectCreateTitleText($object) {
return pht('Create New Task');
}
protected function getObjectEditTitleText($object) {
return pht('Edit Task: %s', $object->getTitle());
}
protected function getObjectEditShortText($object) {
return $object->getMonogram();
}
protected function getObjectCreateShortText() {
return pht('Create Task');
}
protected function getObjectName() {
return pht('Task');
}
protected function getEditorURI() {
return $this->getApplication()->getApplicationURI('task/edit/');
}
protected function getCommentViewHeaderText($object) {
return pht('Weigh In');
}
protected function getCommentViewButtonText($object) {
return pht('Set Sail for Adventure');
}
protected function getObjectViewURI($object) {
return '/'.$object->getMonogram();
}
protected function buildCustomEditFields($object) {
$status_map = $this->getTaskStatusMap($object);
$priority_map = $this->getTaskPriorityMap($object);
+ $alias_map = ManiphestTaskPriority::getTaskPriorityAliasMap();
+
if ($object->isClosed()) {
$default_status = ManiphestTaskStatus::getDefaultStatus();
} else {
$default_status = ManiphestTaskStatus::getDefaultClosedStatus();
}
if ($object->getOwnerPHID()) {
$owner_value = array($object->getOwnerPHID());
} else {
$owner_value = array($this->getViewer()->getPHID());
}
$column_documentation = pht(<<<EODOCS
You can use this transaction type to create a task into a particular workboard
column, or move an existing task between columns.
The transaction value can be specified in several forms. Some are simpler but
less powerful, while others are more complex and more powerful.
The simplest valid value is a single column PHID:
```lang=json
"PHID-PCOL-1111"
```
This will move the task into that column, or create the task into that column
if you are creating a new task. If the task is currently on the board, it will
be moved out of any exclusive columns. If the task is not currently on the
board, it will be added to the board.
You can also perform multiple moves at the same time by passing a list of
PHIDs:
```lang=json
["PHID-PCOL-2222", "PHID-PCOL-3333"]
```
This is equivalent to performing each move individually.
The most complex and most powerful form uses a dictionary to provide additional
information about the move, including an optional specific position within the
column.
The target column should be identified as `columnPHID`, and you may select a
position by passing either `beforePHID` or `afterPHID`, specifying the PHID of
a task currently in the column that you want to move this task before or after:
```lang=json
[
{
"columnPHID": "PHID-PCOL-4444",
"beforePHID": "PHID-TASK-5555"
}
]
```
Note that this affects only the "natural" position of the task. The task
position when the board is sorted by some other attribute (like priority)
depends on that attribute value: change a task's priority to move it on
priority-sorted boards.
EODOCS
);
$column_map = $this->getColumnMap($object);
$fields = array(
id(new PhabricatorHandlesEditField())
->setKey('parent')
->setLabel(pht('Parent Task'))
->setDescription(pht('Task to make this a subtask of.'))
->setConduitDescription(pht('Create as a subtask of another task.'))
->setConduitTypeDescription(pht('PHID of the parent task.'))
->setAliases(array('parentPHID'))
->setTransactionType(ManiphestTaskParentTransaction::TRANSACTIONTYPE)
->setHandleParameterType(new ManiphestTaskListHTTPParameterType())
->setSingleValue(null)
->setIsReorderable(false)
->setIsDefaultable(false)
->setIsLockable(false),
id(new PhabricatorColumnsEditField())
->setKey('column')
->setLabel(pht('Column'))
->setDescription(pht('Create a task in a workboard column.'))
->setConduitDescription(
pht('Move a task to one or more workboard columns.'))
->setConduitTypeDescription(
pht('List of columns to move the task to.'))
->setConduitDocumentation($column_documentation)
->setAliases(array('columnPHID', 'columns', 'columnPHIDs'))
->setTransactionType(PhabricatorTransactions::TYPE_COLUMNS)
->setIsReorderable(false)
->setIsDefaultable(false)
->setIsLockable(false)
->setCommentActionLabel(pht('Move on Workboard'))
->setCommentActionOrder(2000)
->setColumnMap($column_map),
id(new PhabricatorTextEditField())
->setKey('title')
->setLabel(pht('Title'))
->setDescription(pht('Name of the task.'))
->setConduitDescription(pht('Rename the task.'))
->setConduitTypeDescription(pht('New task name.'))
->setTransactionType(ManiphestTaskTitleTransaction::TRANSACTIONTYPE)
->setIsRequired(true)
->setValue($object->getTitle()),
id(new PhabricatorUsersEditField())
->setKey('owner')
->setAliases(array('ownerPHID', 'assign', 'assigned'))
->setLabel(pht('Assigned To'))
->setDescription(pht('User who is responsible for the task.'))
->setConduitDescription(pht('Reassign the task.'))
->setConduitTypeDescription(
pht('New task owner, or `null` to unassign.'))
->setTransactionType(ManiphestTaskOwnerTransaction::TRANSACTIONTYPE)
->setIsCopyable(true)
->setSingleValue($object->getOwnerPHID())
->setCommentActionLabel(pht('Assign / Claim'))
->setCommentActionValue($owner_value),
id(new PhabricatorSelectEditField())
->setKey('status')
->setLabel(pht('Status'))
->setDescription(pht('Status of the task.'))
->setConduitDescription(pht('Change the task status.'))
->setConduitTypeDescription(pht('New task status constant.'))
->setTransactionType(ManiphestTaskStatusTransaction::TRANSACTIONTYPE)
->setIsCopyable(true)
->setValue($object->getStatus())
->setOptions($status_map)
->setCommentActionLabel(pht('Change Status'))
->setCommentActionValue($default_status),
id(new PhabricatorSelectEditField())
->setKey('priority')
->setLabel(pht('Priority'))
->setDescription(pht('Priority of the task.'))
->setConduitDescription(pht('Change the priority of the task.'))
->setConduitTypeDescription(pht('New task priority constant.'))
->setTransactionType(ManiphestTaskPriorityTransaction::TRANSACTIONTYPE)
->setIsCopyable(true)
->setValue($object->getPriorityKeyword())
->setOptions($priority_map)
+ ->setOptionAliases($alias_map)
->setCommentActionLabel(pht('Change Priority')),
);
if (ManiphestTaskPoints::getIsEnabled()) {
$points_label = ManiphestTaskPoints::getPointsLabel();
$action_label = ManiphestTaskPoints::getPointsActionLabel();
$fields[] = id(new PhabricatorPointsEditField())
->setKey('points')
->setLabel($points_label)
->setDescription(pht('Point value of the task.'))
->setConduitDescription(pht('Change the task point value.'))
->setConduitTypeDescription(pht('New task point value.'))
->setTransactionType(ManiphestTaskPointsTransaction::TRANSACTIONTYPE)
->setIsCopyable(true)
->setValue($object->getPoints())
->setCommentActionLabel($action_label);
}
$fields[] = id(new PhabricatorRemarkupEditField())
->setKey('description')
->setLabel(pht('Description'))
->setDescription(pht('Task description.'))
->setConduitDescription(pht('Update the task description.'))
->setConduitTypeDescription(pht('New task description.'))
->setTransactionType(ManiphestTaskDescriptionTransaction::TRANSACTIONTYPE)
->setValue($object->getDescription())
->setPreviewPanel(
id(new PHUIRemarkupPreviewPanel())
->setHeader(pht('Description Preview')));
return $fields;
}
private function getTaskStatusMap(ManiphestTask $task) {
$status_map = ManiphestTaskStatus::getTaskStatusMap();
$current_status = $task->getStatus();
// If the current status is something we don't recognize (maybe an older
// status which was deleted), put a dummy entry in the status map so that
// saving the form doesn't destroy any data by accident.
if (idx($status_map, $current_status) === null) {
$status_map[$current_status] = pht('<Unknown: %s>', $current_status);
}
$dup_status = ManiphestTaskStatus::getDuplicateStatus();
foreach ($status_map as $status => $status_name) {
// Always keep the task's current status.
if ($status == $current_status) {
continue;
}
// Don't allow tasks to be changed directly into "Closed, Duplicate"
// status. Instead, you have to merge them. See T4819.
if ($status == $dup_status) {
unset($status_map[$status]);
continue;
}
// Don't let new or existing tasks be moved into a disabled status.
if (ManiphestTaskStatus::isDisabledStatus($status)) {
unset($status_map[$status]);
continue;
}
}
return $status_map;
}
private function getTaskPriorityMap(ManiphestTask $task) {
$priority_map = ManiphestTaskPriority::getTaskPriorityMap();
$priority_keywords = ManiphestTaskPriority::getTaskPriorityKeywordsMap();
$current_priority = $task->getPriority();
$results = array();
foreach ($priority_map as $priority => $priority_name) {
$disabled = ManiphestTaskPriority::isDisabledPriority($priority);
if ($disabled && !($priority == $current_priority)) {
continue;
}
$keyword = head(idx($priority_keywords, $priority));
$results[$keyword] = $priority_name;
}
// If the current value isn't a legitimate one, put it in the dropdown
// anyway so saving the form doesn't cause any side effects.
if (idx($priority_map, $current_priority) === null) {
$results[ManiphestTaskPriority::UNKNOWN_PRIORITY_KEYWORD] = pht(
'<Unknown: %s>',
$current_priority);
}
return $results;
}
protected function newEditResponse(
AphrontRequest $request,
$object,
array $xactions) {
if ($request->isAjax()) {
// Reload the task to make sure we pick up the final task state.
$viewer = $this->getViewer();
$task = id(new ManiphestTaskQuery())
->setViewer($viewer)
->withIDs(array($object->getID()))
->needSubscriberPHIDs(true)
->needProjectPHIDs(true)
->executeOne();
switch ($request->getStr('responseType')) {
case 'card':
return $this->buildCardResponse($task);
default:
return $this->buildListResponse($task);
}
}
return parent::newEditResponse($request, $object, $xactions);
}
private function buildListResponse(ManiphestTask $task) {
$controller = $this->getController();
$payload = array(
'tasks' => $controller->renderSingleTask($task),
'data' => array(),
);
return id(new AphrontAjaxResponse())->setContent($payload);
}
private function buildCardResponse(ManiphestTask $task) {
$controller = $this->getController();
$request = $controller->getRequest();
$viewer = $request->getViewer();
$column_phid = $request->getStr('columnPHID');
$visible_phids = $request->getStrList('visiblePHIDs');
if (!$visible_phids) {
$visible_phids = array();
}
$column = id(new PhabricatorProjectColumnQuery())
->setViewer($viewer)
->withPHIDs(array($column_phid))
->executeOne();
if (!$column) {
return new Aphront404Response();
}
$board_phid = $column->getProjectPHID();
$object_phid = $task->getPHID();
return id(new PhabricatorBoardResponseEngine())
->setViewer($viewer)
->setBoardPHID($board_phid)
->setObjectPHID($object_phid)
->setVisiblePHIDs($visible_phids)
->buildResponse();
}
private function getColumnMap(ManiphestTask $task) {
$phid = $task->getPHID();
if (!$phid) {
return array();
}
$board_phids = PhabricatorEdgeQuery::loadDestinationPHIDs(
$phid,
PhabricatorProjectObjectHasProjectEdgeType::EDGECONST);
if (!$board_phids) {
return array();
}
$viewer = $this->getViewer();
$layout_engine = id(new PhabricatorBoardLayoutEngine())
->setViewer($viewer)
->setBoardPHIDs($board_phids)
->setObjectPHIDs(array($task->getPHID()))
->executeLayout();
$map = array();
foreach ($board_phids as $board_phid) {
$in_columns = $layout_engine->getObjectColumns($board_phid, $phid);
$in_columns = mpull($in_columns, null, 'getPHID');
$all_columns = $layout_engine->getColumns($board_phid);
if (!$all_columns) {
// This could be a project with no workboard, or a project the viewer
// does not have permission to see.
continue;
}
$board = head($all_columns)->getProject();
$options = array();
foreach ($all_columns as $column) {
$name = $column->getDisplayName();
$is_hidden = $column->isHidden();
$is_selected = isset($in_columns[$column->getPHID()]);
// Don't show hidden, subproject or milestone columns in this map
// unless the object is currently in the column.
$skip_column = ($is_hidden || $column->getProxyPHID());
if ($skip_column) {
if (!$is_selected) {
continue;
}
}
if ($is_hidden) {
$name = pht('(%s)', $name);
}
if ($is_selected) {
$name = pht("\xE2\x97\x8F %s", $name);
} else {
$name = pht("\xE2\x97\x8B %s", $name);
}
$option = array(
'key' => $column->getPHID(),
'label' => $name,
'selected' => (bool)$is_selected,
);
$options[] = $option;
}
$map[] = array(
'label' => $board->getDisplayName(),
'options' => $options,
);
}
$map = isort($map, 'label');
$map = array_values($map);
return $map;
}
}
diff --git a/src/applications/maniphest/storage/ManiphestTask.php b/src/applications/maniphest/storage/ManiphestTask.php
index 3b312fc9cc..d8a174bd0a 100644
--- a/src/applications/maniphest/storage/ManiphestTask.php
+++ b/src/applications/maniphest/storage/ManiphestTask.php
@@ -1,603 +1,606 @@
<?php
final class ManiphestTask extends ManiphestDAO
implements
PhabricatorSubscribableInterface,
PhabricatorMarkupInterface,
PhabricatorPolicyInterface,
PhabricatorTokenReceiverInterface,
PhabricatorFlaggableInterface,
PhabricatorMentionableInterface,
PhrequentTrackableInterface,
PhabricatorCustomFieldInterface,
PhabricatorDestructibleInterface,
PhabricatorApplicationTransactionInterface,
PhabricatorProjectInterface,
PhabricatorSpacesInterface,
PhabricatorConduitResultInterface,
PhabricatorFulltextInterface,
DoorkeeperBridgedObjectInterface,
PhabricatorEditEngineSubtypeInterface,
PhabricatorEditEngineLockableInterface {
const MARKUP_FIELD_DESCRIPTION = 'markup:desc';
protected $authorPHID;
protected $ownerPHID;
protected $status;
protected $priority;
protected $subpriority = 0;
protected $title = '';
protected $originalTitle = '';
protected $description = '';
protected $originalEmailSource;
protected $mailKey;
protected $viewPolicy = PhabricatorPolicies::POLICY_USER;
protected $editPolicy = PhabricatorPolicies::POLICY_USER;
protected $ownerOrdering;
protected $spacePHID;
protected $bridgedObjectPHID;
protected $properties = array();
protected $points;
protected $subtype;
private $subscriberPHIDs = self::ATTACHABLE;
private $groupByProjectPHID = self::ATTACHABLE;
private $customFields = self::ATTACHABLE;
private $edgeProjectPHIDs = self::ATTACHABLE;
private $bridgedObject = self::ATTACHABLE;
public static function initializeNewTask(PhabricatorUser $actor) {
$app = id(new PhabricatorApplicationQuery())
->setViewer($actor)
->withClasses(array('PhabricatorManiphestApplication'))
->executeOne();
$view_policy = $app->getPolicy(ManiphestDefaultViewCapability::CAPABILITY);
$edit_policy = $app->getPolicy(ManiphestDefaultEditCapability::CAPABILITY);
return id(new ManiphestTask())
->setStatus(ManiphestTaskStatus::getDefaultStatus())
->setPriority(ManiphestTaskPriority::getDefaultPriority())
->setAuthorPHID($actor->getPHID())
->setViewPolicy($view_policy)
->setEditPolicy($edit_policy)
->setSpacePHID($actor->getDefaultSpacePHID())
->setSubtype(PhabricatorEditEngineSubtype::SUBTYPE_DEFAULT)
->attachProjectPHIDs(array())
->attachSubscriberPHIDs(array());
}
protected function getConfiguration() {
return array(
self::CONFIG_AUX_PHID => true,
self::CONFIG_SERIALIZATION => array(
'properties' => self::SERIALIZATION_JSON,
),
self::CONFIG_COLUMN_SCHEMA => array(
'ownerPHID' => 'phid?',
'status' => 'text64',
'priority' => 'uint32',
'title' => 'sort',
'originalTitle' => 'text',
'description' => 'text',
'mailKey' => 'bytes20',
'ownerOrdering' => 'text64?',
'originalEmailSource' => 'text255?',
'subpriority' => 'double',
'points' => 'double?',
'bridgedObjectPHID' => 'phid?',
'subtype' => 'text64',
),
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'),
),
'key_title' => array(
'columns' => array('title(64)'),
),
'key_bridgedobject' => array(
'columns' => array('bridgedObjectPHID'),
'unique' => true,
),
'key_subtype' => array(
'columns' => array('subtype'),
),
),
) + parent::getConfiguration();
}
public function loadDependsOnTaskPHIDs() {
return PhabricatorEdgeQuery::loadDestinationPHIDs(
$this->getPHID(),
ManiphestTaskDependsOnTaskEdgeType::EDGECONST);
}
public function loadDependedOnByTaskPHIDs() {
return PhabricatorEdgeQuery::loadDestinationPHIDs(
$this->getPHID(),
ManiphestTaskDependedOnByTaskEdgeType::EDGECONST);
}
public function generatePHID() {
return PhabricatorPHID::generateNewPHID(ManiphestTaskPHIDType::TYPECONST);
}
public function getSubscriberPHIDs() {
return $this->assertAttached($this->subscriberPHIDs);
}
public function getProjectPHIDs() {
return $this->assertAttached($this->edgeProjectPHIDs);
}
public function attachProjectPHIDs(array $phids) {
$this->edgeProjectPHIDs = $phids;
return $this;
}
public function attachSubscriberPHIDs(array $phids) {
$this->subscriberPHIDs = $phids;
return $this;
}
public function setOwnerPHID($phid) {
$this->ownerPHID = nonempty($phid, null);
return $this;
}
public function setTitle($title) {
$this->title = $title;
if (!$this->getID()) {
$this->originalTitle = $title;
}
return $this;
}
public function getMonogram() {
return 'T'.$this->getID();
}
public function getURI() {
return '/'.$this->getMonogram();
}
public function attachGroupByProjectPHID($phid) {
$this->groupByProjectPHID = $phid;
return $this;
}
public function getGroupByProjectPHID() {
return $this->assertAttached($this->groupByProjectPHID);
}
public function save() {
if (!$this->mailKey) {
$this->mailKey = Filesystem::readRandomCharacters(20);
}
$result = parent::save();
return $result;
}
public function isClosed() {
return ManiphestTaskStatus::isClosedStatus($this->getStatus());
}
public function isLocked() {
return ManiphestTaskStatus::isLockedStatus($this->getStatus());
}
public function setProperty($key, $value) {
$this->properties[$key] = $value;
return $this;
}
public function getProperty($key, $default = null) {
return idx($this->properties, $key, $default);
}
public function getCoverImageFilePHID() {
return idx($this->properties, 'cover.filePHID');
}
public function getCoverImageThumbnailPHID() {
return idx($this->properties, 'cover.thumbnailPHID');
}
public function getWorkboardOrderVectors() {
return array(
PhabricatorProjectColumn::ORDER_PRIORITY => array(
(int)-$this->getPriority(),
(double)-$this->getSubpriority(),
(int)-$this->getID(),
),
);
}
public function getPriorityKeyword() {
$priority = $this->getPriority();
- $map = ManiphestTaskPriority::getTaskPriorityKeywordsMap();
- $default = array(ManiphestTaskPriority::UNKNOWN_PRIORITY_KEYWORD);
- $keywords = idx($map, $priority, $default);
- return head($keywords);
+
+ $keyword = ManiphestTaskPriority::getKeywordForTaskPriority($priority);
+ if ($keyword !== null) {
+ return $keyword;
+ }
+
+ return ManiphestTaskPriority::UNKNOWN_PRIORITY_KEYWORD;
}
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);
}
public function getWorkboardProperties() {
return array(
'status' => $this->getStatus(),
'points' => (double)$this->getPoints(),
);
}
/* -( PhabricatorSubscribableInterface )----------------------------------- */
public function isAutomaticallySubscribed($phid) {
return ($phid == $this->getOwnerPHID());
}
/* -( Markup Interface )--------------------------------------------------- */
/**
* @task markup
*/
public function getMarkupFieldKey($field) {
$content = $this->getMarkupText($field);
return PhabricatorMarkupEngine::digestRemarkupContent($this, $content);
}
/**
* @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();
}
/* -( Policy Interface )--------------------------------------------------- */
public function getCapabilities() {
return array(
PhabricatorPolicyCapability::CAN_VIEW,
PhabricatorPolicyCapability::CAN_INTERACT,
PhabricatorPolicyCapability::CAN_EDIT,
);
}
public function getPolicy($capability) {
switch ($capability) {
case PhabricatorPolicyCapability::CAN_VIEW:
return $this->getViewPolicy();
case PhabricatorPolicyCapability::CAN_INTERACT:
if ($this->isLocked()) {
return PhabricatorPolicies::POLICY_NOONE;
} else {
return $this->getViewPolicy();
}
case PhabricatorPolicyCapability::CAN_EDIT:
return $this->getEditPolicy();
}
}
public function hasAutomaticCapability($capability, PhabricatorUser $user) {
// 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;
}
}
return false;
}
public function describeAutomaticCapability($capability) {
return pht('The owner of a task can always view and edit it.');
}
/* -( PhabricatorTokenReceiverInterface )---------------------------------- */
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(),
)));
}
/* -( 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;
}
/* -( PhabricatorDestructibleInterface )----------------------------------- */
public function destroyObjectPermanently(
PhabricatorDestructionEngine $engine) {
$this->openTransaction();
$this->delete();
$this->saveTransaction();
}
/* -( PhabricatorApplicationTransactionInterface )------------------------- */
public function getApplicationTransactionEditor() {
return new ManiphestTransactionEditor();
}
public function getApplicationTransactionObject() {
return $this;
}
public function getApplicationTransactionTemplate() {
return new ManiphestTransaction();
}
public function willRenderTimeline(
PhabricatorApplicationTransactionView $timeline,
AphrontRequest $request) {
return $timeline;
}
/* -( PhabricatorSpacesInterface )----------------------------------------- */
public function getSpacePHID() {
return $this->spacePHID;
}
/* -( PhabricatorConduitResultInterface )---------------------------------- */
public function getFieldSpecificationsForConduit() {
return array(
id(new PhabricatorConduitSearchFieldSpecification())
->setKey('title')
->setType('string')
->setDescription(pht('The title of the task.')),
id(new PhabricatorConduitSearchFieldSpecification())
->setKey('description')
->setType('remarkup')
->setDescription(pht('The task description.')),
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')
->setType('map<string, wild>')
->setDescription(pht('Information about task status.')),
id(new PhabricatorConduitSearchFieldSpecification())
->setKey('priority')
->setType('map<string, wild>')
->setDescription(pht('Information about task priority.')),
id(new PhabricatorConduitSearchFieldSpecification())
->setKey('points')
->setType('points')
->setDescription(pht('Point value of the task.')),
id(new PhabricatorConduitSearchFieldSpecification())
->setKey('subtype')
->setType('string')
->setDescription(pht('Subtype of the task.')),
);
}
public function getFieldValuesForConduit() {
$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),
);
return array(
'name' => $this->getTitle(),
'description' => array(
'raw' => $this->getDescription(),
),
'authorPHID' => $this->getAuthorPHID(),
'ownerPHID' => $this->getOwnerPHID(),
'status' => $status_info,
'priority' => $priority_info,
'points' => $this->getPoints(),
'subtype' => $this->getSubtype(),
);
}
public function getConduitSearchAttachments() {
return array(
id(new PhabricatorBoardColumnsSearchEngineAttachment())
->setAttachmentKey('columns'),
);
}
public function newSubtypeObject() {
$subtype_key = $this->getEditEngineSubtype();
$subtype_map = $this->newEditEngineSubtypeMap();
return idx($subtype_map, $subtype_key);
}
/* -( PhabricatorFulltextInterface )--------------------------------------- */
public function newFulltextEngine() {
return new ManiphestTaskFulltextEngine();
}
/* -( DoorkeeperBridgedObjectInterface )----------------------------------- */
public function getBridgedObject() {
return $this->assertAttached($this->bridgedObject);
}
public function attachBridgedObject(
DoorkeeperExternalObject $object = null) {
$this->bridgedObject = $object;
return $this;
}
/* -( PhabricatorEditEngineSubtypeInterface )------------------------------ */
public function getEditEngineSubtype() {
return $this->getSubtype();
}
public function setEditEngineSubtype($value) {
return $this->setSubtype($value);
}
public function newEditEngineSubtypeMap() {
$config = PhabricatorEnv::getEnvConfig('maniphest.subtypes');
return PhabricatorEditEngineSubtype::newSubtypeMap($config);
}
/* -( PhabricatorEditEngineLockableInterface )----------------------------- */
public function newEditEngineLock() {
return new ManiphestTaskEditEngineLock();
}
}
diff --git a/src/applications/transactions/editfield/PhabricatorSelectEditField.php b/src/applications/transactions/editfield/PhabricatorSelectEditField.php
index d8e99d610c..b72cafc5d1 100644
--- a/src/applications/transactions/editfield/PhabricatorSelectEditField.php
+++ b/src/applications/transactions/editfield/PhabricatorSelectEditField.php
@@ -1,38 +1,62 @@
<?php
final class PhabricatorSelectEditField
extends PhabricatorEditField {
private $options;
+ private $optionAliases = array();
public function setOptions(array $options) {
$this->options = $options;
return $this;
}
public function getOptions() {
if ($this->options === null) {
throw new PhutilInvalidStateException('setOptions');
}
return $this->options;
}
+ public function setOptionAliases(array $option_aliases) {
+ $this->optionAliases = $option_aliases;
+ return $this;
+ }
+
+ public function getOptionAliases() {
+ return $this->optionAliases;
+ }
+
+ protected function getValueForControl() {
+ $value = parent::getValueForControl();
+
+ $options = $this->getOptions();
+ if (!isset($options[$value])) {
+ $aliases = $this->getOptionAliases();
+ if (isset($aliases[$value])) {
+ $value = $aliases[$value];
+ }
+ }
+
+ return $value;
+ }
+
protected function newControl() {
return id(new AphrontFormSelectControl())
->setOptions($this->getOptions());
}
protected function newHTTPParameterType() {
return new AphrontSelectHTTPParameterType();
}
protected function newCommentAction() {
return id(new PhabricatorEditEngineSelectCommentAction())
->setOptions($this->getOptions());
}
protected function newConduitParameterType() {
return new ConduitStringParameterType();
}
}

File Metadata

Mime Type
text/x-diff
Expires
Mon, Jul 28, 3:13 AM (1 w, 22 h ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
186383
Default Alt Text
(41 KB)

Event Timeline