mirror of
https://we.phorge.it/source/phorge.git
synced 2025-01-19 11:11:10 +01:00
Merge branch 'master' into phutil_tag
(Final final sync.)
This commit is contained in:
commit
7ec8e885e1
35 changed files with 498 additions and 201 deletions
|
@ -882,6 +882,10 @@ return array(
|
||||||
'image/vnd.microsoft.icon' => true,
|
'image/vnd.microsoft.icon' => true,
|
||||||
),
|
),
|
||||||
|
|
||||||
|
// Configuration option for enabling imagemagick
|
||||||
|
// to resize animated profile pictures (gif)
|
||||||
|
'files.enable-imagemagick' => false,
|
||||||
|
|
||||||
// -- Storage --------------------------------------------------------------- //
|
// -- Storage --------------------------------------------------------------- //
|
||||||
|
|
||||||
// Phabricator allows users to upload files, and can keep them in various
|
// Phabricator allows users to upload files, and can keep them in various
|
||||||
|
|
|
@ -1866,7 +1866,7 @@ celerity_register_resource_map(array(
|
||||||
),
|
),
|
||||||
'javelin-behavior-pholio-mock-view' =>
|
'javelin-behavior-pholio-mock-view' =>
|
||||||
array(
|
array(
|
||||||
'uri' => '/res/518a169e/rsrc/js/application/pholio/behavior-pholio-mock-view.js',
|
'uri' => '/res/e5f432ac/rsrc/js/application/pholio/behavior-pholio-mock-view.js',
|
||||||
'type' => 'js',
|
'type' => 'js',
|
||||||
'requires' =>
|
'requires' =>
|
||||||
array(
|
array(
|
||||||
|
@ -2591,7 +2591,7 @@ celerity_register_resource_map(array(
|
||||||
),
|
),
|
||||||
'phabricator-core-css' =>
|
'phabricator-core-css' =>
|
||||||
array(
|
array(
|
||||||
'uri' => '/res/03c97d00/rsrc/css/core/core.css',
|
'uri' => '/res/2a055ecb/rsrc/css/core/core.css',
|
||||||
'type' => 'css',
|
'type' => 'css',
|
||||||
'requires' =>
|
'requires' =>
|
||||||
array(
|
array(
|
||||||
|
@ -3400,7 +3400,7 @@ celerity_register_resource_map(array(
|
||||||
), array(
|
), array(
|
||||||
'packages' =>
|
'packages' =>
|
||||||
array(
|
array(
|
||||||
'4b569463' =>
|
'acc46105' =>
|
||||||
array(
|
array(
|
||||||
'name' => 'core.pkg.css',
|
'name' => 'core.pkg.css',
|
||||||
'symbols' =>
|
'symbols' =>
|
||||||
|
@ -3443,7 +3443,7 @@ celerity_register_resource_map(array(
|
||||||
35 => 'phabricator-object-item-list-view-css',
|
35 => 'phabricator-object-item-list-view-css',
|
||||||
36 => 'global-drag-and-drop-css',
|
36 => 'global-drag-and-drop-css',
|
||||||
),
|
),
|
||||||
'uri' => '/res/pkg/4b569463/core.pkg.css',
|
'uri' => '/res/pkg/acc46105/core.pkg.css',
|
||||||
'type' => 'css',
|
'type' => 'css',
|
||||||
),
|
),
|
||||||
'bc0774e5' =>
|
'bc0774e5' =>
|
||||||
|
@ -3631,17 +3631,17 @@ celerity_register_resource_map(array(
|
||||||
'reverse' =>
|
'reverse' =>
|
||||||
array(
|
array(
|
||||||
'aphront-attached-file-view-css' => 'e30a3fa8',
|
'aphront-attached-file-view-css' => 'e30a3fa8',
|
||||||
'aphront-crumbs-view-css' => '4b569463',
|
'aphront-crumbs-view-css' => 'acc46105',
|
||||||
'aphront-dialog-view-css' => '4b569463',
|
'aphront-dialog-view-css' => 'acc46105',
|
||||||
'aphront-error-view-css' => '4b569463',
|
'aphront-error-view-css' => 'acc46105',
|
||||||
'aphront-form-view-css' => '4b569463',
|
'aphront-form-view-css' => 'acc46105',
|
||||||
'aphront-list-filter-view-css' => '4b569463',
|
'aphront-list-filter-view-css' => 'acc46105',
|
||||||
'aphront-pager-view-css' => '4b569463',
|
'aphront-pager-view-css' => 'acc46105',
|
||||||
'aphront-panel-view-css' => '4b569463',
|
'aphront-panel-view-css' => 'acc46105',
|
||||||
'aphront-table-view-css' => '4b569463',
|
'aphront-table-view-css' => 'acc46105',
|
||||||
'aphront-tokenizer-control-css' => '4b569463',
|
'aphront-tokenizer-control-css' => 'acc46105',
|
||||||
'aphront-tooltip-css' => '4b569463',
|
'aphront-tooltip-css' => 'acc46105',
|
||||||
'aphront-typeahead-control-css' => '4b569463',
|
'aphront-typeahead-control-css' => 'acc46105',
|
||||||
'differential-changeset-view-css' => '8aaacd1b',
|
'differential-changeset-view-css' => '8aaacd1b',
|
||||||
'differential-core-view-css' => '8aaacd1b',
|
'differential-core-view-css' => '8aaacd1b',
|
||||||
'differential-inline-comment-editor' => '95d0d865',
|
'differential-inline-comment-editor' => '95d0d865',
|
||||||
|
@ -3655,7 +3655,7 @@ celerity_register_resource_map(array(
|
||||||
'differential-table-of-contents-css' => '8aaacd1b',
|
'differential-table-of-contents-css' => '8aaacd1b',
|
||||||
'diffusion-commit-view-css' => 'c8ce2d88',
|
'diffusion-commit-view-css' => 'c8ce2d88',
|
||||||
'diffusion-icons-css' => 'c8ce2d88',
|
'diffusion-icons-css' => 'c8ce2d88',
|
||||||
'global-drag-and-drop-css' => '4b569463',
|
'global-drag-and-drop-css' => 'acc46105',
|
||||||
'inline-comment-summary-css' => '8aaacd1b',
|
'inline-comment-summary-css' => '8aaacd1b',
|
||||||
'javelin-aphlict' => 'bc0774e5',
|
'javelin-aphlict' => 'bc0774e5',
|
||||||
'javelin-behavior' => 'd466c034',
|
'javelin-behavior' => 'd466c034',
|
||||||
|
@ -3724,48 +3724,48 @@ celerity_register_resource_map(array(
|
||||||
'javelin-util' => 'd466c034',
|
'javelin-util' => 'd466c034',
|
||||||
'javelin-vector' => 'd466c034',
|
'javelin-vector' => 'd466c034',
|
||||||
'javelin-workflow' => 'd466c034',
|
'javelin-workflow' => 'd466c034',
|
||||||
'lightbox-attachment-css' => '4b569463',
|
'lightbox-attachment-css' => 'acc46105',
|
||||||
'maniphest-task-summary-css' => 'e30a3fa8',
|
'maniphest-task-summary-css' => 'e30a3fa8',
|
||||||
'maniphest-transaction-detail-css' => 'e30a3fa8',
|
'maniphest-transaction-detail-css' => 'e30a3fa8',
|
||||||
'phabricator-busy' => 'bc0774e5',
|
'phabricator-busy' => 'bc0774e5',
|
||||||
'phabricator-content-source-view-css' => '8aaacd1b',
|
'phabricator-content-source-view-css' => '8aaacd1b',
|
||||||
'phabricator-core-buttons-css' => '4b569463',
|
'phabricator-core-buttons-css' => 'acc46105',
|
||||||
'phabricator-core-css' => '4b569463',
|
'phabricator-core-css' => 'acc46105',
|
||||||
'phabricator-crumbs-view-css' => '4b569463',
|
'phabricator-crumbs-view-css' => 'acc46105',
|
||||||
'phabricator-directory-css' => '4b569463',
|
'phabricator-directory-css' => 'acc46105',
|
||||||
'phabricator-drag-and-drop-file-upload' => '95d0d865',
|
'phabricator-drag-and-drop-file-upload' => '95d0d865',
|
||||||
'phabricator-dropdown-menu' => 'bc0774e5',
|
'phabricator-dropdown-menu' => 'bc0774e5',
|
||||||
'phabricator-file-upload' => 'bc0774e5',
|
'phabricator-file-upload' => 'bc0774e5',
|
||||||
'phabricator-filetree-view-css' => '4b569463',
|
'phabricator-filetree-view-css' => 'acc46105',
|
||||||
'phabricator-flag-css' => '4b569463',
|
'phabricator-flag-css' => 'acc46105',
|
||||||
'phabricator-form-view-css' => '4b569463',
|
'phabricator-form-view-css' => 'acc46105',
|
||||||
'phabricator-header-view-css' => '4b569463',
|
'phabricator-header-view-css' => 'acc46105',
|
||||||
'phabricator-jump-nav' => '4b569463',
|
'phabricator-jump-nav' => 'acc46105',
|
||||||
'phabricator-keyboard-shortcut' => 'bc0774e5',
|
'phabricator-keyboard-shortcut' => 'bc0774e5',
|
||||||
'phabricator-keyboard-shortcut-manager' => 'bc0774e5',
|
'phabricator-keyboard-shortcut-manager' => 'bc0774e5',
|
||||||
'phabricator-main-menu-view' => '4b569463',
|
'phabricator-main-menu-view' => 'acc46105',
|
||||||
'phabricator-menu-item' => 'bc0774e5',
|
'phabricator-menu-item' => 'bc0774e5',
|
||||||
'phabricator-nav-view-css' => '4b569463',
|
'phabricator-nav-view-css' => 'acc46105',
|
||||||
'phabricator-notification' => 'bc0774e5',
|
'phabricator-notification' => 'bc0774e5',
|
||||||
'phabricator-notification-css' => '4b569463',
|
'phabricator-notification-css' => 'acc46105',
|
||||||
'phabricator-notification-menu-css' => '4b569463',
|
'phabricator-notification-menu-css' => 'acc46105',
|
||||||
'phabricator-object-item-list-view-css' => '4b569463',
|
'phabricator-object-item-list-view-css' => 'acc46105',
|
||||||
'phabricator-object-selector-css' => '8aaacd1b',
|
'phabricator-object-selector-css' => '8aaacd1b',
|
||||||
'phabricator-paste-file-upload' => 'bc0774e5',
|
'phabricator-paste-file-upload' => 'bc0774e5',
|
||||||
'phabricator-prefab' => 'bc0774e5',
|
'phabricator-prefab' => 'bc0774e5',
|
||||||
'phabricator-project-tag-css' => 'e30a3fa8',
|
'phabricator-project-tag-css' => 'e30a3fa8',
|
||||||
'phabricator-remarkup-css' => '4b569463',
|
'phabricator-remarkup-css' => 'acc46105',
|
||||||
'phabricator-shaped-request' => '95d0d865',
|
'phabricator-shaped-request' => '95d0d865',
|
||||||
'phabricator-side-menu-view-css' => '4b569463',
|
'phabricator-side-menu-view-css' => 'acc46105',
|
||||||
'phabricator-standard-page-view' => '4b569463',
|
'phabricator-standard-page-view' => 'acc46105',
|
||||||
'phabricator-textareautils' => 'bc0774e5',
|
'phabricator-textareautils' => 'bc0774e5',
|
||||||
'phabricator-tooltip' => 'bc0774e5',
|
'phabricator-tooltip' => 'bc0774e5',
|
||||||
'phabricator-transaction-view-css' => '4b569463',
|
'phabricator-transaction-view-css' => 'acc46105',
|
||||||
'phabricator-zindex-css' => '4b569463',
|
'phabricator-zindex-css' => 'acc46105',
|
||||||
'sprite-apps-large-css' => '4b569463',
|
'sprite-apps-large-css' => 'acc46105',
|
||||||
'sprite-gradient-css' => '4b569463',
|
'sprite-gradient-css' => 'acc46105',
|
||||||
'sprite-icon-css' => '4b569463',
|
'sprite-icon-css' => 'acc46105',
|
||||||
'sprite-menu-css' => '4b569463',
|
'sprite-menu-css' => 'acc46105',
|
||||||
'syntax-highlighting-css' => '4b569463',
|
'syntax-highlighting-css' => 'acc46105',
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
|
|
|
@ -1259,6 +1259,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorSetupCheckExtraConfig' => 'applications/config/check/PhabricatorSetupCheckExtraConfig.php',
|
'PhabricatorSetupCheckExtraConfig' => 'applications/config/check/PhabricatorSetupCheckExtraConfig.php',
|
||||||
'PhabricatorSetupCheckFacebook' => 'applications/config/check/PhabricatorSetupCheckFacebook.php',
|
'PhabricatorSetupCheckFacebook' => 'applications/config/check/PhabricatorSetupCheckFacebook.php',
|
||||||
'PhabricatorSetupCheckGD' => 'applications/config/check/PhabricatorSetupCheckGD.php',
|
'PhabricatorSetupCheckGD' => 'applications/config/check/PhabricatorSetupCheckGD.php',
|
||||||
|
'PhabricatorSetupCheckImagemagick' => 'applications/config/check/PhabricatorSetupCheckImagemagick.php',
|
||||||
'PhabricatorSetupCheckInvalidConfig' => 'applications/config/check/PhabricatorSetupCheckInvalidConfig.php',
|
'PhabricatorSetupCheckInvalidConfig' => 'applications/config/check/PhabricatorSetupCheckInvalidConfig.php',
|
||||||
'PhabricatorSetupCheckMail' => 'applications/config/check/PhabricatorSetupCheckMail.php',
|
'PhabricatorSetupCheckMail' => 'applications/config/check/PhabricatorSetupCheckMail.php',
|
||||||
'PhabricatorSetupCheckMySQL' => 'applications/config/check/PhabricatorSetupCheckMySQL.php',
|
'PhabricatorSetupCheckMySQL' => 'applications/config/check/PhabricatorSetupCheckMySQL.php',
|
||||||
|
@ -1409,6 +1410,7 @@ phutil_register_library_map(array(
|
||||||
'PholioController' => 'applications/pholio/controller/PholioController.php',
|
'PholioController' => 'applications/pholio/controller/PholioController.php',
|
||||||
'PholioDAO' => 'applications/pholio/storage/PholioDAO.php',
|
'PholioDAO' => 'applications/pholio/storage/PholioDAO.php',
|
||||||
'PholioImage' => 'applications/pholio/storage/PholioImage.php',
|
'PholioImage' => 'applications/pholio/storage/PholioImage.php',
|
||||||
|
'PholioInlineController' => 'applications/pholio/controller/PholioInlineController.php',
|
||||||
'PholioInlineSaveController' => 'applications/pholio/controller/PholioInlineSaveController.php',
|
'PholioInlineSaveController' => 'applications/pholio/controller/PholioInlineSaveController.php',
|
||||||
'PholioMock' => 'applications/pholio/storage/PholioMock.php',
|
'PholioMock' => 'applications/pholio/storage/PholioMock.php',
|
||||||
'PholioMockCommentController' => 'applications/pholio/controller/PholioMockCommentController.php',
|
'PholioMockCommentController' => 'applications/pholio/controller/PholioMockCommentController.php',
|
||||||
|
@ -2673,6 +2675,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorSetupCheckExtraConfig' => 'PhabricatorSetupCheck',
|
'PhabricatorSetupCheckExtraConfig' => 'PhabricatorSetupCheck',
|
||||||
'PhabricatorSetupCheckFacebook' => 'PhabricatorSetupCheck',
|
'PhabricatorSetupCheckFacebook' => 'PhabricatorSetupCheck',
|
||||||
'PhabricatorSetupCheckGD' => 'PhabricatorSetupCheck',
|
'PhabricatorSetupCheckGD' => 'PhabricatorSetupCheck',
|
||||||
|
'PhabricatorSetupCheckImagemagick' => 'PhabricatorSetupCheck',
|
||||||
'PhabricatorSetupCheckInvalidConfig' => 'PhabricatorSetupCheck',
|
'PhabricatorSetupCheckInvalidConfig' => 'PhabricatorSetupCheck',
|
||||||
'PhabricatorSetupCheckMail' => 'PhabricatorSetupCheck',
|
'PhabricatorSetupCheckMail' => 'PhabricatorSetupCheck',
|
||||||
'PhabricatorSetupCheckMySQL' => 'PhabricatorSetupCheck',
|
'PhabricatorSetupCheckMySQL' => 'PhabricatorSetupCheck',
|
||||||
|
@ -2827,6 +2830,7 @@ phutil_register_library_map(array(
|
||||||
0 => 'PholioDAO',
|
0 => 'PholioDAO',
|
||||||
1 => 'PhabricatorMarkupInterface',
|
1 => 'PhabricatorMarkupInterface',
|
||||||
),
|
),
|
||||||
|
'PholioInlineController' => 'PholioController',
|
||||||
'PholioInlineSaveController' => 'PholioController',
|
'PholioInlineSaveController' => 'PholioController',
|
||||||
'PholioMock' =>
|
'PholioMock' =>
|
||||||
array(
|
array(
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorSetupCheckImagemagick extends PhabricatorSetupCheck {
|
||||||
|
|
||||||
|
protected function executeChecks() {
|
||||||
|
$imagemagick = PhabricatorEnv::getEnvConfig('files.enable-imagemagick');
|
||||||
|
if ($imagemagick) {
|
||||||
|
list($err) = exec_manual('which convert');
|
||||||
|
if ($err) {
|
||||||
|
$message = pht(
|
||||||
|
'You have enabled Imagemagick in your config, but the \'convert\''.
|
||||||
|
' binary is not in the webserver\'s $PATH. Disable imagemagick'.
|
||||||
|
' or make it available to the webserver.');
|
||||||
|
|
||||||
|
$this->newIssue('files.enable-imagemagick')
|
||||||
|
->setName(pht(
|
||||||
|
"'convert' binary not found or Imagemagick is not installed."))
|
||||||
|
->setMessage($message)
|
||||||
|
->addPhabricatorConfig('files.enable-imagemagick')
|
||||||
|
->addPhabricatorConfig('environment.append-paths');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -133,7 +133,7 @@ final class PhabricatorCoreConfigOptions
|
||||||
->setDescription(
|
->setDescription(
|
||||||
pht('Array containing list of Uninstalled applications.')
|
pht('Array containing list of Uninstalled applications.')
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function didValidateOption(
|
protected function didValidateOption(
|
||||||
|
|
|
@ -64,6 +64,7 @@ final class ConpherenceUpdateController extends
|
||||||
$top = $request->getInt('image_y');
|
$top = $request->getInt('image_y');
|
||||||
$left = $request->getInt('image_x');
|
$left = $request->getInt('image_x');
|
||||||
$file_id = $request->getInt('file_id');
|
$file_id = $request->getInt('file_id');
|
||||||
|
$title = $request->getStr('title');
|
||||||
if ($file_id) {
|
if ($file_id) {
|
||||||
$orig_file = id(new PhabricatorFileQuery())
|
$orig_file = id(new PhabricatorFileQuery())
|
||||||
->setViewer($user)
|
->setViewer($user)
|
||||||
|
@ -101,6 +102,8 @@ final class ConpherenceUpdateController extends
|
||||||
pht('This server only supports these image formats: %s.',
|
pht('This server only supports these image formats: %s.',
|
||||||
implode(', ', $supported_formats));
|
implode(', ', $supported_formats));
|
||||||
}
|
}
|
||||||
|
// use the existing title in this image upload case
|
||||||
|
$title = $conpherence->getTitle();
|
||||||
} else if ($top !== null || $left !== null) {
|
} else if ($top !== null || $left !== null) {
|
||||||
$file = $conpherence->getImage(ConpherenceImageData::SIZE_ORIG);
|
$file = $conpherence->getImage(ConpherenceImageData::SIZE_ORIG);
|
||||||
$xformer = new PhabricatorImageTransformer();
|
$xformer = new PhabricatorImageTransformer();
|
||||||
|
@ -119,7 +122,6 @@ final class ConpherenceUpdateController extends
|
||||||
)
|
)
|
||||||
->setNewValue($image_phid);
|
->setNewValue($image_phid);
|
||||||
}
|
}
|
||||||
$title = $request->getStr('title');
|
|
||||||
if ($title != $conpherence->getTitle()) {
|
if ($title != $conpherence->getTitle()) {
|
||||||
$xactions[] = id(new ConpherenceTransaction())
|
$xactions[] = id(new ConpherenceTransaction())
|
||||||
->setTransactionType(ConpherenceTransactionType::TYPE_TITLE)
|
->setTransactionType(ConpherenceTransactionType::TYPE_TITLE)
|
||||||
|
|
|
@ -5,6 +5,16 @@
|
||||||
*/
|
*/
|
||||||
final class ConpherenceReplyHandler extends PhabricatorMailReplyHandler {
|
final class ConpherenceReplyHandler extends PhabricatorMailReplyHandler {
|
||||||
|
|
||||||
|
private $mailAddedParticipantPHIDs;
|
||||||
|
|
||||||
|
public function setMailAddedParticipantPHIDs(array $phids) {
|
||||||
|
$this->mailAddedParticipantPHIDs = $phids;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
public function getMailAddedParticipantPHIDs() {
|
||||||
|
return $this->mailAddedParticipantPHIDs;
|
||||||
|
}
|
||||||
|
|
||||||
public function validateMailReceiver($mail_receiver) {
|
public function validateMailReceiver($mail_receiver) {
|
||||||
if (!($mail_receiver instanceof ConpherenceThread)) {
|
if (!($mail_receiver instanceof ConpherenceThread)) {
|
||||||
throw new Exception("Mail receiver is not a ConpherenceThread!");
|
throw new Exception("Mail receiver is not a ConpherenceThread!");
|
||||||
|
@ -67,14 +77,25 @@ final class ConpherenceReplyHandler extends PhabricatorMailReplyHandler {
|
||||||
$file_phids,
|
$file_phids,
|
||||||
'{F%d}'
|
'{F%d}'
|
||||||
);
|
);
|
||||||
$xactions = $editor->generateTransactionsFromText(
|
|
||||||
$conpherence,
|
$xactions = array();
|
||||||
$body
|
if ($this->getMailAddedParticipantPHIDs()) {
|
||||||
|
$xactions[] = id(new ConpherenceTransaction())
|
||||||
|
->setTransactionType(ConpherenceTransactionType::TYPE_PARTICIPANTS)
|
||||||
|
->setNewValue(array('+' => $this->getMailAddedParticipantPHIDs()));
|
||||||
|
}
|
||||||
|
|
||||||
|
$xactions = array_merge(
|
||||||
|
$xactions,
|
||||||
|
$editor->generateTransactionsFromText(
|
||||||
|
$conpherence,
|
||||||
|
$body
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
$editor->applyTransactions($conpherence, $xactions);
|
$editor->applyTransactions($conpherence, $xactions);
|
||||||
|
|
||||||
return null;
|
return $conpherence;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,12 +46,17 @@ final class ConpherenceTransaction extends PhabricatorApplicationTransaction {
|
||||||
|
|
||||||
switch ($this->getTransactionType()) {
|
switch ($this->getTransactionType()) {
|
||||||
case ConpherenceTransactionType::TYPE_TITLE:
|
case ConpherenceTransactionType::TYPE_TITLE:
|
||||||
if ($old) {
|
if ($old && $new) {
|
||||||
$title = pht(
|
$title = pht(
|
||||||
'%s renamed this conpherence from "%s" to "%s".',
|
'%s renamed this conpherence from "%s" to "%s".',
|
||||||
$this->renderHandleLink($author_phid),
|
$this->renderHandleLink($author_phid),
|
||||||
phutil_escape_html($old),
|
phutil_escape_html($old),
|
||||||
phutil_escape_html($new));
|
phutil_escape_html($new));
|
||||||
|
} else if ($old) {
|
||||||
|
$title = pht(
|
||||||
|
'%s deleted the conpherence name "%s".',
|
||||||
|
$this->renderHandleLink($author_phid),
|
||||||
|
phutil_escape_html($old));
|
||||||
} else {
|
} else {
|
||||||
$title = pht(
|
$title = pht(
|
||||||
'%s named this conpherence "%s".',
|
'%s named this conpherence "%s".',
|
||||||
|
|
|
@ -172,7 +172,7 @@ class DifferentialReplyHandler extends PhabricatorMailReplyHandler {
|
||||||
DifferentialRevisionEditor::removeCCAndUpdateRevision(
|
DifferentialRevisionEditor::removeCCAndUpdateRevision(
|
||||||
$revision,
|
$revision,
|
||||||
$user->getPHID(),
|
$user->getPHID(),
|
||||||
$user->getPHID());
|
$user);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -59,13 +59,13 @@ final class DifferentialSubscribeController extends DifferentialController {
|
||||||
DifferentialRevisionEditor::addCCAndUpdateRevision(
|
DifferentialRevisionEditor::addCCAndUpdateRevision(
|
||||||
$revision,
|
$revision,
|
||||||
$phid,
|
$phid,
|
||||||
$phid);
|
$user);
|
||||||
break;
|
break;
|
||||||
case 'rem':
|
case 'rem':
|
||||||
DifferentialRevisionEditor::removeCCAndUpdateRevision(
|
DifferentialRevisionEditor::removeCCAndUpdateRevision(
|
||||||
$revision,
|
$revision,
|
||||||
$phid,
|
$phid,
|
||||||
$phid);
|
$user);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return new Aphront400Response();
|
return new Aphront400Response();
|
||||||
|
|
|
@ -496,12 +496,13 @@ final class DifferentialRevisionEditor extends PhabricatorEditor {
|
||||||
public static function addCCAndUpdateRevision(
|
public static function addCCAndUpdateRevision(
|
||||||
$revision,
|
$revision,
|
||||||
$phid,
|
$phid,
|
||||||
$reason) {
|
PhabricatorUser $actor) {
|
||||||
|
|
||||||
self::addCC($revision, $phid, $reason);
|
self::addCC($revision, $phid, $actor->getPHID());
|
||||||
|
|
||||||
$type = PhabricatorEdgeConfig::TYPE_OBJECT_HAS_UNSUBSCRIBER;
|
$type = PhabricatorEdgeConfig::TYPE_OBJECT_HAS_UNSUBSCRIBER;
|
||||||
id(new PhabricatorEdgeEditor())
|
id(new PhabricatorEdgeEditor())
|
||||||
|
->setActor($actor)
|
||||||
->removeEdge($revision->getPHID(), $type, $phid)
|
->removeEdge($revision->getPHID(), $type, $phid)
|
||||||
->save();
|
->save();
|
||||||
}
|
}
|
||||||
|
@ -509,12 +510,13 @@ final class DifferentialRevisionEditor extends PhabricatorEditor {
|
||||||
public static function removeCCAndUpdateRevision(
|
public static function removeCCAndUpdateRevision(
|
||||||
$revision,
|
$revision,
|
||||||
$phid,
|
$phid,
|
||||||
$reason) {
|
PhabricatorUser $actor) {
|
||||||
|
|
||||||
self::removeCC($revision, $phid, $reason);
|
self::removeCC($revision, $phid, $actor->getPHID());
|
||||||
|
|
||||||
$type = PhabricatorEdgeConfig::TYPE_OBJECT_HAS_UNSUBSCRIBER;
|
$type = PhabricatorEdgeConfig::TYPE_OBJECT_HAS_UNSUBSCRIBER;
|
||||||
id(new PhabricatorEdgeEditor())
|
id(new PhabricatorEdgeEditor())
|
||||||
|
->setActor($actor)
|
||||||
->addEdge($revision->getPHID(), $type, $phid)
|
->addEdge($revision->getPHID(), $type, $phid)
|
||||||
->save();
|
->save();
|
||||||
}
|
}
|
||||||
|
|
|
@ -253,10 +253,15 @@ final class DifferentialChangesetListView extends AphrontView {
|
||||||
|
|
||||||
$repository = $this->repository;
|
$repository = $this->repository;
|
||||||
if ($repository) {
|
if ($repository) {
|
||||||
$meta['diffusionURI'] = (string)$repository->getDiffusionBrowseURIForPath(
|
try {
|
||||||
$changeset->getAbsoluteRepositoryPath($repository, $this->diff),
|
$meta['diffusionURI'] =
|
||||||
idx($changeset->getMetadata(), 'line:first'),
|
(string)$repository->getDiffusionBrowseURIForPath(
|
||||||
$this->getBranch());
|
$changeset->getAbsoluteRepositoryPath($repository, $this->diff),
|
||||||
|
idx($changeset->getMetadata(), 'line:first'),
|
||||||
|
$this->getBranch());
|
||||||
|
} catch (DiffusionSetupException $e) {
|
||||||
|
// Ignore
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$change = $changeset->getChangeType();
|
$change = $changeset->getChangeType();
|
||||||
|
|
|
@ -2,6 +2,9 @@
|
||||||
|
|
||||||
final class DivinerGenerateWorkflow extends DivinerWorkflow {
|
final class DivinerGenerateWorkflow extends DivinerWorkflow {
|
||||||
|
|
||||||
|
private $config;
|
||||||
|
private $atomCache;
|
||||||
|
|
||||||
public function didConstruct() {
|
public function didConstruct() {
|
||||||
$this
|
$this
|
||||||
->setName('generate')
|
->setName('generate')
|
||||||
|
@ -12,10 +15,37 @@ final class DivinerGenerateWorkflow extends DivinerWorkflow {
|
||||||
'name' => 'clean',
|
'name' => 'clean',
|
||||||
'help' => 'Clear the caches before generating documentation.',
|
'help' => 'Clear the caches before generating documentation.',
|
||||||
),
|
),
|
||||||
|
array(
|
||||||
|
'name' => 'book',
|
||||||
|
'param' => 'path',
|
||||||
|
'help' => 'Path to a Diviner book configuration.',
|
||||||
|
),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function getConfig($key, $default = null) {
|
||||||
|
return idx($this->config, $key, $default);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getAtomCache() {
|
||||||
|
if (!$this->atomCache) {
|
||||||
|
$book_root = $this->getConfig('root');
|
||||||
|
$book_name = $this->getConfig('name');
|
||||||
|
$cache_directory = $book_root.'/.divinercache/'.$book_name;
|
||||||
|
$this->atomCache = new DivinerAtomCache($cache_directory);
|
||||||
|
}
|
||||||
|
return $this->atomCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function log($message) {
|
||||||
|
$console = PhutilConsole::getConsole();
|
||||||
|
$console->getServer()->setEnableLog(true);
|
||||||
|
$console->writeLog($message."\n");
|
||||||
|
}
|
||||||
|
|
||||||
public function execute(PhutilArgumentParser $args) {
|
public function execute(PhutilArgumentParser $args) {
|
||||||
|
$this->readBookConfiguration($args);
|
||||||
|
|
||||||
if ($args->getArg('clean')) {
|
if ($args->getArg('clean')) {
|
||||||
$this->log(pht('CLEARING CACHES'));
|
$this->log(pht('CLEARING CACHES'));
|
||||||
$this->getAtomCache()->delete();
|
$this->getAtomCache()->delete();
|
||||||
|
@ -170,7 +200,7 @@ final class DivinerGenerateWorkflow extends DivinerWorkflow {
|
||||||
|
|
||||||
|
|
||||||
private function findFilesInProject() {
|
private function findFilesInProject() {
|
||||||
$file_hashes = id(new FileFinder($this->getRoot()))
|
$file_hashes = id(new FileFinder($this->getConfig('root')))
|
||||||
->excludePath('*/.*')
|
->excludePath('*/.*')
|
||||||
->withType('f')
|
->withType('f')
|
||||||
->setGenerateChecksums(true)
|
->setGenerateChecksums(true)
|
||||||
|
@ -222,11 +252,11 @@ final class DivinerGenerateWorkflow extends DivinerWorkflow {
|
||||||
foreach ($atomizers as $class => $files) {
|
foreach ($atomizers as $class => $files) {
|
||||||
foreach (array_chunk($files, 32) as $chunk) {
|
foreach (array_chunk($files, 32) as $chunk) {
|
||||||
$future = new ExecFuture(
|
$future = new ExecFuture(
|
||||||
'%s atomize --atomizer %s -- %Ls',
|
'%s atomize --ugly --atomizer %s -- %Ls',
|
||||||
dirname(phutil_get_library_root('phabricator')).'/bin/diviner',
|
dirname(phutil_get_library_root('phabricator')).'/bin/diviner',
|
||||||
$class,
|
$class,
|
||||||
$chunk);
|
$chunk);
|
||||||
$future->setCWD($this->getRoot());
|
$future->setCWD($this->getConfig('root'));
|
||||||
|
|
||||||
$futures[] = $future;
|
$futures[] = $future;
|
||||||
}
|
}
|
||||||
|
@ -381,4 +411,42 @@ final class DivinerGenerateWorkflow extends DivinerWorkflow {
|
||||||
return md5(serialize($inputs)).'G';
|
return md5(serialize($inputs)).'G';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function readBookConfiguration(PhutilArgumentParser $args) {
|
||||||
|
$book_path = $args->getArg('book');
|
||||||
|
if ($book_path === null) {
|
||||||
|
throw new PhutilArgumentUsageException(
|
||||||
|
"Specify a Diviner book configuration file with --book.");
|
||||||
|
}
|
||||||
|
|
||||||
|
$book_data = Filesystem::readFile($book_path);
|
||||||
|
$book = json_decode($book_data, true);
|
||||||
|
if (!is_array($book)) {
|
||||||
|
throw new PhutilArgumentUsageException(
|
||||||
|
"Book configuration '{$book_path}' is not in JSON format.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the book specifies a "root", resolve it; otherwise, use the directory
|
||||||
|
// the book configuration file lives in.
|
||||||
|
$full_path = dirname(Filesystem::resolvePath($book_path));
|
||||||
|
if (empty($book['root'])) {
|
||||||
|
$book['root'] = '.';
|
||||||
|
}
|
||||||
|
$book['root'] = Filesystem::resolvePath($book['root'], $full_path);
|
||||||
|
|
||||||
|
// Make sure we have a valid book name.
|
||||||
|
if (!isset($book['name'])) {
|
||||||
|
throw new PhutilArgumentUsageException(
|
||||||
|
"Book configuration '{$book_path}' is missing required ".
|
||||||
|
"property 'name'.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!preg_match('/^[a-z][a-z-]*$/', $book['name'])) {
|
||||||
|
$name = $book['name'];
|
||||||
|
throw new PhutilArgumentUsageException(
|
||||||
|
"Book configuration '{$book_path}' has name '{$name}', but book names ".
|
||||||
|
"must include only lowercase letters and hyphens.");
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->config = $book;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,32 +2,8 @@
|
||||||
|
|
||||||
abstract class DivinerWorkflow extends PhutilArgumentWorkflow {
|
abstract class DivinerWorkflow extends PhutilArgumentWorkflow {
|
||||||
|
|
||||||
private $atomCache;
|
|
||||||
|
|
||||||
public function isExecutable() {
|
public function isExecutable() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function getRoot() {
|
|
||||||
return getcwd();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function getConfig($key, $default = null) {
|
|
||||||
return $default;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function getAtomCache() {
|
|
||||||
if (!$this->atomCache) {
|
|
||||||
$cache_directory = $this->getRoot().'/.divinercache';
|
|
||||||
$this->atomCache = new DivinerAtomCache($cache_directory);
|
|
||||||
}
|
|
||||||
return $this->atomCache;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function log($message) {
|
|
||||||
$console = PhutilConsole::getConsole();
|
|
||||||
$console->getServer()->setEnableLog(true);
|
|
||||||
$console->writeLog($message."\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,8 +95,14 @@ final class PhabricatorImageTransformer {
|
||||||
$scaled_y = $min_y;
|
$scaled_y = $min_y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$cropped = $this->applyScaleWithImagemagick($file, $x, $scaled_y);
|
||||||
|
|
||||||
|
if ($cropped != null) {
|
||||||
|
return $cropped;
|
||||||
|
}
|
||||||
|
|
||||||
$img = $this->applyScaleTo(
|
$img = $this->applyScaleTo(
|
||||||
$img,
|
$file,
|
||||||
$x,
|
$x,
|
||||||
$scaled_y);
|
$scaled_y);
|
||||||
|
|
||||||
|
@ -131,11 +137,13 @@ final class PhabricatorImageTransformer {
|
||||||
* Very crudely scale an image up or down to an exact size.
|
* Very crudely scale an image up or down to an exact size.
|
||||||
*/
|
*/
|
||||||
private function crudelyScaleTo(PhabricatorFile $file, $dx, $dy) {
|
private function crudelyScaleTo(PhabricatorFile $file, $dx, $dy) {
|
||||||
$data = $file->loadFileData();
|
$scaled = $this->applyScaleWithImagemagick($file, $dx, $dy);
|
||||||
$src = imagecreatefromstring($data);
|
|
||||||
|
|
||||||
$dst = $this->applyScaleTo($src, $dx, $dy);
|
if ($scaled != null) {
|
||||||
|
return $scaled;
|
||||||
|
}
|
||||||
|
|
||||||
|
$dst = $this->applyScaleTo($file, $dx, $dy);
|
||||||
return $this->saveImageDataInAnyFormat($dst, $file->getMimeType());
|
return $this->saveImageDataInAnyFormat($dst, $file->getMimeType());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,17 +155,22 @@ final class PhabricatorImageTransformer {
|
||||||
return $dst;
|
return $dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function applyScaleTo($src, $dx, $dy) {
|
private function applyScaleTo(PhabricatorFile $file, $dx, $dy) {
|
||||||
|
$data = $file->loadFileData();
|
||||||
|
$src = imagecreatefromstring($data);
|
||||||
|
|
||||||
$x = imagesx($src);
|
$x = imagesx($src);
|
||||||
$y = imagesy($src);
|
$y = imagesy($src);
|
||||||
|
|
||||||
$scale = min(($dx / $x), ($dy / $y), 1);
|
$scale = min(($dx / $x), ($dy / $y), 1);
|
||||||
|
|
||||||
$dst = $this->getBlankDestinationFile($dx, $dy);
|
|
||||||
|
|
||||||
$sdx = $scale * $x;
|
$sdx = $scale * $x;
|
||||||
$sdy = $scale * $y;
|
$sdy = $scale * $y;
|
||||||
|
|
||||||
|
$dst = $this->getBlankDestinationFile($dx, $dy);
|
||||||
|
imagesavealpha($dst, true);
|
||||||
|
imagefill($dst, 0, 0, imagecolorallocatealpha($dst, 255, 255, 255, 127));
|
||||||
|
|
||||||
imagecopyresampled(
|
imagecopyresampled(
|
||||||
$dst,
|
$dst,
|
||||||
$src,
|
$src,
|
||||||
|
@ -167,6 +180,7 @@ final class PhabricatorImageTransformer {
|
||||||
$x, $y);
|
$x, $y);
|
||||||
|
|
||||||
return $dst;
|
return $dst;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getPreviewDimensions(PhabricatorFile $file, $size) {
|
public static function getPreviewDimensions(PhabricatorFile $file, $size) {
|
||||||
|
@ -337,7 +351,7 @@ final class PhabricatorImageTransformer {
|
||||||
|
|
||||||
private function saveImageDataInAnyFormat($data, $preferred_mime = '') {
|
private function saveImageDataInAnyFormat($data, $preferred_mime = '') {
|
||||||
switch ($preferred_mime) {
|
switch ($preferred_mime) {
|
||||||
case 'image/gif': // GIF doesn't support true color.
|
case 'image/gif': // Gif doesn't support true color
|
||||||
case 'image/png':
|
case 'image/png':
|
||||||
if (function_exists('imagepng')) {
|
if (function_exists('imagepng')) {
|
||||||
ob_start();
|
ob_start();
|
||||||
|
@ -368,4 +382,43 @@ final class PhabricatorImageTransformer {
|
||||||
return $img;
|
return $img;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function applyScaleWithImagemagick(PhabricatorFile $file, $dx, $dy) {
|
||||||
|
|
||||||
|
$img_type = $file->getMimeType();
|
||||||
|
$imagemagick = PhabricatorEnv::getEnvConfig('files.enable-imagemagick');
|
||||||
|
|
||||||
|
if ($img_type != 'image/gif' || $imagemagick == false) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = $file->loadFileData();
|
||||||
|
$src = imagecreatefromstring($data);
|
||||||
|
|
||||||
|
$x = imagesx($src);
|
||||||
|
$y = imagesy($src);
|
||||||
|
|
||||||
|
$scale = min(($dx / $x), ($dy / $y), 1);
|
||||||
|
|
||||||
|
$sdx = $scale * $x;
|
||||||
|
$sdy = $scale * $y;
|
||||||
|
|
||||||
|
$input = new TempFile();
|
||||||
|
Filesystem::writeFile($input, $data);
|
||||||
|
|
||||||
|
$resized = new TempFile();
|
||||||
|
|
||||||
|
list($err) = exec_manual(
|
||||||
|
'convert %s -coalesce -resize %sX%s\! %s'
|
||||||
|
, $input, $sdx, $sdy, $resized
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!$err) {
|
||||||
|
$new_data = Filesystem::readFile($resized);
|
||||||
|
return $new_data;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -119,6 +119,16 @@ final class PhabricatorFilesConfigOptions
|
||||||
"value and the UI will then reflect the actual configured ".
|
"value and the UI will then reflect the actual configured ".
|
||||||
"limit."))
|
"limit."))
|
||||||
->addExample('10M', pht("Valid setting.")),
|
->addExample('10M', pht("Valid setting.")),
|
||||||
|
$this->newOption('files.enable-imagemagick', 'bool', false)
|
||||||
|
->setBoolOptions(
|
||||||
|
array(
|
||||||
|
pht('Enable'),
|
||||||
|
pht('Disable')
|
||||||
|
))->setDescription(
|
||||||
|
pht("This option will enable animated gif images".
|
||||||
|
"to be set as profile pictures. The \'convert\' binary ".
|
||||||
|
"should be available to the webserver for this to work")),
|
||||||
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -101,7 +101,8 @@ final class PhabricatorApplicationLaunchView extends AphrontView {
|
||||||
'span',
|
'span',
|
||||||
array(
|
array(
|
||||||
'class' => implode(' ', $classes),
|
'class' => implode(' ', $classes),
|
||||||
));
|
),
|
||||||
|
'');
|
||||||
|
|
||||||
$create_button = phutil_tag(
|
$create_button = phutil_tag(
|
||||||
'a',
|
'a',
|
||||||
|
|
|
@ -78,7 +78,10 @@ final class PhabricatorMetaMTAReceivedMail extends PhabricatorMetaMTADAO {
|
||||||
/**
|
/**
|
||||||
* Parses "to" addresses, looking for a public create email address
|
* Parses "to" addresses, looking for a public create email address
|
||||||
* first and if not found parsing the "to" address for reply handler
|
* first and if not found parsing the "to" address for reply handler
|
||||||
* information: receiver name, user id, and hash.
|
* information: receiver name, user id, and hash. If nothing can be
|
||||||
|
* found, it then loads user phids for as many to: email addresses as
|
||||||
|
* it can, theoretically falling back to create a conpherence amongst
|
||||||
|
* those users.
|
||||||
*/
|
*/
|
||||||
private function getPhabricatorToInformation() {
|
private function getPhabricatorToInformation() {
|
||||||
// Only one "public" create address so far
|
// Only one "public" create address so far
|
||||||
|
@ -99,6 +102,8 @@ final class PhabricatorMetaMTAReceivedMail extends PhabricatorMetaMTADAO {
|
||||||
$receiver_name = null;
|
$receiver_name = null;
|
||||||
$user_id = null;
|
$user_id = null;
|
||||||
$hash = null;
|
$hash = null;
|
||||||
|
$user_phids = array();
|
||||||
|
$user_names = array();
|
||||||
foreach ($this->getToAddresses() as $address) {
|
foreach ($this->getToAddresses() as $address) {
|
||||||
if ($address == $create_task) {
|
if ($address == $create_task) {
|
||||||
$phabricator_address = $address;
|
$phabricator_address = $address;
|
||||||
|
@ -121,13 +126,31 @@ final class PhabricatorMetaMTAReceivedMail extends PhabricatorMetaMTADAO {
|
||||||
$hash = $matches[3];
|
$hash = $matches[3];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$parts = explode('@', $address);
|
||||||
|
$maybe_name = trim($parts[0]);
|
||||||
|
$maybe_domain = trim($parts[1]);
|
||||||
|
$mail_domain = PhabricatorEnv::getEnvConfig('metamta.domain');
|
||||||
|
if ($mail_domain == $maybe_domain &&
|
||||||
|
PhabricatorUser::validateUsername($maybe_name)) {
|
||||||
|
$user_names[] = $maybe_name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// since we haven't found a phabricator address, maybe this is
|
||||||
|
// someone trying to create a conpherence?
|
||||||
|
if (!$phabricator_address && $user_names) {
|
||||||
|
$users = id(new PhabricatorUser())
|
||||||
|
->loadAllWhere('userName IN (%Ls)', $user_names);
|
||||||
|
$user_phids = mpull($users, 'getPHID');
|
||||||
}
|
}
|
||||||
|
|
||||||
return array(
|
return array(
|
||||||
$phabricator_address,
|
$phabricator_address,
|
||||||
$receiver_name,
|
$receiver_name,
|
||||||
$user_id,
|
$user_id,
|
||||||
$hash
|
$hash,
|
||||||
|
$user_phids
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,8 +193,9 @@ final class PhabricatorMetaMTAReceivedMail extends PhabricatorMetaMTADAO {
|
||||||
list($to,
|
list($to,
|
||||||
$receiver_name,
|
$receiver_name,
|
||||||
$user_id,
|
$user_id,
|
||||||
$hash) = $this->getPhabricatorToInformation();
|
$hash,
|
||||||
if (!$to) {
|
$user_phids) = $this->getPhabricatorToInformation();
|
||||||
|
if (!$to && !$user_phids) {
|
||||||
$raw_to = idx($this->headers, 'to');
|
$raw_to = idx($this->headers, 'to');
|
||||||
return $this->setMessage("Unrecognized 'to' format: {$raw_to}")->save();
|
return $this->setMessage("Unrecognized 'to' format: {$raw_to}")->save();
|
||||||
}
|
}
|
||||||
|
@ -186,7 +210,7 @@ final class PhabricatorMetaMTAReceivedMail extends PhabricatorMetaMTADAO {
|
||||||
if ($create_task && $to == $create_task) {
|
if ($create_task && $to == $create_task) {
|
||||||
$receiver = new ManiphestTask();
|
$receiver = new ManiphestTask();
|
||||||
|
|
||||||
$user = $this->lookupPublicUser();
|
$user = $this->lookupSender();
|
||||||
if ($user) {
|
if ($user) {
|
||||||
$this->setAuthorPHID($user->getPHID());
|
$this->setAuthorPHID($user->getPHID());
|
||||||
} else {
|
} else {
|
||||||
|
@ -230,12 +254,32 @@ final class PhabricatorMetaMTAReceivedMail extends PhabricatorMetaMTADAO {
|
||||||
return $this->save();
|
return $this->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// means we're creating a conpherence...!
|
||||||
|
if ($user_phids) {
|
||||||
|
// we must have a valid user who created this conpherence
|
||||||
|
$user = $this->lookupSender();
|
||||||
|
if (!$user) {
|
||||||
|
return $this->setMessage("Invalid public user '{$from}'.")->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
$conpherence = id(new ConpherenceReplyHandler())
|
||||||
|
->setMailReceiver(new ConpherenceThread())
|
||||||
|
->setMailAddedParticipantPHIDs($user_phids)
|
||||||
|
->setActor($user)
|
||||||
|
->setExcludeMailRecipientPHIDs($this->loadExcludeMailRecipientPHIDs())
|
||||||
|
->processEmail($this);
|
||||||
|
|
||||||
|
$this->setRelatedPHID($conpherence->getPHID());
|
||||||
|
$this->setMessage('OK');
|
||||||
|
return $this->save();
|
||||||
|
}
|
||||||
|
|
||||||
if ($user_id == 'public') {
|
if ($user_id == 'public') {
|
||||||
if (!PhabricatorEnv::getEnvConfig('metamta.public-replies')) {
|
if (!PhabricatorEnv::getEnvConfig('metamta.public-replies')) {
|
||||||
return $this->setMessage("Public replies not enabled.")->save();
|
return $this->setMessage("Public replies not enabled.")->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
$user = $this->lookupPublicUser();
|
$user = $this->lookupSender();
|
||||||
|
|
||||||
if (!$user) {
|
if (!$user) {
|
||||||
return $this->setMessage("Invalid public user '{$from}'.")->save();
|
return $this->setMessage("Invalid public user '{$from}'.")->save();
|
||||||
|
@ -373,7 +417,7 @@ final class PhabricatorMetaMTAReceivedMail extends PhabricatorMetaMTADAO {
|
||||||
return array_filter($raw_addresses);
|
return array_filter($raw_addresses);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function lookupPublicUser() {
|
private function lookupSender() {
|
||||||
$from = idx($this->headers, 'from');
|
$from = idx($this->headers, 'from');
|
||||||
$from = $this->getRawEmailAddress($from);
|
$from = $this->getRawEmailAddress($from);
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,8 @@ final class PhabricatorApplicationPholio extends PhabricatorApplication {
|
||||||
'new/' => 'PholioMockEditController',
|
'new/' => 'PholioMockEditController',
|
||||||
'edit/(?P<id>\d+)/' => 'PholioMockEditController',
|
'edit/(?P<id>\d+)/' => 'PholioMockEditController',
|
||||||
'comment/(?P<id>\d+)/' => 'PholioMockCommentController',
|
'comment/(?P<id>\d+)/' => 'PholioMockCommentController',
|
||||||
'inline/(?P<id>\d+)/' => 'PholioInlineSaveController',
|
'inline/(?P<id>\d+)/' => 'PholioInlineController',
|
||||||
|
'inline/save/' => 'PholioInlineSaveController',
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group pholio
|
||||||
|
*/
|
||||||
|
final class PholioInlineController extends PholioController {
|
||||||
|
|
||||||
|
private $id;
|
||||||
|
|
||||||
|
public function willProcessRequest(array $data) {
|
||||||
|
$this->id = $data['id'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function processRequest() {
|
||||||
|
$request = $this->getRequest();
|
||||||
|
$user = $request->getUser();
|
||||||
|
|
||||||
|
$inline_comments = id(new PholioTransactionComment())->loadAllWhere(
|
||||||
|
'imageid = %d AND transactionphid IS NOT NULL',
|
||||||
|
$this->id
|
||||||
|
);
|
||||||
|
|
||||||
|
$inlines = array();
|
||||||
|
foreach ($inline_comments as $inline_comment) {
|
||||||
|
$inlines[] = array(
|
||||||
|
'phid' => $inline_comment->getPHID(),
|
||||||
|
'imageID' => $inline_comment->getImageID(),
|
||||||
|
'x' => $inline_comment->getX(),
|
||||||
|
'y' => $inline_comment->getY(),
|
||||||
|
'width' => $inline_comment->getWidth(),
|
||||||
|
'height' => $inline_comment->getHeight(),
|
||||||
|
'content' => $inline_comment->getContent());
|
||||||
|
}
|
||||||
|
|
||||||
|
return id(new AphrontAjaxResponse())->setContent($inlines);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -3,7 +3,7 @@
|
||||||
final class PhabricatorApplicationPhriction extends PhabricatorApplication {
|
final class PhabricatorApplicationPhriction extends PhabricatorApplication {
|
||||||
|
|
||||||
public function getShortDescription() {
|
public function getShortDescription() {
|
||||||
return 'Wiki';
|
return pht('Wiki');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getBaseURI() {
|
public function getBaseURI() {
|
||||||
|
|
|
@ -9,7 +9,7 @@ abstract class PhrictionController extends PhabricatorController {
|
||||||
|
|
||||||
$page = $this->buildStandardPageView();
|
$page = $this->buildStandardPageView();
|
||||||
|
|
||||||
$page->setApplicationName('Phriction');
|
$page->setApplicationName(pht('Phriction'));
|
||||||
$page->setBaseURI('/w/');
|
$page->setBaseURI('/w/');
|
||||||
$page->setTitle(idx($data, 'title'));
|
$page->setTitle(idx($data, 'title'));
|
||||||
$page->setGlyph("\xE2\x9A\xA1");
|
$page->setGlyph("\xE2\x9A\xA1");
|
||||||
|
@ -32,7 +32,7 @@ abstract class PhrictionController extends PhabricatorController {
|
||||||
$nav->addFilter('', pht('Create Document'), '/phriction/new');
|
$nav->addFilter('', pht('Create Document'), '/phriction/new');
|
||||||
}
|
}
|
||||||
|
|
||||||
$nav->addLabel('Filters');
|
$nav->addLabel(pht('Filters'));
|
||||||
$nav->addFilter('active', pht('Active Documents'));
|
$nav->addFilter('active', pht('Active Documents'));
|
||||||
$nav->addFilter('all', pht('All Documents'));
|
$nav->addFilter('all', pht('All Documents'));
|
||||||
$nav->addFilter('updates', pht('Recently Updated'));
|
$nav->addFilter('updates', pht('Recently Updated'));
|
||||||
|
|
|
@ -32,11 +32,11 @@ final class PhrictionDeleteController extends PhrictionController {
|
||||||
|
|
||||||
$dialog = id(new AphrontDialogView())
|
$dialog = id(new AphrontDialogView())
|
||||||
->setUser($user)
|
->setUser($user)
|
||||||
->setTitle('Delete document?')
|
->setTitle(pht('Delete document?'))
|
||||||
->appendChild(
|
->appendChild(
|
||||||
'Really delete this document? You can recover it later by reverting '.
|
pht('Really delete this document? You can recover it later by '.
|
||||||
'to a previous version.')
|
'reverting to a previous version.'))
|
||||||
->addSubmitButton('Delete')
|
->addSubmitButton(pht('Delete'))
|
||||||
->addCancelButton($document_uri);
|
->addCancelButton($document_uri);
|
||||||
|
|
||||||
return id(new AphrontDialogResponse())->setDialog($dialog);
|
return id(new AphrontDialogResponse())->setDialog($dialog);
|
||||||
|
|
|
@ -138,9 +138,9 @@ final class PhrictionDiffController
|
||||||
array(
|
array(
|
||||||
'href' => $uri->alter('l', $l - 1)->alter('r', $r - 1),
|
'href' => $uri->alter('l', $l - 1)->alter('r', $r - 1),
|
||||||
),
|
),
|
||||||
"\xC2\xAB Previous Change");
|
pht("\xC2\xAB Previous Change"));
|
||||||
} else {
|
} else {
|
||||||
$link_l = 'Original Change';
|
$link_l = pht('Original Change');
|
||||||
}
|
}
|
||||||
|
|
||||||
$link_r = null;
|
$link_r = null;
|
||||||
|
@ -150,9 +150,9 @@ final class PhrictionDiffController
|
||||||
array(
|
array(
|
||||||
'href' => $uri->alter('l', $l + 1)->alter('r', $r + 1),
|
'href' => $uri->alter('l', $l + 1)->alter('r', $r + 1),
|
||||||
),
|
),
|
||||||
"Next Change \xC2\xBB");
|
pht("Next Change \xC2\xBB"));
|
||||||
} else {
|
} else {
|
||||||
$link_r = 'Most Recent Change';
|
$link_r = pht('Most Recent Change');
|
||||||
}
|
}
|
||||||
|
|
||||||
$navigation_table =
|
$navigation_table =
|
||||||
|
@ -184,7 +184,7 @@ final class PhrictionDiffController
|
||||||
$output,
|
$output,
|
||||||
),
|
),
|
||||||
array(
|
array(
|
||||||
'title' => 'Document History',
|
'title' => pht('Document History'),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -208,7 +208,7 @@ final class PhrictionDiffController
|
||||||
'href' => '/phriction/edit/'.$document_id.'/',
|
'href' => '/phriction/edit/'.$document_id.'/',
|
||||||
'class' => 'button',
|
'class' => 'button',
|
||||||
),
|
),
|
||||||
'Edit Current Version');
|
pht('Edit Current Version'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -218,7 +218,7 @@ final class PhrictionDiffController
|
||||||
'href' => '/phriction/edit/'.$document_id.'/?revert='.$version,
|
'href' => '/phriction/edit/'.$document_id.'/?revert='.$version,
|
||||||
'class' => 'button',
|
'class' => 'button',
|
||||||
),
|
),
|
||||||
'Revert to Version '.$version.'...');
|
pht('Revert to Version %s...', $version));
|
||||||
}
|
}
|
||||||
|
|
||||||
private function renderComparisonTable(array $content) {
|
private function renderComparisonTable(array $content) {
|
||||||
|
@ -244,11 +244,11 @@ final class PhrictionDiffController
|
||||||
$table = new AphrontTableView($rows);
|
$table = new AphrontTableView($rows);
|
||||||
$table->setHeaders(
|
$table->setHeaders(
|
||||||
array(
|
array(
|
||||||
'Date',
|
pht('Date'),
|
||||||
'Time',
|
pht('Time'),
|
||||||
'Version',
|
pht('Version'),
|
||||||
'Author',
|
pht('Author'),
|
||||||
'Description',
|
pht('Description'),
|
||||||
));
|
));
|
||||||
$table->setColumnClasses(
|
$table->setColumnClasses(
|
||||||
array(
|
array(
|
||||||
|
|
|
@ -45,7 +45,6 @@ final class PhrictionDocumentController
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$create_uri = '/phriction/edit/?slug='.$slug;
|
$create_uri = '/phriction/edit/?slug='.$slug;
|
||||||
|
|
||||||
$page_content = hsprintf(
|
$page_content = hsprintf(
|
||||||
'<div class="phriction-content">'.
|
'<div class="phriction-content">'.
|
||||||
'<em>No content here!</em><br />'.
|
'<em>No content here!</em><br />'.
|
||||||
|
@ -54,7 +53,7 @@ final class PhrictionDocumentController
|
||||||
'</div>',
|
'</div>',
|
||||||
$slug,
|
$slug,
|
||||||
$create_uri);
|
$create_uri);
|
||||||
$page_title = 'Page Not Found';
|
$page_title = pht('Page Not Found');
|
||||||
} else {
|
} else {
|
||||||
$version = $request->getInt('v');
|
$version = $request->getInt('v');
|
||||||
if ($version) {
|
if ($version) {
|
||||||
|
@ -67,13 +66,13 @@ final class PhrictionDocumentController
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($content->getID() != $document->getContentID()) {
|
if ($content->getID() != $document->getContentID()) {
|
||||||
|
$vdate = phabricator_datetime($content->getDateCreated(), $user);
|
||||||
$version_note = new AphrontErrorView();
|
$version_note = new AphrontErrorView();
|
||||||
$version_note->setSeverity(AphrontErrorView::SEVERITY_NOTICE);
|
$version_note->setSeverity(AphrontErrorView::SEVERITY_NOTICE);
|
||||||
$version_note->setTitle('Older Version');
|
$version_note->setTitle('Older Version');
|
||||||
$version_note->appendChild(
|
$version_note->appendChild(
|
||||||
'You are viewing an older version of this document, as it '.
|
pht('You are viewing an older version of this document, as it '.
|
||||||
'appeared on '.
|
'appeared on %s.', $vdate));
|
||||||
phabricator_datetime($content->getDateCreated(), $user).'.');
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$content = id(new PhrictionContent())->load($document->getContentID());
|
$content = id(new PhrictionContent())->load($document->getContentID());
|
||||||
|
@ -139,8 +138,8 @@ final class PhrictionDocumentController
|
||||||
$notice->setSeverity(AphrontErrorView::SEVERITY_NOTICE);
|
$notice->setSeverity(AphrontErrorView::SEVERITY_NOTICE);
|
||||||
$notice->setTitle('Document Deleted');
|
$notice->setTitle('Document Deleted');
|
||||||
$notice->appendChild(
|
$notice->appendChild(
|
||||||
'This document has been deleted. You can edit it to put new content '.
|
pht('This document has been deleted. You can edit it to put new '.
|
||||||
'here, or use history to revert to an earlier version.');
|
'content here, or use history to revert to an earlier version.'));
|
||||||
$core_content = $notice->render();
|
$core_content = $notice->render();
|
||||||
} else {
|
} else {
|
||||||
throw new Exception("Unknown document status '{$doc_status}'!");
|
throw new Exception("Unknown document status '{$doc_status}'!");
|
||||||
|
@ -323,20 +322,22 @@ final class PhrictionDocumentController
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($more_children) {
|
if ($more_children) {
|
||||||
$list[] = '<li>More...</li>';
|
$list[] = '<li>'.pht('More...').'</li>';
|
||||||
}
|
}
|
||||||
$list[] = '</ul>';
|
$list[] = '</ul>';
|
||||||
$list = implode("\n", $list);
|
$list = implode("\n", $list);
|
||||||
|
|
||||||
return
|
return
|
||||||
'<div class="phriction-children">'.
|
'<div class="phriction-children">'.
|
||||||
'<div class="phriction-children-header">Document Hierarchy</div>'.
|
'<div class="phriction-children-header">'.
|
||||||
|
pht('Document Hierarchy').
|
||||||
|
'</div>'.
|
||||||
$list.
|
$list.
|
||||||
'</div>';
|
'</div>';
|
||||||
}
|
}
|
||||||
|
|
||||||
private function renderChildDocumentLink(array $info) {
|
private function renderChildDocumentLink(array $info) {
|
||||||
$title = nonempty($info['title'], '(Untitled Document)');
|
$title = nonempty($info['title'], pht('(Untitled Document)'));
|
||||||
$item = phutil_tag(
|
$item = phutil_tag(
|
||||||
'a',
|
'a',
|
||||||
array(
|
array(
|
||||||
|
|
|
@ -95,8 +95,8 @@ final class PhrictionEditController
|
||||||
$notes = $request->getStr('description');
|
$notes = $request->getStr('description');
|
||||||
|
|
||||||
if (!strlen($title)) {
|
if (!strlen($title)) {
|
||||||
$e_title = 'Required';
|
$e_title = pht('Required');
|
||||||
$errors[] = 'Document title is required.';
|
$errors[] = pht('Document title is required.');
|
||||||
} else {
|
} else {
|
||||||
$e_title = null;
|
$e_title = null;
|
||||||
}
|
}
|
||||||
|
@ -107,9 +107,9 @@ final class PhrictionEditController
|
||||||
|
|
||||||
$dialog = new AphrontDialogView();
|
$dialog = new AphrontDialogView();
|
||||||
$dialog->setUser($user);
|
$dialog->setUser($user);
|
||||||
$dialog->setTitle('No Edits');
|
$dialog->setTitle(pht('No Edits'));
|
||||||
$dialog->appendChild(
|
$dialog->appendChild(
|
||||||
'<p>You did not make any changes to the document.</p>');
|
'<p>'.pht('You did not make any changes to the document.').'</p>');
|
||||||
$dialog->addCancelButton($request->getRequestURI());
|
$dialog->addCancelButton($request->getRequestURI());
|
||||||
|
|
||||||
return id(new AphrontDialogResponse())->setDialog($dialog);
|
return id(new AphrontDialogResponse())->setDialog($dialog);
|
||||||
|
@ -121,9 +121,9 @@ final class PhrictionEditController
|
||||||
|
|
||||||
$dialog = new AphrontDialogView();
|
$dialog = new AphrontDialogView();
|
||||||
$dialog->setUser($user);
|
$dialog->setUser($user);
|
||||||
$dialog->setTitle('Empty Page');
|
$dialog->setTitle(pht('Empty Page'));
|
||||||
$dialog->appendChild(
|
$dialog->appendChild(
|
||||||
'<p>You can not create an empty document.</p>');
|
'<p>'.pht('You can not create an empty document.').'</p>');
|
||||||
$dialog->addCancelButton($request->getRequestURI());
|
$dialog->addCancelButton($request->getRequestURI());
|
||||||
|
|
||||||
return id(new AphrontDialogResponse())->setDialog($dialog);
|
return id(new AphrontDialogResponse())->setDialog($dialog);
|
||||||
|
@ -150,16 +150,16 @@ final class PhrictionEditController
|
||||||
$error_view = null;
|
$error_view = null;
|
||||||
if ($errors) {
|
if ($errors) {
|
||||||
$error_view = id(new AphrontErrorView())
|
$error_view = id(new AphrontErrorView())
|
||||||
->setTitle('Form Errors')
|
->setTitle(pht('Form Errors'))
|
||||||
->setErrors($errors);
|
->setErrors($errors);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($document->getID()) {
|
if ($document->getID()) {
|
||||||
$panel_header = 'Edit Phriction Document';
|
$panel_header = pht('Edit Phriction Document');
|
||||||
$submit_button = 'Save Changes';
|
$submit_button = pht('Save Changes');
|
||||||
} else {
|
} else {
|
||||||
$panel_header = 'Create New Phriction Document';
|
$panel_header = pht('Create New Phriction Document');
|
||||||
$submit_button = 'Create Document';
|
$submit_button = pht('Create Document');
|
||||||
}
|
}
|
||||||
|
|
||||||
$uri = $document->getSlug();
|
$uri = $document->getSlug();
|
||||||
|
@ -178,7 +178,7 @@ final class PhrictionEditController
|
||||||
array(
|
array(
|
||||||
'href' => $request->getRequestURI()->alter('nodraft', true),
|
'href' => $request->getRequestURI()->alter('nodraft', true),
|
||||||
),
|
),
|
||||||
'discard this draft');
|
pht('discard this draft'));
|
||||||
|
|
||||||
$draft_note = new AphrontErrorView();
|
$draft_note = new AphrontErrorView();
|
||||||
$draft_note->setSeverity(AphrontErrorView::SEVERITY_NOTICE);
|
$draft_note->setSeverity(AphrontErrorView::SEVERITY_NOTICE);
|
||||||
|
@ -199,17 +199,17 @@ final class PhrictionEditController
|
||||||
->addHiddenInput('nodraft', $request->getBool('nodraft'))
|
->addHiddenInput('nodraft', $request->getBool('nodraft'))
|
||||||
->appendChild(
|
->appendChild(
|
||||||
id(new AphrontFormTextControl())
|
id(new AphrontFormTextControl())
|
||||||
->setLabel('Title')
|
->setLabel(pht('Title'))
|
||||||
->setValue($content->getTitle())
|
->setValue($content->getTitle())
|
||||||
->setError($e_title)
|
->setError($e_title)
|
||||||
->setName('title'))
|
->setName('title'))
|
||||||
->appendChild(
|
->appendChild(
|
||||||
id(new AphrontFormStaticControl())
|
id(new AphrontFormStaticControl())
|
||||||
->setLabel('URI')
|
->setLabel(pht('URI'))
|
||||||
->setValue($uri))
|
->setValue($uri))
|
||||||
->appendChild(
|
->appendChild(
|
||||||
id(new PhabricatorRemarkupControl())
|
id(new PhabricatorRemarkupControl())
|
||||||
->setLabel('Content')
|
->setLabel(pht('Content'))
|
||||||
->setValue($content_text)
|
->setValue($content_text)
|
||||||
->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_TALL)
|
->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_TALL)
|
||||||
->setName('content')
|
->setName('content')
|
||||||
|
@ -217,7 +217,7 @@ final class PhrictionEditController
|
||||||
->setUser($user))
|
->setUser($user))
|
||||||
->appendChild(
|
->appendChild(
|
||||||
id(new AphrontFormTextControl())
|
id(new AphrontFormTextControl())
|
||||||
->setLabel('Edit Notes')
|
->setLabel(pht('Edit Notes'))
|
||||||
->setValue($notes)
|
->setValue($notes)
|
||||||
->setError(null)
|
->setError(null)
|
||||||
->setName('description'))
|
->setName('description'))
|
||||||
|
@ -227,18 +227,18 @@ final class PhrictionEditController
|
||||||
->setValue($submit_button));
|
->setValue($submit_button));
|
||||||
|
|
||||||
$panel = id(new AphrontPanelView())
|
$panel = id(new AphrontPanelView())
|
||||||
->setWidth(AphrontPanelView::WIDTH_WIDE)
|
->setNoBackground()
|
||||||
->setHeader($panel_header)
|
->setHeader($panel_header)
|
||||||
->appendChild($form);
|
->appendChild($form);
|
||||||
|
|
||||||
$preview_panel =
|
$preview_panel =
|
||||||
'<div class="aphront-panel-preview aphront-panel-preview-wide">
|
'<div class="aphront-panel-preview aphront-panel-preview-wide">
|
||||||
<div class="phriction-document-preview-header">
|
<div class="phriction-document-preview-header">
|
||||||
Document Preview
|
'.pht('Document Preview').'
|
||||||
</div>
|
</div>
|
||||||
<div id="document-preview">
|
<div id="document-preview">
|
||||||
<div class="aphront-panel-preview-loading-text">
|
<div class="aphront-panel-preview-loading-text">
|
||||||
Loading preview...
|
'.pht('Loading preview...').'
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>';
|
</div>';
|
||||||
|
@ -259,7 +259,7 @@ final class PhrictionEditController
|
||||||
$preview_panel,
|
$preview_panel,
|
||||||
),
|
),
|
||||||
array(
|
array(
|
||||||
'title' => 'Edit Document',
|
'title' => pht('Edit Document'),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,7 @@ final class PhrictionHistoryController
|
||||||
|
|
||||||
$diff_uri = new PhutilURI('/phriction/diff/'.$document->getID().'/');
|
$diff_uri = new PhutilURI('/phriction/diff/'.$document->getID().'/');
|
||||||
|
|
||||||
$vs_previous = '<em>Created</em>';
|
$vs_previous = '<em>'.pht('Created').'</em>';
|
||||||
if ($content->getVersion() != 1) {
|
if ($content->getVersion() != 1) {
|
||||||
$uri = $diff_uri
|
$uri = $diff_uri
|
||||||
->alter('l', $content->getVersion() - 1)
|
->alter('l', $content->getVersion() - 1)
|
||||||
|
@ -59,10 +59,10 @@ final class PhrictionHistoryController
|
||||||
array(
|
array(
|
||||||
'href' => $uri,
|
'href' => $uri,
|
||||||
),
|
),
|
||||||
'Show Change');
|
pht('Show Change'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$vs_head = '<em>Current</em>';
|
$vs_head = '<em>'.pht('Current').'</em>';
|
||||||
if ($content->getID() != $document->getContentID()) {
|
if ($content->getID() != $document->getContentID()) {
|
||||||
$uri = $diff_uri
|
$uri = $diff_uri
|
||||||
->alter('l', $content->getVersion())
|
->alter('l', $content->getVersion())
|
||||||
|
@ -73,7 +73,7 @@ final class PhrictionHistoryController
|
||||||
array(
|
array(
|
||||||
'href' => $uri,
|
'href' => $uri,
|
||||||
),
|
),
|
||||||
'Show Later Changes');
|
pht('Show Later Changes'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$change_type = PhrictionChangeType::getChangeTypeLabel(
|
$change_type = PhrictionChangeType::getChangeTypeLabel(
|
||||||
|
@ -87,7 +87,7 @@ final class PhrictionHistoryController
|
||||||
array(
|
array(
|
||||||
'href' => $slug_uri.'?v='.$version,
|
'href' => $slug_uri.'?v='.$version,
|
||||||
),
|
),
|
||||||
'Version '.$version),
|
pht('Version %s', $version)),
|
||||||
$handles[$content->getAuthorPHID()]->renderLink(),
|
$handles[$content->getAuthorPHID()]->renderLink(),
|
||||||
$change_type,
|
$change_type,
|
||||||
phutil_escape_html($content->getDescription()),
|
phutil_escape_html($content->getDescription()),
|
||||||
|
@ -99,14 +99,14 @@ final class PhrictionHistoryController
|
||||||
$table = new AphrontTableView($rows);
|
$table = new AphrontTableView($rows);
|
||||||
$table->setHeaders(
|
$table->setHeaders(
|
||||||
array(
|
array(
|
||||||
'Date',
|
pht('Date'),
|
||||||
'Time',
|
pht('Time'),
|
||||||
'Version',
|
pht('Version'),
|
||||||
'Author',
|
pht('Author'),
|
||||||
'Type',
|
pht('Type'),
|
||||||
'Description',
|
pht('Description'),
|
||||||
'Against Previous',
|
pht('Against Previous'),
|
||||||
'Against Current',
|
pht('Against Current'),
|
||||||
));
|
));
|
||||||
$table->setColumnClasses(
|
$table->setColumnClasses(
|
||||||
array(
|
array(
|
||||||
|
@ -132,7 +132,8 @@ final class PhrictionHistoryController
|
||||||
PhrictionDocument::getSlugURI($document->getSlug(), 'history')));
|
PhrictionDocument::getSlugURI($document->getSlug(), 'history')));
|
||||||
|
|
||||||
$panel = new AphrontPanelView();
|
$panel = new AphrontPanelView();
|
||||||
$panel->setHeader('Document History');
|
$panel->setHeader(pht('Document History'));
|
||||||
|
$panel->setNoBackground();
|
||||||
$panel->appendChild($table);
|
$panel->appendChild($table);
|
||||||
$panel->appendChild($pager);
|
$panel->appendChild($pager);
|
||||||
|
|
||||||
|
@ -142,7 +143,7 @@ final class PhrictionHistoryController
|
||||||
$panel,
|
$panel,
|
||||||
),
|
),
|
||||||
array(
|
array(
|
||||||
'title' => 'Document History',
|
'title' => pht('Document History'),
|
||||||
'device' => true,
|
'device' => true,
|
||||||
));
|
));
|
||||||
|
|
||||||
|
|
|
@ -67,10 +67,10 @@ final class PhrictionListController
|
||||||
$document_table = new AphrontTableView($rows);
|
$document_table = new AphrontTableView($rows);
|
||||||
$document_table->setHeaders(
|
$document_table->setHeaders(
|
||||||
array(
|
array(
|
||||||
'Last Editor',
|
pht('Last Editor'),
|
||||||
'Title',
|
pht('Title'),
|
||||||
'Last Update',
|
pht('Last Update'),
|
||||||
'Time',
|
pht('Time'),
|
||||||
));
|
));
|
||||||
|
|
||||||
$document_table->setColumnClasses(
|
$document_table->setColumnClasses(
|
||||||
|
@ -84,6 +84,7 @@ final class PhrictionListController
|
||||||
$view_header = $views[$this->view];
|
$view_header = $views[$this->view];
|
||||||
|
|
||||||
$panel = new AphrontPanelView();
|
$panel = new AphrontPanelView();
|
||||||
|
$panel->setNoBackground();
|
||||||
$panel->appendChild($document_table);
|
$panel->appendChild($document_table);
|
||||||
$panel->appendChild($pager);
|
$panel->appendChild($pager);
|
||||||
|
|
||||||
|
|
|
@ -78,7 +78,7 @@ final class PhrictionContent extends PhrictionDAO
|
||||||
$toc =
|
$toc =
|
||||||
'<div class="phabricator-remarkup-toc">'.
|
'<div class="phabricator-remarkup-toc">'.
|
||||||
'<div class="phabricator-remarkup-toc-header">'.
|
'<div class="phabricator-remarkup-toc-header">'.
|
||||||
'Table of Contents'.
|
pht('Table of Contents').
|
||||||
'</div>'.
|
'</div>'.
|
||||||
$toc.
|
$toc.
|
||||||
'</div>';
|
'</div>';
|
||||||
|
|
4
src/docs/book/user.book
Normal file
4
src/docs/book/user.book
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"name" : "phabricator",
|
||||||
|
"root" : "../../../"
|
||||||
|
}
|
|
@ -67,7 +67,7 @@ NOTE: This is cumbersome. There will be better testing tools at some point.
|
||||||
|
|
||||||
You can run `aphlict` in the foreground to get output to your console:
|
You can run `aphlict` in the foreground to get output to your console:
|
||||||
|
|
||||||
phabricator/ $ ./bin/aphlict --foreground
|
phabricator/ $ sudo ./bin/aphlict --foreground
|
||||||
|
|
||||||
You can run `support/aphlict/client/aphlict_test_client.php` to connect to the
|
You can run `support/aphlict/client/aphlict_test_client.php` to connect to the
|
||||||
Aphlict server from the command line. Messages the client receives will be
|
Aphlict server from the command line. Messages the client receives will be
|
||||||
|
|
|
@ -9,16 +9,16 @@ extends PhabricatorBaseProtocolAdapter {
|
||||||
private $readHandles;
|
private $readHandles;
|
||||||
private $multiHandle;
|
private $multiHandle;
|
||||||
private $active;
|
private $active;
|
||||||
private $rooms;
|
private $inRooms = array();
|
||||||
|
|
||||||
public function connect() {
|
public function connect() {
|
||||||
$this->server = idx($this->config, 'server');
|
$this->server = idx($this->config, 'server');
|
||||||
$this->authtoken = idx($this->config, 'authtoken');
|
$this->authtoken = idx($this->config, 'authtoken');
|
||||||
$ssl = idx($this->config, 'ssl', false);
|
$ssl = idx($this->config, 'ssl', false);
|
||||||
$this->rooms = idx($this->config, 'join');
|
$rooms = idx($this->config, 'join');
|
||||||
|
|
||||||
// First, join the room
|
// First, join the room
|
||||||
if (!$this->rooms) {
|
if (!$rooms) {
|
||||||
throw new Exception("Not configured to join any rooms!");
|
throw new Exception("Not configured to join any rooms!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ extends PhabricatorBaseProtocolAdapter {
|
||||||
$this->multiHandle = curl_multi_init();
|
$this->multiHandle = curl_multi_init();
|
||||||
$this->readHandles = array();
|
$this->readHandles = array();
|
||||||
|
|
||||||
foreach ($this->rooms as $room_id) {
|
foreach ($rooms as $room_id) {
|
||||||
$this->joinRoom($room_id);
|
$this->joinRoom($room_id);
|
||||||
|
|
||||||
// Set up the curl stream for reading
|
// Set up the curl stream for reading
|
||||||
|
@ -138,10 +138,12 @@ extends PhabricatorBaseProtocolAdapter {
|
||||||
|
|
||||||
private function joinRoom($room_id) {
|
private function joinRoom($room_id) {
|
||||||
$this->performPost("/room/{$room_id}/join.json");
|
$this->performPost("/room/{$room_id}/join.json");
|
||||||
|
$this->inRooms[$room_id] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function leaveRoom($room_id) {
|
private function leaveRoom($room_id) {
|
||||||
$this->performPost("/room/{$room_id}/leave.json");
|
$this->performPost("/room/{$room_id}/leave.json");
|
||||||
|
unset($this->inRooms[$room_id]);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function speak($message, $room_id) {
|
private function speak($message, $room_id) {
|
||||||
|
@ -154,48 +156,42 @@ extends PhabricatorBaseProtocolAdapter {
|
||||||
}
|
}
|
||||||
|
|
||||||
private function performPost($endpoint, $data = Null) {
|
private function performPost($endpoint, $data = Null) {
|
||||||
$url = $this->server.$endpoint;
|
$uri = new PhutilURI($this->server);
|
||||||
|
$uri->setPath($endpoint);
|
||||||
|
|
||||||
$payload = json_encode($data);
|
$payload = json_encode($data);
|
||||||
|
|
||||||
// cURL init & config
|
list($output) = id(new HTTPSFuture($uri))
|
||||||
$ch = curl_init();
|
->setMethod('POST')
|
||||||
curl_setopt($ch, CURLOPT_URL, $url);
|
->addHeader('Content-Type', 'application/json')
|
||||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
->addHeader('Authorization', $this->getAuthorizationHeader())
|
||||||
curl_setopt($ch, CURLOPT_POST, 1);
|
->setData($payload)
|
||||||
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
|
->resolvex();
|
||||||
curl_setopt($ch, CURLOPT_USERPWD, $this->authtoken . ':x');
|
|
||||||
curl_setopt(
|
|
||||||
$ch,
|
|
||||||
CURLOPT_HTTPHEADER,
|
|
||||||
array("Content-type: application/json"));
|
|
||||||
|
|
||||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
|
|
||||||
$output = curl_exec($ch);
|
|
||||||
|
|
||||||
curl_close($ch);
|
|
||||||
|
|
||||||
$output = trim($output);
|
$output = trim($output);
|
||||||
|
|
||||||
if (strlen($output)) {
|
if (strlen($output)) {
|
||||||
return json_decode($output);
|
return json_decode($output, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __destruct() {
|
public function __destruct() {
|
||||||
if ($this->rooms) {
|
foreach ($this->inRooms as $room_id => $ignored) {
|
||||||
foreach ($this->rooms as $room_id) {
|
$this->leaveRoom($room_id);
|
||||||
$this->leaveRoom($room_id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->readHandles) {
|
if ($this->readHandles) {
|
||||||
foreach ($this->readHandles as $read_handle) {
|
foreach ($this->readHandles as $read_handle) {
|
||||||
curl_multi_remove_handle($this->multiHandle, $read_handle);
|
curl_multi_remove_handle($this->multiHandle, $read_handle);
|
||||||
curl_close($read_handle);
|
curl_close($read_handle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
curl_multi_close($this->multiHandle);
|
curl_multi_close($this->multiHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function getAuthorizationHeader() {
|
||||||
|
return 'Basic '.base64_encode($this->authtoken.':x');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@ final class AphrontFormSubmitControl extends AphrontFormControl {
|
||||||
$submit_button = phutil_tag(
|
$submit_button = phutil_tag(
|
||||||
'button',
|
'button',
|
||||||
array(
|
array(
|
||||||
|
'type' => 'submit',
|
||||||
'name' => '__submit__',
|
'name' => '__submit__',
|
||||||
'disabled' => $this->getDisabled() ? 'disabled' : null,
|
'disabled' => $this->getDisabled() ? 'disabled' : null,
|
||||||
),
|
),
|
||||||
|
|
|
@ -7,6 +7,9 @@ body {
|
||||||
scrollbar to a page with a scrollbar doesn't make content jump a few
|
scrollbar to a page with a scrollbar doesn't make content jump a few
|
||||||
pixels left when the viewport narrows. */
|
pixels left when the viewport narrows. */
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
|
/* reset behavior in ie7, as it will add an extra scrollbar regardless
|
||||||
|
selector * targets ie6 and ie7 only */
|
||||||
|
*overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.device-phone {
|
.device-phone {
|
||||||
|
|
|
@ -35,6 +35,7 @@ JX.behavior('pholio-mock-view', function(config) {
|
||||||
main.src = data.fullSizeURI;
|
main.src = data.fullSizeURI;
|
||||||
|
|
||||||
JX.DOM.setContent(wrapper,main);
|
JX.DOM.setContent(wrapper,main);
|
||||||
|
load_inline_comments();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
@ -123,7 +124,7 @@ JX.behavior('pholio-mock-view', function(config) {
|
||||||
|
|
||||||
selection_fill.title = comment;
|
selection_fill.title = comment;
|
||||||
|
|
||||||
var saveURL = "/pholio/inline/" + imageData['imageID'] + "/";
|
var saveURL = "/pholio/inline/save/";
|
||||||
|
|
||||||
var inlineComment = new JX.Request(saveURL, function(r) {
|
var inlineComment = new JX.Request(saveURL, function(r) {
|
||||||
|
|
||||||
|
@ -144,6 +145,36 @@ JX.behavior('pholio-mock-view', function(config) {
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function load_inline_comments() {
|
||||||
|
var data = JX.Stratcom.getData(JX.$(config.mainID));
|
||||||
|
|
||||||
|
var inline_comments_url = "/pholio/inline/" + data['imageID'] + "/";
|
||||||
|
var inline_comments = new JX.Request(inline_comments_url, function(r) {
|
||||||
|
|
||||||
|
if (r.length > 0) {
|
||||||
|
for(i=0; i < r.length; i++) {
|
||||||
|
var inlineSelection = JX.$N(
|
||||||
|
'div',
|
||||||
|
{
|
||||||
|
id: r[i].phid,
|
||||||
|
className: 'pholio-mock-select-border',
|
||||||
|
title: r[i].content
|
||||||
|
});
|
||||||
|
|
||||||
|
JX.DOM.appendContent(wrapper, inlineSelection);
|
||||||
|
|
||||||
|
JX.$V(r[i].x, r[i].y).setPos(inlineSelection);
|
||||||
|
JX.$V(r[i].width, r[i].height)
|
||||||
|
.setDim(inlineSelection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
inline_comments.send();
|
||||||
|
}
|
||||||
|
|
||||||
|
load_inline_comments();
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue