mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-05 21:26:14 +01:00
(stable) Promote 2019 Week 32
This commit is contained in:
commit
26f9ba4684
36 changed files with 929 additions and 155 deletions
|
@ -9,10 +9,10 @@ return array(
|
||||||
'names' => array(
|
'names' => array(
|
||||||
'conpherence.pkg.css' => '3c8a0668',
|
'conpherence.pkg.css' => '3c8a0668',
|
||||||
'conpherence.pkg.js' => '020aebcf',
|
'conpherence.pkg.js' => '020aebcf',
|
||||||
'core.pkg.css' => 'af983028',
|
'core.pkg.css' => '5a4a5010',
|
||||||
'core.pkg.js' => '73a06a9f',
|
'core.pkg.js' => '73a06a9f',
|
||||||
'differential.pkg.css' => '8d8360fb',
|
'differential.pkg.css' => '8d8360fb',
|
||||||
'differential.pkg.js' => '67e02996',
|
'differential.pkg.js' => '0b037a4f',
|
||||||
'diffusion.pkg.css' => '42c75c37',
|
'diffusion.pkg.css' => '42c75c37',
|
||||||
'diffusion.pkg.js' => 'a98c0bf7',
|
'diffusion.pkg.js' => 'a98c0bf7',
|
||||||
'maniphest.pkg.css' => '35995d6d',
|
'maniphest.pkg.css' => '35995d6d',
|
||||||
|
@ -24,7 +24,7 @@ return array(
|
||||||
'rsrc/audio/basic/ting.mp3' => 'a6b6540e',
|
'rsrc/audio/basic/ting.mp3' => 'a6b6540e',
|
||||||
'rsrc/css/aphront/aphront-bars.css' => '4a327b4a',
|
'rsrc/css/aphront/aphront-bars.css' => '4a327b4a',
|
||||||
'rsrc/css/aphront/dark-console.css' => '7f06cda2',
|
'rsrc/css/aphront/dark-console.css' => '7f06cda2',
|
||||||
'rsrc/css/aphront/dialog-view.css' => 'b70c70df',
|
'rsrc/css/aphront/dialog-view.css' => '874f5c06',
|
||||||
'rsrc/css/aphront/list-filter-view.css' => 'feb64255',
|
'rsrc/css/aphront/list-filter-view.css' => 'feb64255',
|
||||||
'rsrc/css/aphront/multi-column.css' => 'fbc00ba3',
|
'rsrc/css/aphront/multi-column.css' => 'fbc00ba3',
|
||||||
'rsrc/css/aphront/notification.css' => '30240bd2',
|
'rsrc/css/aphront/notification.css' => '30240bd2',
|
||||||
|
@ -484,7 +484,7 @@ return array(
|
||||||
'rsrc/js/core/behavior-line-linker.js' => 'e15c8b1f',
|
'rsrc/js/core/behavior-line-linker.js' => 'e15c8b1f',
|
||||||
'rsrc/js/core/behavior-linked-container.js' => '74446546',
|
'rsrc/js/core/behavior-linked-container.js' => '74446546',
|
||||||
'rsrc/js/core/behavior-more.js' => '506aa3f4',
|
'rsrc/js/core/behavior-more.js' => '506aa3f4',
|
||||||
'rsrc/js/core/behavior-object-selector.js' => 'a4af0b4a',
|
'rsrc/js/core/behavior-object-selector.js' => '98ef467f',
|
||||||
'rsrc/js/core/behavior-oncopy.js' => 'ff7b3f22',
|
'rsrc/js/core/behavior-oncopy.js' => 'ff7b3f22',
|
||||||
'rsrc/js/core/behavior-phabricator-nav.js' => 'f166c949',
|
'rsrc/js/core/behavior-phabricator-nav.js' => 'f166c949',
|
||||||
'rsrc/js/core/behavior-phabricator-remarkup-assist.js' => '2f80333f',
|
'rsrc/js/core/behavior-phabricator-remarkup-assist.js' => '2f80333f',
|
||||||
|
@ -530,7 +530,7 @@ return array(
|
||||||
'almanac-css' => '2e050f4f',
|
'almanac-css' => '2e050f4f',
|
||||||
'aphront-bars' => '4a327b4a',
|
'aphront-bars' => '4a327b4a',
|
||||||
'aphront-dark-console-css' => '7f06cda2',
|
'aphront-dark-console-css' => '7f06cda2',
|
||||||
'aphront-dialog-view-css' => 'b70c70df',
|
'aphront-dialog-view-css' => '874f5c06',
|
||||||
'aphront-list-filter-view-css' => 'feb64255',
|
'aphront-list-filter-view-css' => 'feb64255',
|
||||||
'aphront-multi-column-view-css' => 'fbc00ba3',
|
'aphront-multi-column-view-css' => 'fbc00ba3',
|
||||||
'aphront-panel-view-css' => '46923d46',
|
'aphront-panel-view-css' => '46923d46',
|
||||||
|
@ -645,7 +645,7 @@ return array(
|
||||||
'javelin-behavior-phabricator-line-linker' => 'e15c8b1f',
|
'javelin-behavior-phabricator-line-linker' => 'e15c8b1f',
|
||||||
'javelin-behavior-phabricator-nav' => 'f166c949',
|
'javelin-behavior-phabricator-nav' => 'f166c949',
|
||||||
'javelin-behavior-phabricator-notification-example' => '29819b75',
|
'javelin-behavior-phabricator-notification-example' => '29819b75',
|
||||||
'javelin-behavior-phabricator-object-selector' => 'a4af0b4a',
|
'javelin-behavior-phabricator-object-selector' => '98ef467f',
|
||||||
'javelin-behavior-phabricator-oncopy' => 'ff7b3f22',
|
'javelin-behavior-phabricator-oncopy' => 'ff7b3f22',
|
||||||
'javelin-behavior-phabricator-remarkup-assist' => '2f80333f',
|
'javelin-behavior-phabricator-remarkup-assist' => '2f80333f',
|
||||||
'javelin-behavior-phabricator-reveal-content' => 'b105a3a6',
|
'javelin-behavior-phabricator-reveal-content' => 'b105a3a6',
|
||||||
|
@ -1730,6 +1730,12 @@ return array(
|
||||||
'javelin-dom',
|
'javelin-dom',
|
||||||
'javelin-router',
|
'javelin-router',
|
||||||
),
|
),
|
||||||
|
'98ef467f' => array(
|
||||||
|
'javelin-behavior',
|
||||||
|
'javelin-dom',
|
||||||
|
'javelin-request',
|
||||||
|
'javelin-util',
|
||||||
|
),
|
||||||
'9aae2b66' => array(
|
'9aae2b66' => array(
|
||||||
'javelin-install',
|
'javelin-install',
|
||||||
'javelin-util',
|
'javelin-util',
|
||||||
|
@ -1790,12 +1796,6 @@ return array(
|
||||||
'phui-button-css',
|
'phui-button-css',
|
||||||
'phui-button-simple-css',
|
'phui-button-simple-css',
|
||||||
),
|
),
|
||||||
'a4af0b4a' => array(
|
|
||||||
'javelin-behavior',
|
|
||||||
'javelin-dom',
|
|
||||||
'javelin-request',
|
|
||||||
'javelin-util',
|
|
||||||
),
|
|
||||||
'a5257c4e' => array(
|
'a5257c4e' => array(
|
||||||
'javelin-install',
|
'javelin-install',
|
||||||
'javelin-dom',
|
'javelin-dom',
|
||||||
|
|
|
@ -3878,7 +3878,21 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorOwnersPathsSearchEngineAttachment' => 'applications/owners/engineextension/PhabricatorOwnersPathsSearchEngineAttachment.php',
|
'PhabricatorOwnersPathsSearchEngineAttachment' => 'applications/owners/engineextension/PhabricatorOwnersPathsSearchEngineAttachment.php',
|
||||||
'PhabricatorOwnersSchemaSpec' => 'applications/owners/storage/PhabricatorOwnersSchemaSpec.php',
|
'PhabricatorOwnersSchemaSpec' => 'applications/owners/storage/PhabricatorOwnersSchemaSpec.php',
|
||||||
'PhabricatorOwnersSearchField' => 'applications/owners/searchfield/PhabricatorOwnersSearchField.php',
|
'PhabricatorOwnersSearchField' => 'applications/owners/searchfield/PhabricatorOwnersSearchField.php',
|
||||||
|
'PhabricatorPDFCatalogObject' => 'applications/phortune/pdf/PhabricatorPDFCatalogObject.php',
|
||||||
|
'PhabricatorPDFContentsObject' => 'applications/phortune/pdf/PhabricatorPDFContentsObject.php',
|
||||||
'PhabricatorPDFDocumentEngine' => 'applications/files/document/PhabricatorPDFDocumentEngine.php',
|
'PhabricatorPDFDocumentEngine' => 'applications/files/document/PhabricatorPDFDocumentEngine.php',
|
||||||
|
'PhabricatorPDFFontObject' => 'applications/phortune/pdf/PhabricatorPDFFontObject.php',
|
||||||
|
'PhabricatorPDFFragment' => 'applications/phortune/pdf/PhabricatorPDFFragment.php',
|
||||||
|
'PhabricatorPDFFragmentOffset' => 'applications/phortune/pdf/PhabricatorPDFFragmentOffset.php',
|
||||||
|
'PhabricatorPDFGenerator' => 'applications/phortune/pdf/PhabricatorPDFGenerator.php',
|
||||||
|
'PhabricatorPDFHeadFragment' => 'applications/phortune/pdf/PhabricatorPDFHeadFragment.php',
|
||||||
|
'PhabricatorPDFInfoObject' => 'applications/phortune/pdf/PhabricatorPDFInfoObject.php',
|
||||||
|
'PhabricatorPDFIterator' => 'applications/phortune/pdf/PhabricatorPDFIterator.php',
|
||||||
|
'PhabricatorPDFObject' => 'applications/phortune/pdf/PhabricatorPDFObject.php',
|
||||||
|
'PhabricatorPDFPageObject' => 'applications/phortune/pdf/PhabricatorPDFPageObject.php',
|
||||||
|
'PhabricatorPDFPagesObject' => 'applications/phortune/pdf/PhabricatorPDFPagesObject.php',
|
||||||
|
'PhabricatorPDFResourcesObject' => 'applications/phortune/pdf/PhabricatorPDFResourcesObject.php',
|
||||||
|
'PhabricatorPDFTailFragment' => 'applications/phortune/pdf/PhabricatorPDFTailFragment.php',
|
||||||
'PhabricatorPHDConfigOptions' => 'applications/config/option/PhabricatorPHDConfigOptions.php',
|
'PhabricatorPHDConfigOptions' => 'applications/config/option/PhabricatorPHDConfigOptions.php',
|
||||||
'PhabricatorPHID' => 'applications/phid/storage/PhabricatorPHID.php',
|
'PhabricatorPHID' => 'applications/phid/storage/PhabricatorPHID.php',
|
||||||
'PhabricatorPHIDConstants' => 'applications/phid/PhabricatorPHIDConstants.php',
|
'PhabricatorPHIDConstants' => 'applications/phid/PhabricatorPHIDConstants.php',
|
||||||
|
@ -10101,7 +10115,24 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorOwnersPathsSearchEngineAttachment' => 'PhabricatorSearchEngineAttachment',
|
'PhabricatorOwnersPathsSearchEngineAttachment' => 'PhabricatorSearchEngineAttachment',
|
||||||
'PhabricatorOwnersSchemaSpec' => 'PhabricatorConfigSchemaSpec',
|
'PhabricatorOwnersSchemaSpec' => 'PhabricatorConfigSchemaSpec',
|
||||||
'PhabricatorOwnersSearchField' => 'PhabricatorSearchTokenizerField',
|
'PhabricatorOwnersSearchField' => 'PhabricatorSearchTokenizerField',
|
||||||
|
'PhabricatorPDFCatalogObject' => 'PhabricatorPDFObject',
|
||||||
|
'PhabricatorPDFContentsObject' => 'PhabricatorPDFObject',
|
||||||
'PhabricatorPDFDocumentEngine' => 'PhabricatorDocumentEngine',
|
'PhabricatorPDFDocumentEngine' => 'PhabricatorDocumentEngine',
|
||||||
|
'PhabricatorPDFFontObject' => 'PhabricatorPDFObject',
|
||||||
|
'PhabricatorPDFFragment' => 'Phobject',
|
||||||
|
'PhabricatorPDFFragmentOffset' => 'Phobject',
|
||||||
|
'PhabricatorPDFGenerator' => 'Phobject',
|
||||||
|
'PhabricatorPDFHeadFragment' => 'PhabricatorPDFFragment',
|
||||||
|
'PhabricatorPDFInfoObject' => 'PhabricatorPDFObject',
|
||||||
|
'PhabricatorPDFIterator' => array(
|
||||||
|
'Phobject',
|
||||||
|
'Iterator',
|
||||||
|
),
|
||||||
|
'PhabricatorPDFObject' => 'PhabricatorPDFFragment',
|
||||||
|
'PhabricatorPDFPageObject' => 'PhabricatorPDFObject',
|
||||||
|
'PhabricatorPDFPagesObject' => 'PhabricatorPDFObject',
|
||||||
|
'PhabricatorPDFResourcesObject' => 'PhabricatorPDFObject',
|
||||||
|
'PhabricatorPDFTailFragment' => 'PhabricatorPDFFragment',
|
||||||
'PhabricatorPHDConfigOptions' => 'PhabricatorApplicationConfigOptions',
|
'PhabricatorPHDConfigOptions' => 'PhabricatorApplicationConfigOptions',
|
||||||
'PhabricatorPHID' => 'Phobject',
|
'PhabricatorPHID' => 'Phobject',
|
||||||
'PhabricatorPHIDConstants' => 'Phobject',
|
'PhabricatorPHIDConstants' => 'Phobject',
|
||||||
|
|
|
@ -194,6 +194,7 @@ final class PhabricatorTOTPAuthFactor extends PhabricatorAuthFactor {
|
||||||
$control = id(new PHUIFormNumberControl())
|
$control = id(new PHUIFormNumberControl())
|
||||||
->setName($name)
|
->setName($name)
|
||||||
->setDisableAutocomplete(true)
|
->setDisableAutocomplete(true)
|
||||||
|
->setAutofocus(true)
|
||||||
->setValue($value)
|
->setValue($value)
|
||||||
->setError($error);
|
->setError($error);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,24 @@
|
||||||
final class ConduitEpochParameterType
|
final class ConduitEpochParameterType
|
||||||
extends ConduitParameterType {
|
extends ConduitParameterType {
|
||||||
|
|
||||||
|
private $allowNull;
|
||||||
|
|
||||||
|
public function setAllowNull($allow_null) {
|
||||||
|
$this->allowNull = $allow_null;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAllowNull() {
|
||||||
|
return $this->allowNull;
|
||||||
|
}
|
||||||
|
|
||||||
protected function getParameterValue(array $request, $key, $strict) {
|
protected function getParameterValue(array $request, $key, $strict) {
|
||||||
$value = parent::getParameterValue($request, $key, $strict);
|
$value = parent::getParameterValue($request, $key, $strict);
|
||||||
|
|
||||||
|
if ($this->allowNull && ($value === null)) {
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
$value = $this->parseIntValue($request, $key, $value, $strict);
|
$value = $this->parseIntValue($request, $key, $value, $strict);
|
||||||
|
|
||||||
if ($value <= 0) {
|
if ($value <= 0) {
|
||||||
|
|
|
@ -17,32 +17,31 @@ final class DiffusionRepositoryEditDeleteController
|
||||||
->setRepository($repository)
|
->setRepository($repository)
|
||||||
->getPanelURI();
|
->getPanelURI();
|
||||||
|
|
||||||
$dialog = new AphrontDialogView();
|
$doc_uri = PhabricatorEnv::getDoclink(
|
||||||
$text_1 = pht(
|
'Permanently Destroying Data');
|
||||||
'If you really want to delete the repository, run this command from '.
|
|
||||||
'the command line:');
|
|
||||||
$command = csprintf(
|
|
||||||
'phabricator/ $ ./bin/remove destroy %R',
|
|
||||||
$repository->getMonogram());
|
|
||||||
$text_2 = pht(
|
|
||||||
'Repositories touch many objects and as such deletes are '.
|
|
||||||
'prohibitively expensive to run from the web UI.');
|
|
||||||
$body = phutil_tag(
|
|
||||||
'div',
|
|
||||||
array(
|
|
||||||
'class' => 'phabricator-remarkup',
|
|
||||||
),
|
|
||||||
array(
|
|
||||||
phutil_tag('p', array(), $text_1),
|
|
||||||
phutil_tag('p', array(),
|
|
||||||
phutil_tag('tt', array(), $command)),
|
|
||||||
phutil_tag('p', array(), $text_2),
|
|
||||||
));
|
|
||||||
|
|
||||||
return $this->newDialog()
|
return $this->newDialog()
|
||||||
->setTitle(pht('Really want to delete the repository?'))
|
->setTitle(pht('Delete Repository'))
|
||||||
->appendChild($body)
|
->appendParagraph(
|
||||||
->addCancelButton($panel_uri, pht('Okay'));
|
pht(
|
||||||
|
'To permanently destroy this repository, run this command from '.
|
||||||
|
'the command line:'))
|
||||||
|
->appendCommand(
|
||||||
|
csprintf(
|
||||||
|
'phabricator/ $ ./bin/remove destroy %R',
|
||||||
|
$repository->getMonogram()))
|
||||||
|
->appendParagraph(
|
||||||
|
pht(
|
||||||
|
'Repositories can not be permanently destroyed from the web '.
|
||||||
|
'interface. See %s in the documentation for more information.',
|
||||||
|
phutil_tag(
|
||||||
|
'a',
|
||||||
|
array(
|
||||||
|
'href' => $doc_uri,
|
||||||
|
'target' => '_blank',
|
||||||
|
),
|
||||||
|
pht('Permanently Destroying Data'))))
|
||||||
|
->addCancelButton($panel_uri, pht('Close'));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -155,8 +155,6 @@ final class DiffusionRepositoryBasicsManagementPanel
|
||||||
->setName(pht('Delete Repository'))
|
->setName(pht('Delete Repository'))
|
||||||
->setHref($delete_uri)
|
->setHref($delete_uri)
|
||||||
->setIcon('fa-times')
|
->setIcon('fa-times')
|
||||||
->setColor(PhabricatorActionView::RED)
|
|
||||||
->setDisabled(true)
|
|
||||||
->setWorkflow(true));
|
->setWorkflow(true));
|
||||||
|
|
||||||
return $this->newCurtainView()
|
return $this->newCurtainView()
|
||||||
|
|
|
@ -47,7 +47,7 @@ final class DiffusionPatternSearchView extends DiffusionView {
|
||||||
$offset = $match[1];
|
$offset = $match[1];
|
||||||
if ($cursor != $offset) {
|
if ($cursor != $offset) {
|
||||||
$output[] = array(
|
$output[] = array(
|
||||||
'text' => substr($string, $cursor, $offset),
|
'text' => substr($string, $cursor, ($offset - $cursor)),
|
||||||
'highlight' => false,
|
'highlight' => false,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -451,15 +451,20 @@ You can choose the default priority for newly created tasks with
|
||||||
EOTEXT
|
EOTEXT
|
||||||
));
|
));
|
||||||
|
|
||||||
|
$fields_description = $this->deformat(pht(<<<EOTEXT
|
||||||
|
List of custom fields for Maniphest tasks.
|
||||||
|
|
||||||
|
For details on adding custom fields to Maniphest, see [[ %s | %s ]] in the
|
||||||
|
documentation.
|
||||||
|
EOTEXT
|
||||||
|
,
|
||||||
|
PhabricatorEnv::getDoclink('Configuring Custom Fields'),
|
||||||
|
pht('Configuring Custom Fields')));
|
||||||
|
|
||||||
return array(
|
return array(
|
||||||
$this->newOption('maniphest.custom-field-definitions', 'wild', array())
|
$this->newOption('maniphest.custom-field-definitions', 'wild', array())
|
||||||
->setSummary(pht('Custom Maniphest fields.'))
|
->setSummary(pht('Custom Maniphest fields.'))
|
||||||
->setDescription(
|
->setDescription($fields_description)
|
||||||
pht(
|
|
||||||
'Array of custom fields for Maniphest tasks. For details on '.
|
|
||||||
'adding custom fields to Maniphest, see "Configuring Custom '.
|
|
||||||
'Fields" in the documentation.'))
|
|
||||||
->addExample($fields_json, pht('Valid setting')),
|
->addExample($fields_json, pht('Valid setting')),
|
||||||
$this->newOption('maniphest.fields', $custom_field_type, $default_fields)
|
$this->newOption('maniphest.fields', $custom_field_type, $default_fields)
|
||||||
->setCustomData(id(new ManiphestTask())->getCustomFieldBaseClass())
|
->setCustomData(id(new ManiphestTask())->getCustomFieldBaseClass())
|
||||||
|
|
|
@ -17,58 +17,35 @@ final class PhabricatorPeopleDeleteController
|
||||||
|
|
||||||
$manage_uri = $this->getApplicationURI("manage/{$id}/");
|
$manage_uri = $this->getApplicationURI("manage/{$id}/");
|
||||||
|
|
||||||
if ($user->getPHID() == $viewer->getPHID()) {
|
$doc_uri = PhabricatorEnv::getDoclink(
|
||||||
return $this->buildDeleteSelfResponse($manage_uri);
|
'Permanently Destroying Data');
|
||||||
}
|
|
||||||
|
|
||||||
$str1 = pht(
|
|
||||||
'Be careful when deleting users! This will permanently and '.
|
|
||||||
'irreversibly destroy this user account.');
|
|
||||||
|
|
||||||
$str2 = pht(
|
|
||||||
'If this user interacted with anything, it is generally better to '.
|
|
||||||
'disable them, not delete them. If you delete them, it will no longer '.
|
|
||||||
'be possible to (for example) search for objects they created, and you '.
|
|
||||||
'will lose other information about their history. Disabling them '.
|
|
||||||
'instead will prevent them from logging in, but will not destroy any of '.
|
|
||||||
'their data.');
|
|
||||||
|
|
||||||
$str3 = pht(
|
|
||||||
'It is generally safe to delete newly created users (and test users and '.
|
|
||||||
'so on), but less safe to delete established users. If possible, '.
|
|
||||||
'disable them instead.');
|
|
||||||
|
|
||||||
$str4 = pht('To permanently destroy this user, run this command:');
|
|
||||||
|
|
||||||
$form = id(new AphrontFormView())
|
|
||||||
->setUser($viewer)
|
|
||||||
->appendRemarkupInstructions(
|
|
||||||
csprintf(
|
|
||||||
" phabricator/ $ ./bin/remove destroy %R\n",
|
|
||||||
'@'.$user->getUsername()));
|
|
||||||
|
|
||||||
return $this->newDialog()
|
return $this->newDialog()
|
||||||
->setWidth(AphrontDialogView::WIDTH_FORM)
|
->setTitle(pht('Delete User'))
|
||||||
->setTitle(pht('Permanently Delete User'))
|
->appendParagraph(
|
||||||
->setShortTitle(pht('Delete User'))
|
pht(
|
||||||
->appendParagraph($str1)
|
'To permanently destroy this user, run this command from the '.
|
||||||
->appendParagraph($str2)
|
'command line:'))
|
||||||
->appendParagraph($str3)
|
->appendCommand(
|
||||||
->appendParagraph($str4)
|
csprintf(
|
||||||
->appendChild($form->buildLayoutView())
|
'phabricator/ $ ./bin/remove destroy %R',
|
||||||
|
$user->getMonogram()))
|
||||||
|
->appendParagraph(
|
||||||
|
pht(
|
||||||
|
'Unless you have a very good reason to delete this user, consider '.
|
||||||
|
'disabling them instead.'))
|
||||||
|
->appendParagraph(
|
||||||
|
pht(
|
||||||
|
'Users can not be permanently destroyed from the web interface. '.
|
||||||
|
'See %s in the documentation for more information.',
|
||||||
|
phutil_tag(
|
||||||
|
'a',
|
||||||
|
array(
|
||||||
|
'href' => $doc_uri,
|
||||||
|
'target' => '_blank',
|
||||||
|
),
|
||||||
|
pht('Permanently Destroying Data'))))
|
||||||
->addCancelButton($manage_uri, pht('Close'));
|
->addCancelButton($manage_uri, pht('Close'));
|
||||||
}
|
}
|
||||||
|
|
||||||
private function buildDeleteSelfResponse($cancel_uri) {
|
|
||||||
return $this->newDialog()
|
|
||||||
->setTitle(pht('You Shall Journey No Farther'))
|
|
||||||
->appendParagraph(
|
|
||||||
pht(
|
|
||||||
'As you stare into the gaping maw of the abyss, something '.
|
|
||||||
'holds you back.'))
|
|
||||||
->appendParagraph(pht('You can not delete your own account.'))
|
|
||||||
->addCancelButton($cancel_uri, pht('Turn Back'));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,20 +34,6 @@ final class PhabricatorPeopleProfileBadgesController
|
||||||
$user,
|
$user,
|
||||||
PhabricatorPeopleProfileMenuEngine::ITEM_BADGES);
|
PhabricatorPeopleProfileMenuEngine::ITEM_BADGES);
|
||||||
|
|
||||||
// Best option?
|
|
||||||
$badges = id(new PhabricatorBadgesQuery())
|
|
||||||
->setViewer($viewer)
|
|
||||||
->withStatuses(array(
|
|
||||||
PhabricatorBadgesBadge::STATUS_ACTIVE,
|
|
||||||
))
|
|
||||||
->requireCapabilities(
|
|
||||||
array(
|
|
||||||
PhabricatorPolicyCapability::CAN_VIEW,
|
|
||||||
PhabricatorPolicyCapability::CAN_EDIT,
|
|
||||||
))
|
|
||||||
->setLimit(1)
|
|
||||||
->execute();
|
|
||||||
|
|
||||||
$button = id(new PHUIButtonView())
|
$button = id(new PHUIButtonView())
|
||||||
->setTag('a')
|
->setTag('a')
|
||||||
->setIcon('fa-plus')
|
->setIcon('fa-plus')
|
||||||
|
@ -55,17 +41,16 @@ final class PhabricatorPeopleProfileBadgesController
|
||||||
->setWorkflow(true)
|
->setWorkflow(true)
|
||||||
->setHref('/badges/award/'.$user->getID().'/');
|
->setHref('/badges/award/'.$user->getID().'/');
|
||||||
|
|
||||||
if ($badges) {
|
$header->addActionLink($button);
|
||||||
$header->addActionLink($button);
|
|
||||||
}
|
|
||||||
|
|
||||||
$view = id(new PHUITwoColumnView())
|
$view = id(new PHUITwoColumnView())
|
||||||
->setHeader($header)
|
->setHeader($header)
|
||||||
->addClass('project-view-home')
|
->addClass('project-view-home')
|
||||||
->addClass('project-view-people-home')
|
->addClass('project-view-people-home')
|
||||||
->setFooter(array(
|
->setFooter(
|
||||||
$this->buildBadgesView($user)
|
array(
|
||||||
));
|
$badges,
|
||||||
|
));
|
||||||
|
|
||||||
return $this->newPage()
|
return $this->newPage()
|
||||||
->setTitle($title)
|
->setTitle($title)
|
||||||
|
|
|
@ -188,8 +188,8 @@ final class PhortuneCartEditor
|
||||||
protected function getMailTo(PhabricatorLiskDAO $object) {
|
protected function getMailTo(PhabricatorLiskDAO $object) {
|
||||||
$phids = array();
|
$phids = array();
|
||||||
|
|
||||||
// Reload the cart to pull merchant and account information, in case we
|
// Reload the cart to pull account information, in case we just created the
|
||||||
// just created the object.
|
// object.
|
||||||
$cart = id(new PhortuneCartQuery())
|
$cart = id(new PhortuneCartQuery())
|
||||||
->setViewer($this->requireActor())
|
->setViewer($this->requireActor())
|
||||||
->withPHIDs(array($object->getPHID()))
|
->withPHIDs(array($object->getPHID()))
|
||||||
|
@ -199,10 +199,6 @@ final class PhortuneCartEditor
|
||||||
$phids[] = $account_member;
|
$phids[] = $account_member;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($cart->getMerchant()->getMemberPHIDs() as $merchant_member) {
|
|
||||||
$phids[] = $merchant_member;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $phids;
|
return $phids;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorPDFCatalogObject
|
||||||
|
extends PhabricatorPDFObject {
|
||||||
|
|
||||||
|
private $pagesObject;
|
||||||
|
|
||||||
|
public function setPagesObject(PhabricatorPDFPagesObject $pages_object) {
|
||||||
|
$this->pagesObject = $this->newChildObject($pages_object);
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPagesObject() {
|
||||||
|
return $this->pagesObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function writeObject() {
|
||||||
|
$this->writeLine('/Type /Catalog');
|
||||||
|
|
||||||
|
$pages_object = $this->getPagesObject();
|
||||||
|
if ($pages_object) {
|
||||||
|
$this->writeLine('/Pages %d 0 R', $pages_object->getObjectIndex());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorPDFContentsObject
|
||||||
|
extends PhabricatorPDFObject {
|
||||||
|
|
||||||
|
private $rawContent;
|
||||||
|
|
||||||
|
public function setRawContent($raw_content) {
|
||||||
|
$this->rawContent = $raw_content;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRawContent() {
|
||||||
|
return $this->rawContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function writeObject() {
|
||||||
|
$data = $this->getRawContent();
|
||||||
|
|
||||||
|
$stream_length = $this->newStream($data);
|
||||||
|
|
||||||
|
$this->writeLine('/Filter /FlateDecode /Length %d', $stream_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
14
src/applications/phortune/pdf/PhabricatorPDFFontObject.php
Normal file
14
src/applications/phortune/pdf/PhabricatorPDFFontObject.php
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorPDFFontObject
|
||||||
|
extends PhabricatorPDFObject {
|
||||||
|
|
||||||
|
protected function writeObject() {
|
||||||
|
$this->writeLine('/Type /Font');
|
||||||
|
|
||||||
|
$this->writeLine('/BaseFont /Helvetica-Bold');
|
||||||
|
$this->writeLine('/Subtype /Type1');
|
||||||
|
$this->writeLine('/Encoding /WinAnsiEncoding');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
38
src/applications/phortune/pdf/PhabricatorPDFFragment.php
Normal file
38
src/applications/phortune/pdf/PhabricatorPDFFragment.php
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
abstract class PhabricatorPDFFragment
|
||||||
|
extends Phobject {
|
||||||
|
|
||||||
|
private $rope;
|
||||||
|
|
||||||
|
public function getAsBytes() {
|
||||||
|
$this->rope = new PhutilRope();
|
||||||
|
|
||||||
|
$this->writeFragment();
|
||||||
|
|
||||||
|
$rope = $this->rope;
|
||||||
|
$this->rope = null;
|
||||||
|
|
||||||
|
return $rope->getAsString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasRefTableEntry() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract protected function writeFragment();
|
||||||
|
|
||||||
|
final protected function writeLine($pattern) {
|
||||||
|
$pattern = $pattern."\n";
|
||||||
|
|
||||||
|
$argv = func_get_args();
|
||||||
|
$argv[0] = $pattern;
|
||||||
|
|
||||||
|
$line = call_user_func_array('sprintf', $argv);
|
||||||
|
|
||||||
|
$this->rope->append($line);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorPDFFragmentOffset
|
||||||
|
extends Phobject {
|
||||||
|
|
||||||
|
private $fragment;
|
||||||
|
private $offset;
|
||||||
|
|
||||||
|
public function setFragment(PhabricatorPDFFragment $fragment) {
|
||||||
|
$this->fragment = $fragment;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFragment() {
|
||||||
|
return $this->fragment;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setOffset($offset) {
|
||||||
|
$this->offset = $offset;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getOffset() {
|
||||||
|
return $this->offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
59
src/applications/phortune/pdf/PhabricatorPDFGenerator.php
Normal file
59
src/applications/phortune/pdf/PhabricatorPDFGenerator.php
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorPDFGenerator
|
||||||
|
extends Phobject {
|
||||||
|
|
||||||
|
private $objects = array();
|
||||||
|
private $hasIterator = false;
|
||||||
|
|
||||||
|
private $infoObject;
|
||||||
|
private $catalogObject;
|
||||||
|
|
||||||
|
public function addObject(PhabricatorPDFObject $object) {
|
||||||
|
if ($this->hasIterator) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'This generator has already emitted an iterator. You can not '.
|
||||||
|
'modify the PDF document after you begin writing it.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->objects[] = $object;
|
||||||
|
$index = count($this->objects);
|
||||||
|
|
||||||
|
$object->setGenerator($this, $index);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getObjects() {
|
||||||
|
return $this->objects;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newIterator() {
|
||||||
|
$this->hasIterator = true;
|
||||||
|
return id(new PhabricatorPDFIterator())
|
||||||
|
->setGenerator($this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setInfoObject(PhabricatorPDFInfoObject $info_object) {
|
||||||
|
$this->addObject($info_object);
|
||||||
|
$this->infoObject = $info_object;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getInfoObject() {
|
||||||
|
return $this->infoObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setCatalogObject(
|
||||||
|
PhabricatorPDFCatalogObject $catalog_object) {
|
||||||
|
$this->addObject($catalog_object);
|
||||||
|
$this->catalogObject = $catalog_object;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCatalogObject() {
|
||||||
|
return $this->catalogObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
10
src/applications/phortune/pdf/PhabricatorPDFHeadFragment.php
Normal file
10
src/applications/phortune/pdf/PhabricatorPDFHeadFragment.php
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorPDFHeadFragment
|
||||||
|
extends PhabricatorPDFFragment {
|
||||||
|
|
||||||
|
protected function writeFragment() {
|
||||||
|
$this->writeLine('%s', '%PDF-1.3');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
11
src/applications/phortune/pdf/PhabricatorPDFInfoObject.php
Normal file
11
src/applications/phortune/pdf/PhabricatorPDFInfoObject.php
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorPDFInfoObject
|
||||||
|
extends PhabricatorPDFObject {
|
||||||
|
|
||||||
|
final protected function writeObject() {
|
||||||
|
$this->writeLine('/Producer (Phabricator 20190801)');
|
||||||
|
$this->writeLine('/CreationDate (D:%s)', date('YmdHis'));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
103
src/applications/phortune/pdf/PhabricatorPDFIterator.php
Normal file
103
src/applications/phortune/pdf/PhabricatorPDFIterator.php
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorPDFIterator
|
||||||
|
extends Phobject
|
||||||
|
implements Iterator {
|
||||||
|
|
||||||
|
private $generator;
|
||||||
|
private $hasRewound;
|
||||||
|
|
||||||
|
private $fragments;
|
||||||
|
private $fragmentKey;
|
||||||
|
private $fragmentBytes;
|
||||||
|
private $fragmentOffsets = array();
|
||||||
|
private $byteLength;
|
||||||
|
|
||||||
|
public function setGenerator(PhabricatorPDFGenerator $generator) {
|
||||||
|
if ($this->generator) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'This iterator already has a generator. You can not modify the '.
|
||||||
|
'generator for a given iterator.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->generator = $generator;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getGenerator() {
|
||||||
|
if (!$this->generator) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'This PDF iterator has no associated PDF generator.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->generator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFragmentOffsets() {
|
||||||
|
return $this->fragmentOffsets;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function current() {
|
||||||
|
return $this->fragmentBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function key() {
|
||||||
|
return $this->framgentKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function next() {
|
||||||
|
$this->fragmentKey++;
|
||||||
|
|
||||||
|
if (!$this->valid()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$fragment = $this->fragments[$this->fragmentKey];
|
||||||
|
|
||||||
|
$this->fragmentOffsets[] = id(new PhabricatorPDFFragmentOffset())
|
||||||
|
->setFragment($fragment)
|
||||||
|
->setOffset($this->byteLength);
|
||||||
|
|
||||||
|
$bytes = $fragment->getAsBytes();
|
||||||
|
|
||||||
|
$this->fragmentBytes = $bytes;
|
||||||
|
$this->byteLength += strlen($bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function rewind() {
|
||||||
|
if ($this->hasRewound) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'PDF iterators may not be rewound. Create a new iterator to emit '.
|
||||||
|
'another PDF.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$generator = $this->getGenerator();
|
||||||
|
$objects = $generator->getObjects();
|
||||||
|
|
||||||
|
$this->fragments = array();
|
||||||
|
$this->fragments[] = new PhabricatorPDFHeadFragment();
|
||||||
|
|
||||||
|
foreach ($objects as $object) {
|
||||||
|
$this->fragments[] = $object;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->fragments[] = id(new PhabricatorPDFTailFragment())
|
||||||
|
->setIterator($this);
|
||||||
|
|
||||||
|
$this->hasRewound = true;
|
||||||
|
|
||||||
|
$this->fragmentKey = -1;
|
||||||
|
$this->byteLength = 0;
|
||||||
|
|
||||||
|
$this->next();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function valid() {
|
||||||
|
return isset($this->fragments[$this->fragmentKey]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
95
src/applications/phortune/pdf/PhabricatorPDFObject.php
Normal file
95
src/applications/phortune/pdf/PhabricatorPDFObject.php
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
abstract class PhabricatorPDFObject
|
||||||
|
extends PhabricatorPDFFragment {
|
||||||
|
|
||||||
|
private $generator;
|
||||||
|
private $objectIndex;
|
||||||
|
private $children = array();
|
||||||
|
private $streams = array();
|
||||||
|
|
||||||
|
final public function hasRefTableEntry() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
final protected function writeFragment() {
|
||||||
|
$this->writeLine('%d 0 obj', $this->getObjectIndex());
|
||||||
|
$this->writeLine('<<');
|
||||||
|
$this->writeObject();
|
||||||
|
$this->writeLine('>>');
|
||||||
|
|
||||||
|
$streams = $this->streams;
|
||||||
|
$this->streams = array();
|
||||||
|
foreach ($streams as $stream) {
|
||||||
|
$this->writeLine('stream');
|
||||||
|
$this->writeLine('%s', $stream);
|
||||||
|
$this->writeLine('endstream');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->writeLine('endobj');
|
||||||
|
}
|
||||||
|
|
||||||
|
final public function setGenerator(
|
||||||
|
PhabricatorPDFGenerator $generator,
|
||||||
|
$index) {
|
||||||
|
|
||||||
|
if ($this->getGenerator()) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'This PDF object is already registered with a PDF generator. You '.
|
||||||
|
'can not register an object with more than one generator.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->generator = $generator;
|
||||||
|
$this->objectIndex = $index;
|
||||||
|
|
||||||
|
foreach ($this->getChildren() as $child) {
|
||||||
|
$generator->addObject($child);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
final public function getGenerator() {
|
||||||
|
return $this->generator;
|
||||||
|
}
|
||||||
|
|
||||||
|
final public function getObjectIndex() {
|
||||||
|
if (!$this->objectIndex) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'Trying to get index for object ("%s") which has not been '.
|
||||||
|
'registered with a generator.',
|
||||||
|
get_class($this)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->objectIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
final protected function newChildObject(PhabricatorPDFObject $object) {
|
||||||
|
if ($this->generator) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'Trying to add a new PDF Object child after already registering '.
|
||||||
|
'the object with a generator.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->children[] = $object;
|
||||||
|
return $object;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getChildren() {
|
||||||
|
return $this->children;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract protected function writeObject();
|
||||||
|
|
||||||
|
final protected function newStream($raw_data) {
|
||||||
|
$stream_data = gzcompress($raw_data);
|
||||||
|
|
||||||
|
$this->streams[] = $stream_data;
|
||||||
|
|
||||||
|
return strlen($stream_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
48
src/applications/phortune/pdf/PhabricatorPDFPageObject.php
Normal file
48
src/applications/phortune/pdf/PhabricatorPDFPageObject.php
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorPDFPageObject
|
||||||
|
extends PhabricatorPDFObject {
|
||||||
|
|
||||||
|
private $pagesObject;
|
||||||
|
private $contentsObject;
|
||||||
|
private $resourcesObject;
|
||||||
|
|
||||||
|
public function setPagesObject(PhabricatorPDFPagesObject $pages) {
|
||||||
|
$this->pagesObject = $pages;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setContentsObject(PhabricatorPDFContentsObject $contents) {
|
||||||
|
$this->contentsObject = $this->newChildObject($contents);
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setResourcesObject(PhabricatorPDFResourcesObject $resources) {
|
||||||
|
$this->resourcesObject = $this->newChildObject($resources);
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function writeObject() {
|
||||||
|
$this->writeLine('/Type /Page');
|
||||||
|
|
||||||
|
$pages_object = $this->pagesObject;
|
||||||
|
$contents_object = $this->contentsObject;
|
||||||
|
$resources_object = $this->resourcesObject;
|
||||||
|
|
||||||
|
if ($pages_object) {
|
||||||
|
$pages_index = $pages_object->getObjectIndex();
|
||||||
|
$this->writeLine('/Parent %d 0 R', $pages_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($contents_object) {
|
||||||
|
$contents_index = $contents_object->getObjectIndex();
|
||||||
|
$this->writeLine('/Contents %d 0 R', $contents_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($resources_object) {
|
||||||
|
$resources_index = $resources_object->getObjectIndex();
|
||||||
|
$this->writeLine('/Resources %d 0 R', $resources_index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
38
src/applications/phortune/pdf/PhabricatorPDFPagesObject.php
Normal file
38
src/applications/phortune/pdf/PhabricatorPDFPagesObject.php
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorPDFPagesObject
|
||||||
|
extends PhabricatorPDFObject {
|
||||||
|
|
||||||
|
private $pageObjects = array();
|
||||||
|
|
||||||
|
public function addPageObject(PhabricatorPDFPageObject $page) {
|
||||||
|
$page->setPagesObject($this);
|
||||||
|
$this->pageObjects[] = $this->newChildObject($page);
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPageObjects() {
|
||||||
|
return $this->pageObjects;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function writeObject() {
|
||||||
|
$this->writeLine('/Type /Pages');
|
||||||
|
|
||||||
|
$page_objects = $this->getPageObjects();
|
||||||
|
|
||||||
|
$this->writeLine('/Count %d', count($page_objects));
|
||||||
|
$this->writeLine('/MediaBox [%d %d %0.2f %0.2f]', 0, 0, 595.28, 841.89);
|
||||||
|
|
||||||
|
if ($page_objects) {
|
||||||
|
$kids = array();
|
||||||
|
foreach ($page_objects as $page_object) {
|
||||||
|
$kids[] = sprintf(
|
||||||
|
'%d 0 R',
|
||||||
|
$page_object->getObjectIndex());
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->writeLine('/Kids [%s]', implode(' ', $kids));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorPDFResourcesObject
|
||||||
|
extends PhabricatorPDFObject {
|
||||||
|
|
||||||
|
private $fontObjects = array();
|
||||||
|
|
||||||
|
public function addFontObject(PhabricatorPDFFontObject $font) {
|
||||||
|
$this->fontObjects[] = $this->newChildObject($font);
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFontObjects() {
|
||||||
|
return $this->fontObjects;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function writeObject() {
|
||||||
|
$this->writeLine('/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]');
|
||||||
|
|
||||||
|
$fonts = $this->getFontObjects();
|
||||||
|
foreach ($fonts as $font) {
|
||||||
|
$this->writeLine('/Font <<');
|
||||||
|
$this->writeLine('/F%d %d 0 R', 1, $font->getObjectIndex());
|
||||||
|
$this->writeLine('>>');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
72
src/applications/phortune/pdf/PhabricatorPDFTailFragment.php
Normal file
72
src/applications/phortune/pdf/PhabricatorPDFTailFragment.php
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorPDFTailFragment
|
||||||
|
extends PhabricatorPDFFragment {
|
||||||
|
|
||||||
|
private $iterator;
|
||||||
|
|
||||||
|
public function setIterator(PhabricatorPDFIterator $iterator) {
|
||||||
|
$this->iterator = $iterator;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getIterator() {
|
||||||
|
return $this->iterator;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function writeFragment() {
|
||||||
|
$iterator = $this->getIterator();
|
||||||
|
$generator = $iterator->getGenerator();
|
||||||
|
$objects = $generator->getObjects();
|
||||||
|
|
||||||
|
$xref_offset = null;
|
||||||
|
|
||||||
|
$this->writeLine('xref');
|
||||||
|
$this->writeLine('0 %d', count($objects) + 1);
|
||||||
|
$this->writeLine('%010d %05d f ', 0, 0xFFFF);
|
||||||
|
|
||||||
|
$offset_map = array();
|
||||||
|
|
||||||
|
$fragment_offsets = $iterator->getFragmentOffsets();
|
||||||
|
foreach ($fragment_offsets as $fragment_offset) {
|
||||||
|
$fragment = $fragment_offset->getFragment();
|
||||||
|
$offset = $fragment_offset->getOffset();
|
||||||
|
|
||||||
|
if ($fragment === $this) {
|
||||||
|
$xref_offset = $offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$fragment->hasRefTableEntry()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$offset_map[$fragment->getObjectIndex()] = $offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
ksort($offset_map);
|
||||||
|
|
||||||
|
foreach ($offset_map as $offset) {
|
||||||
|
$this->writeLine('%010d %05d n ', $offset, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->writeLine('trailer');
|
||||||
|
$this->writeLine('<<');
|
||||||
|
$this->writeLine('/Size %d', count($objects) + 1);
|
||||||
|
|
||||||
|
$info_object = $generator->getInfoObject();
|
||||||
|
if ($info_object) {
|
||||||
|
$this->writeLine('/Info %d 0 R', $info_object->getObjectIndex());
|
||||||
|
}
|
||||||
|
|
||||||
|
$catalog_object = $generator->getCatalogObject();
|
||||||
|
if ($catalog_object) {
|
||||||
|
$this->writeLine('/Root %d 0 R', $catalog_object->getObjectIndex());
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->writeLine('>>');
|
||||||
|
$this->writeLine('startxref');
|
||||||
|
$this->writeLine('%d', $xref_offset);
|
||||||
|
$this->writeLine('%s', '%%EOF');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -107,7 +107,16 @@ final class PhabricatorProjectColumnBulkMoveController
|
||||||
->executeLayout();
|
->executeLayout();
|
||||||
|
|
||||||
$dst_columns = $layout_engine->getColumns($dst_project->getPHID());
|
$dst_columns = $layout_engine->getColumns($dst_project->getPHID());
|
||||||
$dst_columns = mpull($columns, null, 'getPHID');
|
$dst_columns = mpull($dst_columns, null, 'getPHID');
|
||||||
|
|
||||||
|
// Prevent moves to milestones or subprojects by selecting their
|
||||||
|
// columns, since the implications aren't obvious and this doesn't
|
||||||
|
// work the same way as normal column moves.
|
||||||
|
foreach ($dst_columns as $key => $dst_column) {
|
||||||
|
if ($dst_column->getProxyPHID()) {
|
||||||
|
unset($dst_columns[$key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$has_column = false;
|
$has_column = false;
|
||||||
$dst_column = null;
|
$dst_column = null;
|
||||||
|
@ -210,12 +219,40 @@ final class PhabricatorProjectColumnBulkMoveController
|
||||||
->setValue($dst_project->getDisplayName()));
|
->setValue($dst_project->getDisplayName()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$column_options = array(
|
||||||
|
'visible' => array(),
|
||||||
|
'hidden' => array(),
|
||||||
|
);
|
||||||
|
|
||||||
|
$any_hidden = false;
|
||||||
|
foreach ($dst_columns as $column) {
|
||||||
|
if (!$column->isHidden()) {
|
||||||
|
$group = 'visible';
|
||||||
|
} else {
|
||||||
|
$group = 'hidden';
|
||||||
|
}
|
||||||
|
|
||||||
|
$phid = $column->getPHID();
|
||||||
|
$display_name = $column->getDisplayName();
|
||||||
|
|
||||||
|
$column_options[$group][$phid] = $display_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($column_options['hidden']) {
|
||||||
|
$column_options = array(
|
||||||
|
pht('Visible Columns') => $column_options['visible'],
|
||||||
|
pht('Hidden Columns') => $column_options['hidden'],
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$column_options = $column_options['visible'];
|
||||||
|
}
|
||||||
|
|
||||||
$form->appendControl(
|
$form->appendControl(
|
||||||
id(new AphrontFormSelectControl())
|
id(new AphrontFormSelectControl())
|
||||||
->setName('dstColumnPHID')
|
->setName('dstColumnPHID')
|
||||||
->setLabel(pht('Move to Column'))
|
->setLabel(pht('Move to Column'))
|
||||||
->setValue($dst_column_phid)
|
->setValue($dst_column_phid)
|
||||||
->setOptions(mpull($dst_columns, 'getDisplayName', 'getPHID')));
|
->setOptions($column_options));
|
||||||
|
|
||||||
$submit = pht('Move Tasks');
|
$submit = pht('Move Tasks');
|
||||||
|
|
||||||
|
|
|
@ -78,14 +78,29 @@ final class PhabricatorProjectProfileController
|
||||||
$project,
|
$project,
|
||||||
PhabricatorProject::ITEM_PROFILE);
|
PhabricatorProject::ITEM_PROFILE);
|
||||||
|
|
||||||
$stories = id(new PhabricatorFeedQuery())
|
$query = id(new PhabricatorFeedQuery())
|
||||||
->setViewer($viewer)
|
->setViewer($viewer)
|
||||||
->withFilterPHIDs(
|
->withFilterPHIDs(array($project->getPHID()))
|
||||||
array(
|
|
||||||
$project->getPHID(),
|
|
||||||
))
|
|
||||||
->setLimit(50)
|
->setLimit(50)
|
||||||
->execute();
|
->setReturnPartialResultsOnOverheat(true);
|
||||||
|
|
||||||
|
$stories = $query->execute();
|
||||||
|
|
||||||
|
$overheated_view = null;
|
||||||
|
$is_overheated = $query->getIsOverheated();
|
||||||
|
if ($is_overheated) {
|
||||||
|
$overheated_message =
|
||||||
|
PhabricatorApplicationSearchController::newOverheatedError(
|
||||||
|
(bool)$stories);
|
||||||
|
|
||||||
|
$overheated_view = id(new PHUIInfoView())
|
||||||
|
->setSeverity(PHUIInfoView::SEVERITY_WARNING)
|
||||||
|
->setTitle(pht('Query Overheated'))
|
||||||
|
->setErrors(
|
||||||
|
array(
|
||||||
|
$overheated_message,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
$view_all = id(new PHUIButtonView())
|
$view_all = id(new PHUIButtonView())
|
||||||
->setTag('a')
|
->setTag('a')
|
||||||
|
@ -103,7 +118,11 @@ final class PhabricatorProjectProfileController
|
||||||
$feed = id(new PHUIObjectBoxView())
|
$feed = id(new PHUIObjectBoxView())
|
||||||
->setHeader($feed_header)
|
->setHeader($feed_header)
|
||||||
->addClass('project-view-feed')
|
->addClass('project-view-feed')
|
||||||
->appendChild($feed);
|
->appendChild(
|
||||||
|
array(
|
||||||
|
$overheated_view,
|
||||||
|
$feed,
|
||||||
|
));
|
||||||
|
|
||||||
require_celerity_resource('project-view-css');
|
require_celerity_resource('project-view-css');
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ final class PhabricatorBoardLayoutEngine extends Phobject {
|
||||||
|
|
||||||
private $viewer;
|
private $viewer;
|
||||||
private $boardPHIDs;
|
private $boardPHIDs;
|
||||||
private $objectPHIDs;
|
private $objectPHIDs = array();
|
||||||
private $boards;
|
private $boards;
|
||||||
private $columnMap = array();
|
private $columnMap = array();
|
||||||
private $objectColumnMap = array();
|
private $objectColumnMap = array();
|
||||||
|
|
|
@ -37,7 +37,8 @@ final class PhabricatorEpochEditField
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function newConduitParameterType() {
|
protected function newConduitParameterType() {
|
||||||
return new ConduitEpochParameterType();
|
return id(new ConduitEpochParameterType())
|
||||||
|
->setAllowNull($this->getAllowNull());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -121,6 +121,10 @@ When defining custom fields using a configuration option like
|
||||||
supported in text, int and remarkup fields (optional).
|
supported in text, int and remarkup fields (optional).
|
||||||
- **copy**: If true, this field's value will be copied when an object is
|
- **copy**: If true, this field's value will be copied when an object is
|
||||||
created using another object as a template.
|
created using another object as a template.
|
||||||
|
- **limit**: For control types which use a tokenizer control to let the user
|
||||||
|
select a list of values, this limits how many values can be selected. For
|
||||||
|
example, a "users" field with a limit of "1" will behave like the "Owner"
|
||||||
|
field in Maniphest and only allow selection of a single user.
|
||||||
|
|
||||||
The `strings` value supports different strings per control type. They are:
|
The `strings` value supports different strings per control type. They are:
|
||||||
|
|
||||||
|
|
92
src/docs/user/field/permanently_destroying_data.diviner
Normal file
92
src/docs/user/field/permanently_destroying_data.diviner
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
@title Permanently Destroying Data
|
||||||
|
@group fieldmanual
|
||||||
|
|
||||||
|
How to permanently destroy data and manage leaked secrets.
|
||||||
|
|
||||||
|
Overview
|
||||||
|
========
|
||||||
|
|
||||||
|
Phabricator intentionally makes it difficult to permanently destroy data, but
|
||||||
|
provides a command-line tool for destroying objects if you're certain that
|
||||||
|
you want to destroy something.
|
||||||
|
|
||||||
|
**Disable vs Destroy**: Most kinds of objects can be disabled, deactivated,
|
||||||
|
closed, or archived. These operations place them in inactive states and
|
||||||
|
preserve their transaction history.
|
||||||
|
|
||||||
|
(NOTE) Disabling (rather than destroying) objects is strongly recommended
|
||||||
|
unless you have a very good reason to want to permanently destroy an object.
|
||||||
|
|
||||||
|
|
||||||
|
Destroying Data
|
||||||
|
===============
|
||||||
|
|
||||||
|
To permanently destroy an object, run this command from the command line:
|
||||||
|
|
||||||
|
```
|
||||||
|
phabricator/ $ ./bin/remove destroy <object>
|
||||||
|
```
|
||||||
|
|
||||||
|
The `<object>` may be an object monogram or PHID. For instance, you can use
|
||||||
|
`@alice` to destroy a particular user, or `T123` to destroy a particular task.
|
||||||
|
|
||||||
|
(IMPORTANT) This operation is permanent and can not be undone.
|
||||||
|
|
||||||
|
|
||||||
|
CLI Access Required
|
||||||
|
===================
|
||||||
|
|
||||||
|
In almost all cases, Phabricator requires operational access from the CLI to
|
||||||
|
permanently destroy data. One major reason for this requirement is that it
|
||||||
|
limits the reach of an attacker who compromises a privileged account.
|
||||||
|
|
||||||
|
The web UI is generally append-only and actions generally leave an audit
|
||||||
|
trail, usually in the transaction log. Thus, an attacker who compromises an
|
||||||
|
account but only gains access to the web UI usually can not do much permanent
|
||||||
|
damage and usually can not hide their actions or cover their tracks.
|
||||||
|
|
||||||
|
Another reason that destroying data is hard is simply that it's permanent and
|
||||||
|
can not be undone, so there's no way to recover from mistakes.
|
||||||
|
|
||||||
|
|
||||||
|
Leaked Secrets
|
||||||
|
==============
|
||||||
|
|
||||||
|
Sometimes you may want to destroy an object because it has leaked a secret,
|
||||||
|
like an API key or another credential. For example, an engineer might
|
||||||
|
accidentally send a change for review which includes a sensitive private key.
|
||||||
|
|
||||||
|
No Phabricator command can rewind time, and once data is written to Phabricator
|
||||||
|
the cat is often out of the bag: it has often been transmitted to external
|
||||||
|
systems which Phabricator can not interact with via email, webhooks, API calls,
|
||||||
|
repository mirroring, CDN caching, and so on. You can try to clean up the mess,
|
||||||
|
but you're generally already too late.
|
||||||
|
|
||||||
|
The `bin/remove destroy` command will make a reasonable attempt to completely
|
||||||
|
destroy objects, but this is just an attempt. It can not unsend email or uncall
|
||||||
|
the API, and no command can rewind time and undo a leak.
|
||||||
|
|
||||||
|
**Revoking Credentials**: If Phabricator credentials were accidentally
|
||||||
|
disclosed, you can revoke them so they no longer function. See
|
||||||
|
@{article:Revoking Credentials} for more information.
|
||||||
|
|
||||||
|
|
||||||
|
Preventing Leaks
|
||||||
|
================
|
||||||
|
|
||||||
|
Because time can not be rewound, it is best to prevent sensitive data from
|
||||||
|
leaking in the first place. Phabricator supports some technical measures that
|
||||||
|
can make it more difficult to accidentally disclose secrets:
|
||||||
|
|
||||||
|
**Differential Diff Herald Rules**: You can write "Differential Diff" rules
|
||||||
|
in Herald that reject diffs before they are written to disk by using the
|
||||||
|
"Block diff with message" action.
|
||||||
|
|
||||||
|
These rules can reject diffs based on affected file names or file content.
|
||||||
|
This is a coarse tool, but rejecting diffs which contain strings like
|
||||||
|
`BEGIN RSA PRIVATE KEY` may make it more difficult to accidentally disclose
|
||||||
|
certain secrets.
|
||||||
|
|
||||||
|
**Commit Content Herald Rules**: For hosted repositories, you can write
|
||||||
|
"Commit Hook: Commit Content" rules in Herald which reject pushes that contain
|
||||||
|
commit which match certain rules (like file name or file content rules).
|
|
@ -169,8 +169,8 @@ start working normally.
|
||||||
Basics: Delete Repository
|
Basics: Delete Repository
|
||||||
=========================
|
=========================
|
||||||
|
|
||||||
Repositories can not be deleted from the web UI, so this option is always
|
Repositories can not be deleted from the web UI, so this option only gives you
|
||||||
disabled. Clicking it gives you information about how to delete a repository.
|
information about how to delete a repository.
|
||||||
|
|
||||||
Repositories can only be deleted from the command line, with `bin/remove`:
|
Repositories can only be deleted from the command line, with `bin/remove`:
|
||||||
|
|
||||||
|
@ -178,9 +178,8 @@ Repositories can only be deleted from the command line, with `bin/remove`:
|
||||||
$ ./bin/remove destroy <repository>
|
$ ./bin/remove destroy <repository>
|
||||||
```
|
```
|
||||||
|
|
||||||
WARNING: This command will issue you a dire warning about the severity of the
|
This command will permanently destroy the repository. For more information
|
||||||
action you are taking. Heed this warning. You are **strongly discouraged** from
|
about destroying things, see @{article:Permanently Destroying Data}.
|
||||||
destroying repositories. Instead, deactivate them.
|
|
||||||
|
|
||||||
|
|
||||||
Policies
|
Policies
|
||||||
|
|
|
@ -226,20 +226,14 @@ final class PhabricatorStandardCustomFieldDate
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function shouldAppearInConduitTransactions() {
|
|
||||||
// TODO: Dates are complicated and we don't yet support handling them from
|
|
||||||
// Conduit.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function newConduitSearchParameterType() {
|
protected function newConduitSearchParameterType() {
|
||||||
// TODO: Build a new "pair<epoch|null, epoch|null>" type or similar.
|
// TODO: Build a new "pair<epoch|null, epoch|null>" type or similar.
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function newConduitEditParameterType() {
|
protected function newConduitEditParameterType() {
|
||||||
return new ConduitEpochParameterType();
|
return id(new ConduitEpochParameterType())
|
||||||
|
->setAllowNull(!$this->getRequired());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function newExportFieldType() {
|
protected function newExportFieldType() {
|
||||||
|
|
|
@ -161,15 +161,36 @@ final class AphrontDialogView
|
||||||
}
|
}
|
||||||
|
|
||||||
public function appendParagraph($paragraph) {
|
public function appendParagraph($paragraph) {
|
||||||
return $this->appendChild(
|
return $this->appendParagraphTag($paragraph);
|
||||||
phutil_tag(
|
|
||||||
'p',
|
|
||||||
array(
|
|
||||||
'class' => 'aphront-dialog-view-paragraph',
|
|
||||||
),
|
|
||||||
$paragraph));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function appendCommand($command) {
|
||||||
|
$command_tag = phutil_tag('tt', array(), $command);
|
||||||
|
return $this->appendParagraphTag(
|
||||||
|
$command_tag,
|
||||||
|
'aphront-dialog-view-command');
|
||||||
|
}
|
||||||
|
|
||||||
|
private function appendParagraphTag($content, $classes = null) {
|
||||||
|
if ($classes) {
|
||||||
|
$classes = (array)$classes;
|
||||||
|
} else {
|
||||||
|
$classes = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
array_unshift($classes, 'aphront-dialog-view-paragraph');
|
||||||
|
|
||||||
|
$paragraph_tag = phutil_tag(
|
||||||
|
'p',
|
||||||
|
array(
|
||||||
|
'class' => implode(' ', $classes),
|
||||||
|
),
|
||||||
|
$content);
|
||||||
|
|
||||||
|
return $this->appendChild($paragraph_tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public function appendList(array $items) {
|
public function appendList(array $items) {
|
||||||
$listitems = array();
|
$listitems = array();
|
||||||
foreach ($items as $item) {
|
foreach ($items as $item) {
|
||||||
|
|
|
@ -158,6 +158,11 @@
|
||||||
margin-top: 16px;
|
margin-top: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.aphront-dialog-view-command {
|
||||||
|
padding: 8px 16px;
|
||||||
|
background: {$greybackground};
|
||||||
|
}
|
||||||
|
|
||||||
.device-desktop .aphront-dialog-flush .phui-oi-list-view {
|
.device-desktop .aphront-dialog-flush .phui-oi-list-view {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
|
|
@ -132,7 +132,7 @@ JX.behavior('phabricator-object-selector', function(config) {
|
||||||
|
|
||||||
var select_object_link = JX.$N(
|
var select_object_link = JX.$N(
|
||||||
'a',
|
'a',
|
||||||
{href: h.uri, sigil: 'object-attacher'},
|
{href: '#', sigil: 'object-attacher'},
|
||||||
h.name);
|
h.name);
|
||||||
|
|
||||||
var select_object_button = JX.$N(
|
var select_object_button = JX.$N(
|
||||||
|
|
Loading…
Reference in a new issue