1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-10 08:52:39 +01:00

Remove vestigal AuxiliaryField code from Maniphest

Summary: Gets rid of as much of this as possible. We'll batch handles and remarkup again some day, but after ApplicationTransactions.

Test Plan: Edited, viewed, and checked email for custom field edits.

Reviewers: btrahan

Reviewed By: btrahan

CC: aran

Differential Revision: https://secure.phabricator.com/D7037
This commit is contained in:
epriestley 2013-09-19 11:56:30 -07:00
parent 0558d53273
commit 5251e2f14d
7 changed files with 9 additions and 732 deletions

View file

@ -685,7 +685,6 @@ phutil_register_library_map(array(
'LiskMigrationIterator' => 'infrastructure/storage/lisk/LiskMigrationIterator.php',
'LiskRawMigrationIterator' => 'infrastructure/storage/lisk/LiskRawMigrationIterator.php',
'ManiphestAction' => 'applications/maniphest/constants/ManiphestAction.php',
'ManiphestAuxiliaryFieldDefaultSpecification' => 'applications/maniphest/auxiliaryfield/ManiphestAuxiliaryFieldDefaultSpecification.php',
'ManiphestAuxiliaryFieldSpecification' => 'applications/maniphest/auxiliaryfield/ManiphestAuxiliaryFieldSpecification.php',
'ManiphestBatchEditController' => 'applications/maniphest/controller/ManiphestBatchEditController.php',
'ManiphestConfiguredCustomField' => 'applications/maniphest/field/ManiphestConfiguredCustomField.php',
@ -2759,12 +2758,6 @@ phutil_register_library_map(array(
'LiskMigrationIterator' => 'PhutilBufferedIterator',
'LiskRawMigrationIterator' => 'PhutilBufferedIterator',
'ManiphestAction' => 'ManiphestConstants',
'ManiphestAuxiliaryFieldDefaultSpecification' => 'ManiphestAuxiliaryFieldSpecification',
'ManiphestAuxiliaryFieldSpecification' =>
array(
0 => 'ManiphestCustomField',
1 => 'PhabricatorMarkupInterface',
),
'ManiphestBatchEditController' => 'ManiphestController',
'ManiphestConfiguredCustomField' =>
array(

View file

@ -1,463 +0,0 @@
<?php
/**
* @group maniphest
*/
class ManiphestAuxiliaryFieldDefaultSpecification
extends ManiphestAuxiliaryFieldSpecification {
private $required;
private $fieldType;
private $selectOptions;
private $checkboxLabel;
private $checkboxValue;
private $error;
private $shouldCopyWhenCreatingSimilarTask;
const TYPE_SELECT = 'select';
const TYPE_STRING = 'string';
const TYPE_INT = 'int';
const TYPE_BOOL = 'bool';
const TYPE_DATE = 'date';
const TYPE_REMARKUP = 'remarkup';
const TYPE_USER = 'user';
const TYPE_USERS = 'users';
const TYPE_HEADER = 'header';
public function createFields() {
return array();
}
public function getFieldType() {
return $this->fieldType;
}
public function setFieldType($val) {
$this->fieldType = $val;
return $this;
}
public function getError() {
return $this->error;
}
public function setError($val) {
$this->error = $val;
return $this;
}
public function getSelectOptions() {
return $this->selectOptions;
}
public function setSelectOptions($array) {
$this->selectOptions = $array;
return $this;
}
public function setRequired($bool) {
$this->required = $bool;
return $this;
}
public function isRequired() {
return $this->required;
}
public function setCheckboxLabel($checkbox_label) {
$this->checkboxLabel = $checkbox_label;
return $this;
}
public function getCheckboxLabel() {
return $this->checkboxLabel;
}
public function setCheckboxValue($checkbox_value) {
$this->checkboxValue = $checkbox_value;
return $this;
}
public function getCheckboxValue() {
return $this->checkboxValue;
}
public function renderEditControl() {
$control = null;
$type = $this->getFieldType();
switch ($type) {
case self::TYPE_INT:
$control = new AphrontFormTextControl();
break;
case self::TYPE_STRING:
$control = new AphrontFormTextControl();
break;
case self::TYPE_SELECT:
$control = new AphrontFormSelectControl();
$control->setOptions($this->getSelectOptions());
break;
case self::TYPE_BOOL:
$control = new AphrontFormCheckboxControl();
break;
case self::TYPE_DATE:
$control = new AphrontFormDateControl();
$control->setUser($this->getUser());
if (!$this->isRequired()) {
$control->setAllowNull(true);
}
break;
case self::TYPE_REMARKUP:
$control = new PhabricatorRemarkupControl();
$control->setUser($this->getUser());
break;
case self::TYPE_USER:
case self::TYPE_USERS:
$control = new AphrontFormTokenizerControl();
$control->setDatasource('/typeahead/common/users/');
if ($type == self::TYPE_USER) {
$control->setLimit(1);
}
break;
case self::TYPE_HEADER:
$control = new AphrontFormMarkupControl();
break;
default:
$label = $this->getLabel();
throw new Exception(
"Field type '{$type}' is not a valid type (for field '{$label}').");
break;
}
switch ($type) {
case self::TYPE_BOOL:
$control->addCheckbox(
'auxiliary['.$this->getAuxiliaryKey().']',
1,
$this->getCheckboxLabel(),
(bool)$this->getValue());
break;
case self::TYPE_DATE:
if ($this->getValue() > 0) {
$control->setValue($this->getValue());
}
$control->setName('auxiliary_date_'.$this->getAuxiliaryKey());
break;
case self::TYPE_USER:
case self::TYPE_USERS:
$control->setName('auxiliary_tokenizer_'.$this->getAuxiliaryKey());
$value = array();
foreach ($this->getValue() as $phid) {
$value[$phid] = $this->getHandle($phid)->getFullName();
}
$control->setValue($value);
break;
case self::TYPE_HEADER:
$control->setValue(
phutil_tag(
'h2',
array(
'class' => 'maniphest-auxiliary-header',
),
$this->getLabel()));
break;
default:
$control->setValue($this->getValue());
$control->setName('auxiliary['.$this->getAuxiliaryKey().']');
break;
}
switch ($type) {
case self::TYPE_HEADER:
break;
default:
$control->setLabel($this->getLabel());
$control->setCaption($this->getCaption());
$control->setError($this->getError());
break;
}
$stripped_auxiliary_key = preg_replace(
'/[\w\d\.\-\:]+/', '', $this->getAuxiliaryKey());
if (strlen($stripped_auxiliary_key)) {
$unique_key_chars = array_unique(str_split($stripped_auxiliary_key));
$unique_key_chars = implode(" ,", $unique_key_chars);
$control->setDisabled(true);
$control->setCaption(
"This control is not configured correctly, the key must only contain
( a-z, A-Z, 0-9, ., -, : ) but has ( {$unique_key_chars} ), so it can
not be rendered, go fix your config.");
}
return $control;
}
public function setValueFromRequest(AphrontRequest $request) {
$type = $this->getFieldType();
switch ($type) {
case self::TYPE_DATE:
$control = $this->renderEditControl();
$value = $control->readValueFromRequest($request);
break;
case self::TYPE_USER:
case self::TYPE_USERS:
$name = 'auxiliary_tokenizer_'.$this->getAuxiliaryKey();
$value = $request->getArr($name);
if ($type == self::TYPE_USER) {
$value = array_slice($value, 0, 1);
}
break;
default:
$aux_post_values = $request->getArr('auxiliary');
$value = idx($aux_post_values, $this->getAuxiliaryKey(), '');
break;
}
return $this->setValue($value);
}
public function getValueForStorage() {
switch ($this->getFieldType()) {
case self::TYPE_USER:
case self::TYPE_USERS:
return json_encode($this->getValue());
case self::TYPE_DATE:
return (int)$this->getValue();
default:
return $this->getValue();
}
}
public function setValueFromStorage($value) {
switch ($this->getFieldType()) {
case self::TYPE_USER:
case self::TYPE_USERS:
$value = json_decode($value, true);
if (!is_array($value)) {
$value = array();
}
break;
case self::TYPE_DATE:
$value = (int)$value;
$this->setDefaultValue($value);
break;
default:
break;
}
return $this->setValue($value);
}
public function validateApplicationTransactions(
PhabricatorApplicationTransactionEditor $editor,
$type,
array $xactions) {
$errors = parent::validateApplicationTransactions(
$editor,
$type,
$xactions);
$has_value = false;
$value = null;
foreach ($xactions as $xaction) {
$has_value = true;
$value = $xaction->getNewValue();
switch ($this->getFieldType()) {
case self::TYPE_INT:
if ($value && !is_numeric($value)) {
$errors[] = new PhabricatorApplicationTransactionValidationError(
$type,
pht('Invalid'),
pht('%s must be an integer value.', $this->getLabel()),
$xaction);
$this->setError(pht('Invalid'));
}
break;
case self::TYPE_DATE:
if ((int)$value <= 0 && $this->isRequired()) {
$errors[] = new PhabricatorApplicationTransactionValidationError(
$type,
pht('Invalid'),
pht('%s must be a valid date.', $this->getLabel()),
$xaction);
$this->setError(pht('Invalid'));
}
break;
}
}
if ($this->isRequired()) {
if (!$has_value) {
$value = $this->getOldValueForApplicationTransactions();
}
if (!$value) {
$errors[] = new PhabricatorApplicationTransactionValidationError(
$type,
pht('Required'),
pht('%s is required.', $this->getLabel()),
null);
$this->setError(pht('Required'));
}
}
return $errors;
}
public function setDefaultValue($value) {
switch ($this->getFieldType()) {
case self::TYPE_DATE:
$value = strtotime($value);
if ($value <= 0) {
$value = time();
}
$this->setValue($value);
break;
case self::TYPE_USER:
case self::TYPE_USERS:
if (!is_array($value)) {
$value = array();
} else {
$value = array_values($value);
}
$this->setValue($value);
break;
default:
$this->setValue((string)$value);
break;
}
}
public function getMarkupFields() {
switch ($this->getFieldType()) {
case self::TYPE_REMARKUP:
return array('default');
}
return parent::getMarkupFields();
}
public function renderForDetailView() {
switch ($this->getFieldType()) {
case self::TYPE_BOOL:
if ($this->getValue()) {
return $this->getCheckboxValue();
} else {
return null;
}
case self::TYPE_SELECT:
return idx($this->getSelectOptions(), $this->getValue());
case self::TYPE_DATE:
return phabricator_datetime($this->getValue(), $this->getUser());
case self::TYPE_REMARKUP:
return $this->getMarkupEngine()->getOutput(
$this,
'default');
case self::TYPE_USER:
case self::TYPE_USERS:
return $this->renderHandleList($this->getValue());
case self::TYPE_HEADER:
return phutil_tag('hr');
}
return parent::renderForDetailView();
}
public function getRequiredHandlePHIDs() {
switch ($this->getFieldType()) {
case self::TYPE_USER;
case self::TYPE_USERS:
return $this->getValue();
}
return parent::getRequiredHandlePHIDs();
}
protected function renderHandleList(array $phids) {
$links = array();
foreach ($phids as $phid) {
$links[] = $this->getHandle($phid)->renderLink();
}
return phutil_implode_html(', ', $links);
}
public function renderTransactionDescription(
ManiphestTransaction $transaction,
$target) {
$label = $this->getLabel();
$old = $transaction->getOldValue();
$new = $transaction->getNewValue();
switch ($this->getFieldType()) {
case self::TYPE_BOOL:
if ($new) {
$desc = "set field '{$label}' true";
} else {
$desc = "set field '{$label}' false";
}
break;
case self::TYPE_SELECT:
$old_display = idx($this->getSelectOptions(), $old);
$new_display = idx($this->getSelectOptions(), $new);
if ($old === null) {
$desc = "set field '{$label}' to '{$new_display}'";
} else {
$desc = "changed field '{$label}' ".
"from '{$old_display}' to '{$new_display}'";
}
break;
case self::TYPE_DATE:
// NOTE: Although it should be impossible to get bad data in these
// fields normally, users can change the type of an existing field and
// leave us with uninterpretable data in old transactions.
if ((int)$new <= 0) {
$new_display = "none";
} else {
$new_display = phabricator_datetime($new, $this->getUser());
}
if ($old === null) {
$desc = "set field '{$label}' to '{$new_display}'";
} else {
if ((int)$old <= 0) {
$old_display = "none";
} else {
$old_display = phabricator_datetime($old, $this->getUser());
}
$desc = "changed field '{$label}' ".
"from '{$old_display}' to '{$new_display}'";
}
break;
case self::TYPE_REMARKUP:
// TODO: After we get ApplicationTransactions, straighten this out.
$desc = "updated field '{$label}'";
break;
case self::TYPE_USER:
case self::TYPE_USERS:
// TODO: As above, this is a mess that should get straightened out,
// but it will be easier after T2217.
$desc = "updated field '{$label}'";
break;
default:
if (!strlen($old)) {
if (!strlen($new)) {
return null;
}
$desc = "set field '{$label}' to '{$new}'";
} else {
$desc = "updated '{$label}' ".
"from '{$old}' to '{$new}'";
}
break;
}
return $desc;
}
public function setShouldCopyWhenCreatingSimilarTask($copy) {
$this->shouldCopyWhenCreatingSimilarTask = $copy;
return $this;
}
public function shouldCopyWhenCreatingSimilarTask() {
return $this->shouldCopyWhenCreatingSimilarTask;
}
}

View file

@ -1,188 +1,9 @@
<?php
/**
* @group maniphest
* TODO: Destroy after ApplicationTransactions.
*/
abstract class ManiphestAuxiliaryFieldSpecification
extends ManiphestCustomField
implements PhabricatorMarkupInterface {
const RENDER_TARGET_HTML = 'html';
const RENDER_TARGET_TEXT = 'text';
private $label;
private $auxiliaryKey;
private $caption;
private $value;
private $markupEngine;
private $handles;
// TODO: Remove; obsolete.
public function getTask() {
return $this->getObject();
}
// TODO: Remove; obsolete.
public function getUser() {
return $this->getViewer();
}
public function setLabel($val) {
$this->label = $val;
return $this;
}
public function getLabel() {
return $this->label;
}
public function setAuxiliaryKey($val) {
$this->auxiliaryKey = $val;
return $this;
}
public function getAuxiliaryKey() {
return 'std:maniphest:'.$this->auxiliaryKey;
}
public function setCaption($val) {
$this->caption = $val;
return $this;
}
public function getCaption() {
return $this->caption;
}
public function setValue($val) {
$this->value = $val;
return $this;
}
public function getValue() {
return $this->value;
}
public function isRequired() {
return false;
}
public function setType($val) {
$this->type = $val;
return $this;
}
public function getType() {
return $this->type;
}
public function renderForDetailView() {
return $this->getValue();
}
public function getRequiredHandlePHIDs() {
return array();
}
public function setHandles(array $handles) {
assert_instances_of($handles, 'PhabricatorObjectHandle');
$this->handles = array_select_keys(
$handles,
$this->getRequiredHandlePHIDs());
return $this;
}
public function getHandle($phid) {
if (empty($this->handles[$phid])) {
throw new Exception(
"Field is requesting a handle ('{$phid}') it did not require.");
}
return $this->handles[$phid];
}
public function getMarkupFields() {
return array();
}
public function setMarkupEngine(PhabricatorMarkupEngine $engine) {
$this->markupEngine = $engine;
return $this;
}
public function getMarkupEngine() {
return $this->markupEngine;
}
/* -( PhabricatorMarkupInterface )----------------------------------------- */
public function getMarkupFieldKey($field) {
$hash = PhabricatorHash::digestForIndex($this->getMarkupText($field));
return 'maux:'.$this->getAuxiliaryKey().':'.$hash;
}
public function newMarkupEngine($field) {
return PhabricatorMarkupEngine::newManiphestMarkupEngine();
}
public function getMarkupText($field) {
return $this->getValue();
}
public function didMarkupText(
$field,
$output,
PhutilMarkupEngine $engine) {
return phutil_tag(
'div',
array(
'class' => 'phabricator-remarkup',
),
$output);
}
public function shouldUseMarkupCache($field) {
return true;
}
/* -( API Compatibility With New Custom Fields )--------------------------- */
public function getFieldKey() {
return $this->getAuxiliaryKey();
}
public function shouldAppearInEditView() {
return true;
}
public function shouldAppearInPropertyView() {
return true;
}
public function shouldUseStorage() {
return true;
}
public function renderPropertyViewValue() {
$value = $this->renderForDetailView();
if (!strlen($value)) {
return null;
}
return $value;
}
public function renderPropertyViewLabel() {
return $this->getLabel();
}
public function readValueFromRequest(AphrontRequest $request) {
return $this->setValueFromRequest($request);
}
final class ManiphestAuxiliaryFieldSpecification {
public static function writeLegacyAuxiliaryUpdates(
ManiphestTask $task,

View file

@ -98,16 +98,9 @@ final class ManiphestTaskDetailController extends ManiphestController {
$phids = array_keys($phids);
$phids = array_merge(
$phids,
array_mergev(mpull($aux_fields, 'getRequiredHandlePHIDs')));
$this->loadHandles($phids);
$handles = $this->getLoadedHandles();
foreach ($aux_fields as $aux_field) {
$aux_field->setHandles($handles);
}
$context_bar = null;
@ -152,13 +145,6 @@ final class ManiphestTaskDetailController extends ManiphestController {
}
}
foreach ($aux_fields as $aux_field) {
foreach ($aux_field->getMarkupFields() as $markup_field) {
$engine->addObject($aux_field, $markup_field);
$aux_field->setMarkupEngine($engine);
}
}
$engine->process();
$transaction_types = ManiphestTransactionType::getTransactionTypeMap();

View file

@ -354,8 +354,7 @@ final class ManiphestTaskEditController extends ManiphestController {
$phids = array_merge(
array($task->getOwnerPHID()),
$task->getCCPHIDs(),
$task->getProjectPHIDs(),
array_mergev(mpull($aux_fields, 'getRequiredHandlePHIDs')));
$task->getProjectPHIDs());
if ($parent_task) {
$phids[] = $parent_task->getPHID();
@ -366,10 +365,6 @@ final class ManiphestTaskEditController extends ManiphestController {
$handles = $this->loadViewerHandles($phids);
foreach ($aux_fields as $aux_field) {
$aux_field->setHandles($handles);
}
$tvalues = mpull($handles, 'getFullName', 'getPHID');
$error_view = null;

View file

@ -28,70 +28,23 @@ abstract class ManiphestCustomField
return false;
}
// TODO: All of this is legacy junk.
public function getRequiredHandlePHIDs() {
return array();
}
public function setHandles(array $handles) {
}
/**
* Render a verb to appear in email titles when a transaction involving this
* field occurs. Specifically, Maniphest emails are formatted like this:
*
* [Maniphest] [Verb Here] TNNN: Task title here
* ^^^^^^^^^
*
* You should optionally return a title-case verb or short phrase like
* "Created", "Retitled", "Closed", "Resolved", "Commented On",
* "Lowered Priority", etc., which describes the transaction.
*
* @param ManiphestTransaction The transaction which needs description.
* @return string|null A short description of the transaction.
*/
public function renderTransactionEmailVerb(
ManiphestTransaction $transaction) {
return null;
}
/**
* Render a short description of the transaction, to appear above comments
* in the Maniphest transaction log. The string will be rendered after the
* acting user's name. Examples are:
*
* added a comment
* added alincoln to CC
* claimed this task
* created this task
* closed this task out of spite
*
* You should return a similar string, describing the transaction.
*
* Note the ##$target## parameter -- Maniphest needs to render transaction
* descriptions for different targets, like web and email. This method will
* be called with a ##ManiphestAuxiliaryFieldSpecification::RENDER_TARGET_*##
* constant describing the intended target.
*
* @param ManiphestTransaction The transaction which needs description.
* @param const Constant describing the rendering target (e.g., html or text).
* @return string|null Description of the transaction.
*/
public function renderTransactionDescription(
ManiphestTransaction $transaction,
$target) {
ManiphestTransaction $transaction) {
$old = $transaction->getOldValue();
$new = $transaction->getNewValue();
return pht(
'updated field %s from %s to %s',
$this->getFieldName(),
$old,
$new);
}
public function getMarkupFields() {
return array();
hsprintf('%s', $old),
hsprintf('%s', $new));
}
}

View file

@ -541,19 +541,11 @@ final class ManiphestTransactionDetailView extends ManiphestView {
$desc = null;
if ($aux_field) {
$use_field = $aux_field;
$desc = $aux_field->renderTransactionDescription($transaction);
} else {
$use_field = id(new ManiphestAuxiliaryFieldDefaultSpecification())
->setFieldType(
ManiphestAuxiliaryFieldDefaultSpecification::TYPE_STRING);
$desc = 'updated a field';
}
$desc = $use_field->renderTransactionDescription(
$transaction,
$this->forEmail
? ManiphestAuxiliaryFieldSpecification::RENDER_TARGET_TEXT
: ManiphestAuxiliaryFieldSpecification::RENDER_TARGET_HTML);
break;
default:
return array($type, ' brazenly '.$type."'d", $classes);