mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-01 19:22:42 +01:00
Add passthru to AphrontRequest
Summary: For transaction interfaces, I want to prompt the user when they take an action that has no effect, e.g.: Action Has No Effect You can not close this task, because someone else has already closed it. Do you want to post your comment anyway? [Cancel] [Post Comment] We already do this for Differential, but it's all hard-coded. T912 is an open task for fixing this for Maniphest. To do this in a general way, I want to embed the entire request in the dialog as hidden inputs, then add a "__continue__" key and resubmit the form. The endpoint will read this key the second time through and apply what effects it can (e.g., just post a comment). This adds a mechanism for getting all the request data, minus "magic" like __dialog__ and __csrf__. We need to jump through some hoops because of how PHP encodes arrays. Test Plan: Ran unit tests, built "no effect" dialogs on top of this. Reviewers: btrahan, vrana Reviewed By: btrahan CC: aran Maniphest Tasks: T912, T2104 Differential Revision: https://secure.phabricator.com/D4158
This commit is contained in:
parent
c970f7e89c
commit
4fe09a0ac7
2 changed files with 107 additions and 0 deletions
|
@ -17,6 +17,7 @@ final class AphrontRequest {
|
||||||
const TYPE_FORM = '__form__';
|
const TYPE_FORM = '__form__';
|
||||||
const TYPE_CONDUIT = '__conduit__';
|
const TYPE_CONDUIT = '__conduit__';
|
||||||
const TYPE_WORKFLOW = '__wflow__';
|
const TYPE_WORKFLOW = '__wflow__';
|
||||||
|
const TYPE_CONTINUE = '__continue__';
|
||||||
|
|
||||||
private $host;
|
private $host;
|
||||||
private $path;
|
private $path;
|
||||||
|
@ -334,4 +335,58 @@ final class AphrontRequest {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function isContinueRequest() {
|
||||||
|
return $this->isFormPost() && $this->getStr('__continue__');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get application request parameters in a flattened form suitable for
|
||||||
|
* inclusion in an HTTP request, excluding parameters with special meanings.
|
||||||
|
* This is primarily useful if you want to ask the user for more input and
|
||||||
|
* then resubmit their request.
|
||||||
|
*
|
||||||
|
* @return dict<string, string> Original request parameters.
|
||||||
|
*/
|
||||||
|
public function getPassthroughRequestParameters() {
|
||||||
|
$data = self::flattenData($this->getRequestData());
|
||||||
|
|
||||||
|
// Remove magic parameters like __dialog__ and __ajax__.
|
||||||
|
foreach ($data as $key => $value) {
|
||||||
|
if (strncmp($key, '__', 2)) {
|
||||||
|
unset($data[$key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flatten an array of key-value pairs (possibly including arrays as values)
|
||||||
|
* into a list of key-value pairs suitable for submitting via HTTP request
|
||||||
|
* (with arrays flattened).
|
||||||
|
*
|
||||||
|
* @param dict<string, wild> Data to flatten.
|
||||||
|
* @return dict<string, string> Flat data suitable for inclusion in an HTTP
|
||||||
|
* request.
|
||||||
|
*/
|
||||||
|
public static function flattenData(array $data) {
|
||||||
|
$result = array();
|
||||||
|
foreach ($data as $key => $value) {
|
||||||
|
if (is_array($value)) {
|
||||||
|
foreach (self::flattenData($value) as $fkey => $fvalue) {
|
||||||
|
$fkey = '['.preg_replace('/(?=\[)|$/', ']', $fkey, $limit = 1);
|
||||||
|
$result[$key.$fkey] = $fvalue;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$result[$key] = (string)$value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ksort($result);
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,4 +79,56 @@ final class AphrontRequestTestCase extends PhabricatorTestCase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testFlattenRequestData() {
|
||||||
|
$test_cases = array(
|
||||||
|
array(
|
||||||
|
'a' => 'a',
|
||||||
|
'b' => '1',
|
||||||
|
'c' => '',
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'a' => 'a',
|
||||||
|
'b' => '1',
|
||||||
|
'c' => '',
|
||||||
|
),
|
||||||
|
|
||||||
|
array(
|
||||||
|
'x' => array(
|
||||||
|
0 => 'a',
|
||||||
|
1 => 'b',
|
||||||
|
2 => 'c',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'x[0]' => 'a',
|
||||||
|
'x[1]' => 'b',
|
||||||
|
'x[2]' => 'c',
|
||||||
|
),
|
||||||
|
|
||||||
|
array(
|
||||||
|
'x' => array(
|
||||||
|
'y' => array(
|
||||||
|
'z' => array(
|
||||||
|
40 => 'A',
|
||||||
|
50 => 'B',
|
||||||
|
'C' => 60,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'x[y][z][40]' => 'A',
|
||||||
|
'x[y][z][50]' => 'B',
|
||||||
|
'x[y][z][C]' => '60',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
for ($ii = 0; $ii < count($test_cases); $ii += 2) {
|
||||||
|
$input = $test_cases[$ii];
|
||||||
|
$expect = $test_cases[$ii + 1];
|
||||||
|
|
||||||
|
$this->assertEqual($expect, AphrontRequest::flattenData($input));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue