mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-23 14:00:56 +01:00
Generate file attachment transactions for explicit Remarkup attachments on common edit pathways
Summary: Ref T13603. On common edit pathways, extract explicit file attachments from Remarkup. These pathways are affected: - Objects that use EditEngine and expose a remarkup area via "RemarkupEditField". - Objects that use EditEngine to generate a comment area. This is the vast majority of pathways, but not entirely exhaustive. Test Plan: Created and commented on a task, explicitly attaching images. Saw images attach properly. Maniphest Tasks: T13603 Differential Revision: https://secure.phabricator.com/D21830
This commit is contained in:
parent
fee8297121
commit
42876de60d
10 changed files with 212 additions and 6 deletions
|
@ -239,6 +239,7 @@ phutil_register_library_map(array(
|
||||||
'AphrontIsolatedDatabaseConnection' => 'infrastructure/storage/connection/AphrontIsolatedDatabaseConnection.php',
|
'AphrontIsolatedDatabaseConnection' => 'infrastructure/storage/connection/AphrontIsolatedDatabaseConnection.php',
|
||||||
'AphrontIsolatedDatabaseConnectionTestCase' => 'infrastructure/storage/__tests__/AphrontIsolatedDatabaseConnectionTestCase.php',
|
'AphrontIsolatedDatabaseConnectionTestCase' => 'infrastructure/storage/__tests__/AphrontIsolatedDatabaseConnectionTestCase.php',
|
||||||
'AphrontIsolatedHTTPSink' => 'aphront/sink/AphrontIsolatedHTTPSink.php',
|
'AphrontIsolatedHTTPSink' => 'aphront/sink/AphrontIsolatedHTTPSink.php',
|
||||||
|
'AphrontJSONHTTPParameterType' => 'aphront/httpparametertype/AphrontJSONHTTPParameterType.php',
|
||||||
'AphrontJSONResponse' => 'aphront/response/AphrontJSONResponse.php',
|
'AphrontJSONResponse' => 'aphront/response/AphrontJSONResponse.php',
|
||||||
'AphrontJavelinView' => 'view/AphrontJavelinView.php',
|
'AphrontJavelinView' => 'view/AphrontJavelinView.php',
|
||||||
'AphrontKeyboardShortcutsAvailableView' => 'view/widget/AphrontKeyboardShortcutsAvailableView.php',
|
'AphrontKeyboardShortcutsAvailableView' => 'view/widget/AphrontKeyboardShortcutsAvailableView.php',
|
||||||
|
@ -272,6 +273,7 @@ phutil_register_library_map(array(
|
||||||
'AphrontRedirectResponse' => 'aphront/response/AphrontRedirectResponse.php',
|
'AphrontRedirectResponse' => 'aphront/response/AphrontRedirectResponse.php',
|
||||||
'AphrontRedirectResponseTestCase' => 'aphront/response/__tests__/AphrontRedirectResponseTestCase.php',
|
'AphrontRedirectResponseTestCase' => 'aphront/response/__tests__/AphrontRedirectResponseTestCase.php',
|
||||||
'AphrontReloadResponse' => 'aphront/response/AphrontReloadResponse.php',
|
'AphrontReloadResponse' => 'aphront/response/AphrontReloadResponse.php',
|
||||||
|
'AphrontRemarkupHTTPParameterType' => 'aphront/httpparametertype/AphrontRemarkupHTTPParameterType.php',
|
||||||
'AphrontRequest' => 'aphront/AphrontRequest.php',
|
'AphrontRequest' => 'aphront/AphrontRequest.php',
|
||||||
'AphrontRequestExceptionHandler' => 'aphront/handler/AphrontRequestExceptionHandler.php',
|
'AphrontRequestExceptionHandler' => 'aphront/handler/AphrontRequestExceptionHandler.php',
|
||||||
'AphrontRequestStream' => 'aphront/requeststream/AphrontRequestStream.php',
|
'AphrontRequestStream' => 'aphront/requeststream/AphrontRequestStream.php',
|
||||||
|
@ -5858,6 +5860,7 @@ phutil_register_library_map(array(
|
||||||
'QueryFormattingTestCase' => 'infrastructure/storage/__tests__/QueryFormattingTestCase.php',
|
'QueryFormattingTestCase' => 'infrastructure/storage/__tests__/QueryFormattingTestCase.php',
|
||||||
'QueryFuture' => 'infrastructure/storage/future/QueryFuture.php',
|
'QueryFuture' => 'infrastructure/storage/future/QueryFuture.php',
|
||||||
'RemarkupProcessConduitAPIMethod' => 'applications/remarkup/conduit/RemarkupProcessConduitAPIMethod.php',
|
'RemarkupProcessConduitAPIMethod' => 'applications/remarkup/conduit/RemarkupProcessConduitAPIMethod.php',
|
||||||
|
'RemarkupValue' => 'applications/remarkup/RemarkupValue.php',
|
||||||
'RepositoryConduitAPIMethod' => 'applications/repository/conduit/RepositoryConduitAPIMethod.php',
|
'RepositoryConduitAPIMethod' => 'applications/repository/conduit/RepositoryConduitAPIMethod.php',
|
||||||
'RepositoryQueryConduitAPIMethod' => 'applications/repository/conduit/RepositoryQueryConduitAPIMethod.php',
|
'RepositoryQueryConduitAPIMethod' => 'applications/repository/conduit/RepositoryQueryConduitAPIMethod.php',
|
||||||
'ShellLogView' => 'applications/harbormaster/view/ShellLogView.php',
|
'ShellLogView' => 'applications/harbormaster/view/ShellLogView.php',
|
||||||
|
@ -6207,6 +6210,7 @@ phutil_register_library_map(array(
|
||||||
'AphrontIsolatedDatabaseConnection' => 'AphrontDatabaseConnection',
|
'AphrontIsolatedDatabaseConnection' => 'AphrontDatabaseConnection',
|
||||||
'AphrontIsolatedDatabaseConnectionTestCase' => 'PhabricatorTestCase',
|
'AphrontIsolatedDatabaseConnectionTestCase' => 'PhabricatorTestCase',
|
||||||
'AphrontIsolatedHTTPSink' => 'AphrontHTTPSink',
|
'AphrontIsolatedHTTPSink' => 'AphrontHTTPSink',
|
||||||
|
'AphrontJSONHTTPParameterType' => 'AphrontHTTPParameterType',
|
||||||
'AphrontJSONResponse' => 'AphrontResponse',
|
'AphrontJSONResponse' => 'AphrontResponse',
|
||||||
'AphrontJavelinView' => 'AphrontView',
|
'AphrontJavelinView' => 'AphrontView',
|
||||||
'AphrontKeyboardShortcutsAvailableView' => 'AphrontView',
|
'AphrontKeyboardShortcutsAvailableView' => 'AphrontView',
|
||||||
|
@ -6243,6 +6247,7 @@ phutil_register_library_map(array(
|
||||||
'AphrontRedirectResponse' => 'AphrontResponse',
|
'AphrontRedirectResponse' => 'AphrontResponse',
|
||||||
'AphrontRedirectResponseTestCase' => 'PhabricatorTestCase',
|
'AphrontRedirectResponseTestCase' => 'PhabricatorTestCase',
|
||||||
'AphrontReloadResponse' => 'AphrontRedirectResponse',
|
'AphrontReloadResponse' => 'AphrontRedirectResponse',
|
||||||
|
'AphrontRemarkupHTTPParameterType' => 'AphrontHTTPParameterType',
|
||||||
'AphrontRequest' => 'Phobject',
|
'AphrontRequest' => 'Phobject',
|
||||||
'AphrontRequestExceptionHandler' => 'Phobject',
|
'AphrontRequestExceptionHandler' => 'Phobject',
|
||||||
'AphrontRequestStream' => 'Phobject',
|
'AphrontRequestStream' => 'Phobject',
|
||||||
|
@ -12747,6 +12752,7 @@ phutil_register_library_map(array(
|
||||||
'QueryFormattingTestCase' => 'PhabricatorTestCase',
|
'QueryFormattingTestCase' => 'PhabricatorTestCase',
|
||||||
'QueryFuture' => 'Future',
|
'QueryFuture' => 'Future',
|
||||||
'RemarkupProcessConduitAPIMethod' => 'ConduitAPIMethod',
|
'RemarkupProcessConduitAPIMethod' => 'ConduitAPIMethod',
|
||||||
|
'RemarkupValue' => 'Phobject',
|
||||||
'RepositoryConduitAPIMethod' => 'ConduitAPIMethod',
|
'RepositoryConduitAPIMethod' => 'ConduitAPIMethod',
|
||||||
'RepositoryQueryConduitAPIMethod' => 'RepositoryConduitAPIMethod',
|
'RepositoryQueryConduitAPIMethod' => 'RepositoryConduitAPIMethod',
|
||||||
'ShellLogView' => 'AphrontView',
|
'ShellLogView' => 'AphrontView',
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class AphrontJSONHTTPParameterType
|
||||||
|
extends AphrontHTTPParameterType {
|
||||||
|
|
||||||
|
protected function getParameterDefault() {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getParameterValue(AphrontRequest $request, $key) {
|
||||||
|
$str = $request->getStr($key);
|
||||||
|
return phutil_json_decode($str);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getParameterTypeName() {
|
||||||
|
return 'string (json object)';
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getParameterFormatDescriptions() {
|
||||||
|
return array(
|
||||||
|
pht('A JSON-encoded object.'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getParameterExamples() {
|
||||||
|
return array(
|
||||||
|
'v={...}',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class AphrontRemarkupHTTPParameterType
|
||||||
|
extends AphrontHTTPParameterType {
|
||||||
|
|
||||||
|
protected function getParameterDefault() {
|
||||||
|
return $this->newRemarkupValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getParameterValue(AphrontRequest $request, $key) {
|
||||||
|
$corpus_key = $key;
|
||||||
|
$corpus_type = new AphrontStringHTTPParameterType();
|
||||||
|
$corpus_value = $this->getValueWithType(
|
||||||
|
$corpus_type,
|
||||||
|
$request,
|
||||||
|
$corpus_key);
|
||||||
|
|
||||||
|
$metadata_key = $key.'_metadata';
|
||||||
|
$metadata_type = new AphrontJSONHTTPParameterType();
|
||||||
|
$metadata_value = $this->getValueWithType(
|
||||||
|
$metadata_type,
|
||||||
|
$request,
|
||||||
|
$metadata_key);
|
||||||
|
|
||||||
|
return $this->newRemarkupValue()
|
||||||
|
->setCorpus($corpus_value)
|
||||||
|
->setMetadata($metadata_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getParameterTypeName() {
|
||||||
|
return 'string (remarkup)';
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getParameterFormatDescriptions() {
|
||||||
|
return array(
|
||||||
|
pht('Remarkup text.'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getParameterExamples() {
|
||||||
|
return array(
|
||||||
|
'v=Lorem...',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function newRemarkupValue() {
|
||||||
|
return new RemarkupValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
27
src/applications/remarkup/RemarkupValue.php
Normal file
27
src/applications/remarkup/RemarkupValue.php
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class RemarkupValue
|
||||||
|
extends Phobject {
|
||||||
|
|
||||||
|
private $corpus;
|
||||||
|
private $metadata;
|
||||||
|
|
||||||
|
public function setCorpus($corpus) {
|
||||||
|
$this->corpus = $corpus;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCorpus() {
|
||||||
|
return $this->corpus;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setMetadata(array $metadata) {
|
||||||
|
$this->metadata = $metadata;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMetadata() {
|
||||||
|
return $this->metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -3,6 +3,7 @@
|
||||||
abstract class PhabricatorTransactionChange extends Phobject {
|
abstract class PhabricatorTransactionChange extends Phobject {
|
||||||
|
|
||||||
private $transaction;
|
private $transaction;
|
||||||
|
private $metadata = array();
|
||||||
private $oldValue;
|
private $oldValue;
|
||||||
private $newValue;
|
private $newValue;
|
||||||
|
|
||||||
|
@ -34,4 +35,13 @@ abstract class PhabricatorTransactionChange extends Phobject {
|
||||||
return $this->newValue;
|
return $this->newValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final public function setMetadata(array $metadata) {
|
||||||
|
$this->metadata = $metadata;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
final public function getMetadata() {
|
||||||
|
return $this->metadata;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2012,6 +2012,7 @@ abstract class PhabricatorEditEngine
|
||||||
if (strlen($comment_text) || !$xactions) {
|
if (strlen($comment_text) || !$xactions) {
|
||||||
$xactions[] = id(clone $template)
|
$xactions[] = id(clone $template)
|
||||||
->setTransactionType(PhabricatorTransactions::TYPE_COMMENT)
|
->setTransactionType(PhabricatorTransactions::TYPE_COMMENT)
|
||||||
|
->setMetadataValue('remarkup.control', $comment_metadata)
|
||||||
->attachComment(
|
->attachComment(
|
||||||
id(clone $comment_template)
|
id(clone $comment_template)
|
||||||
->setContent($comment_text));
|
->setContent($comment_text));
|
||||||
|
@ -2079,6 +2080,26 @@ abstract class PhabricatorEditEngine
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function newTransactionsFromRemarkupMetadata(
|
||||||
|
PhabricatorApplicationTransaction $template,
|
||||||
|
array $metadata) {
|
||||||
|
|
||||||
|
$xactions = array();
|
||||||
|
|
||||||
|
$attached_phids = idx($metadata, 'attachedFilePHIDs');
|
||||||
|
if (is_array($attached_phids) && $attached_phids) {
|
||||||
|
$attachment_map = array_fill_keys(
|
||||||
|
$attached_phids,
|
||||||
|
PhabricatorFileAttachment::MODE_ATTACH);
|
||||||
|
|
||||||
|
$xactions[] = id(clone $template)
|
||||||
|
->setTransactionType(PhabricatorTransactions::TYPE_FILE)
|
||||||
|
->setNewValue($attachment_map);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $xactions;
|
||||||
|
}
|
||||||
|
|
||||||
protected function newDraftEngine($object) {
|
protected function newDraftEngine($object) {
|
||||||
$viewer = $this->getViewer();
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,10 @@ final class PhabricatorRemarkupEditField
|
||||||
return new PhabricatorRemarkupControl();
|
return new PhabricatorRemarkupControl();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function newHTTPParameterType() {
|
||||||
|
return new AphrontRemarkupHTTPParameterType();
|
||||||
|
}
|
||||||
|
|
||||||
protected function newConduitParameterType() {
|
protected function newConduitParameterType() {
|
||||||
return new ConduitStringParameterType();
|
return new ConduitStringParameterType();
|
||||||
}
|
}
|
||||||
|
@ -15,4 +19,29 @@ final class PhabricatorRemarkupEditField
|
||||||
return new BulkRemarkupParameterType();
|
return new BulkRemarkupParameterType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getValueForTransaction() {
|
||||||
|
$value = $this->getValue();
|
||||||
|
|
||||||
|
if ($value instanceof RemarkupValue) {
|
||||||
|
$value = $value->getCorpus();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMetadata() {
|
||||||
|
$defaults = array();
|
||||||
|
|
||||||
|
$value = $this->getValue();
|
||||||
|
if ($value instanceof RemarkupValue) {
|
||||||
|
$defaults['remarkup.control'] = $value->getMetadata();
|
||||||
|
}
|
||||||
|
|
||||||
|
$metadata = parent::getMetadata();
|
||||||
|
$metadata = $metadata + $defaults;
|
||||||
|
|
||||||
|
return $metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2225,7 +2225,8 @@ abstract class PhabricatorApplicationTransactionEditor
|
||||||
|
|
||||||
$file_xaction = $this->newFileTransaction(
|
$file_xaction = $this->newFileTransaction(
|
||||||
$object,
|
$object,
|
||||||
$xactions);
|
$xactions,
|
||||||
|
$changes);
|
||||||
if ($file_xaction) {
|
if ($file_xaction) {
|
||||||
$xactions[] = $file_xaction;
|
$xactions[] = $file_xaction;
|
||||||
}
|
}
|
||||||
|
@ -2236,19 +2237,33 @@ abstract class PhabricatorApplicationTransactionEditor
|
||||||
|
|
||||||
private function newFileTransaction(
|
private function newFileTransaction(
|
||||||
PhabricatorLiskDAO $object,
|
PhabricatorLiskDAO $object,
|
||||||
array $xactions) {
|
array $xactions,
|
||||||
|
array $remarkup_changes) {
|
||||||
|
|
||||||
|
assert_instances_of(
|
||||||
|
$remarkup_changes,
|
||||||
|
'PhabricatorTransactionRemarkupChange');
|
||||||
|
|
||||||
$new_map = array();
|
$new_map = array();
|
||||||
|
|
||||||
$file_phids = $this->extractFilePHIDs($object, $xactions);
|
foreach ($remarkup_changes as $remarkup_change) {
|
||||||
if (!$file_phids) {
|
$metadata = $remarkup_change->getMetadata();
|
||||||
return null;
|
|
||||||
|
$attached_phids = idx($metadata, 'attachedFilePHIDs');
|
||||||
|
foreach ($attached_phids as $file_phid) {
|
||||||
|
$new_map[$file_phid] = PhabricatorFileAttachment::MODE_ATTACH;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$file_phids = $this->extractFilePHIDs($object, $xactions);
|
||||||
foreach ($file_phids as $file_phid) {
|
foreach ($file_phids as $file_phid) {
|
||||||
$new_map[$file_phid] = PhabricatorFileAttachment::MODE_ATTACH;
|
$new_map[$file_phid] = PhabricatorFileAttachment::MODE_ATTACH;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!$new_map) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
$xaction = $object->getApplicationTransactionTemplate()
|
$xaction = $object->getApplicationTransactionTemplate()
|
||||||
->setTransactionType(PhabricatorTransactions::TYPE_FILE)
|
->setTransactionType(PhabricatorTransactions::TYPE_FILE)
|
||||||
->setNewValue($new_map);
|
->setNewValue($new_map);
|
||||||
|
|
|
@ -244,6 +244,13 @@ abstract class PhabricatorApplicationTransaction
|
||||||
->setNewValue($new_value);
|
->setNewValue($new_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$metadata = $this->getMetadataValue('remarkup.control', array());
|
||||||
|
foreach ($changes as $change) {
|
||||||
|
if (!$change->getMetadata()) {
|
||||||
|
$change->setMetadata($metadata);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return $changes;
|
return $changes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
final class PhabricatorRemarkupControl extends AphrontFormTextAreaControl {
|
final class PhabricatorRemarkupControl
|
||||||
|
extends AphrontFormTextAreaControl {
|
||||||
|
|
||||||
private $disableMacro = false;
|
private $disableMacro = false;
|
||||||
private $disableFullScreen = false;
|
private $disableFullScreen = false;
|
||||||
|
@ -45,6 +46,15 @@ final class PhabricatorRemarkupControl extends AphrontFormTextAreaControl {
|
||||||
return $this->remarkupMetadata;
|
return $this->remarkupMetadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setValue($value) {
|
||||||
|
if ($value instanceof RemarkupValue) {
|
||||||
|
$this->setRemarkupMetadata($value->getMetadata());
|
||||||
|
$value = $value->getCorpus();
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent::setValue($value);
|
||||||
|
}
|
||||||
|
|
||||||
protected function renderInput() {
|
protected function renderInput() {
|
||||||
$id = $this->getID();
|
$id = $this->getID();
|
||||||
if (!$id) {
|
if (!$id) {
|
||||||
|
|
Loading…
Reference in a new issue