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,
|
||||
),
|
||||
|
||||
// Configuration option for enabling imagemagick
|
||||
// to resize animated profile pictures (gif)
|
||||
'files.enable-imagemagick' => false,
|
||||
|
||||
// -- Storage --------------------------------------------------------------- //
|
||||
|
||||
// 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' =>
|
||||
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',
|
||||
'requires' =>
|
||||
array(
|
||||
|
@ -2591,7 +2591,7 @@ celerity_register_resource_map(array(
|
|||
),
|
||||
'phabricator-core-css' =>
|
||||
array(
|
||||
'uri' => '/res/03c97d00/rsrc/css/core/core.css',
|
||||
'uri' => '/res/2a055ecb/rsrc/css/core/core.css',
|
||||
'type' => 'css',
|
||||
'requires' =>
|
||||
array(
|
||||
|
@ -3400,7 +3400,7 @@ celerity_register_resource_map(array(
|
|||
), array(
|
||||
'packages' =>
|
||||
array(
|
||||
'4b569463' =>
|
||||
'acc46105' =>
|
||||
array(
|
||||
'name' => 'core.pkg.css',
|
||||
'symbols' =>
|
||||
|
@ -3443,7 +3443,7 @@ celerity_register_resource_map(array(
|
|||
35 => 'phabricator-object-item-list-view-css',
|
||||
36 => 'global-drag-and-drop-css',
|
||||
),
|
||||
'uri' => '/res/pkg/4b569463/core.pkg.css',
|
||||
'uri' => '/res/pkg/acc46105/core.pkg.css',
|
||||
'type' => 'css',
|
||||
),
|
||||
'bc0774e5' =>
|
||||
|
@ -3631,17 +3631,17 @@ celerity_register_resource_map(array(
|
|||
'reverse' =>
|
||||
array(
|
||||
'aphront-attached-file-view-css' => 'e30a3fa8',
|
||||
'aphront-crumbs-view-css' => '4b569463',
|
||||
'aphront-dialog-view-css' => '4b569463',
|
||||
'aphront-error-view-css' => '4b569463',
|
||||
'aphront-form-view-css' => '4b569463',
|
||||
'aphront-list-filter-view-css' => '4b569463',
|
||||
'aphront-pager-view-css' => '4b569463',
|
||||
'aphront-panel-view-css' => '4b569463',
|
||||
'aphront-table-view-css' => '4b569463',
|
||||
'aphront-tokenizer-control-css' => '4b569463',
|
||||
'aphront-tooltip-css' => '4b569463',
|
||||
'aphront-typeahead-control-css' => '4b569463',
|
||||
'aphront-crumbs-view-css' => 'acc46105',
|
||||
'aphront-dialog-view-css' => 'acc46105',
|
||||
'aphront-error-view-css' => 'acc46105',
|
||||
'aphront-form-view-css' => 'acc46105',
|
||||
'aphront-list-filter-view-css' => 'acc46105',
|
||||
'aphront-pager-view-css' => 'acc46105',
|
||||
'aphront-panel-view-css' => 'acc46105',
|
||||
'aphront-table-view-css' => 'acc46105',
|
||||
'aphront-tokenizer-control-css' => 'acc46105',
|
||||
'aphront-tooltip-css' => 'acc46105',
|
||||
'aphront-typeahead-control-css' => 'acc46105',
|
||||
'differential-changeset-view-css' => '8aaacd1b',
|
||||
'differential-core-view-css' => '8aaacd1b',
|
||||
'differential-inline-comment-editor' => '95d0d865',
|
||||
|
@ -3655,7 +3655,7 @@ celerity_register_resource_map(array(
|
|||
'differential-table-of-contents-css' => '8aaacd1b',
|
||||
'diffusion-commit-view-css' => 'c8ce2d88',
|
||||
'diffusion-icons-css' => 'c8ce2d88',
|
||||
'global-drag-and-drop-css' => '4b569463',
|
||||
'global-drag-and-drop-css' => 'acc46105',
|
||||
'inline-comment-summary-css' => '8aaacd1b',
|
||||
'javelin-aphlict' => 'bc0774e5',
|
||||
'javelin-behavior' => 'd466c034',
|
||||
|
@ -3724,48 +3724,48 @@ celerity_register_resource_map(array(
|
|||
'javelin-util' => 'd466c034',
|
||||
'javelin-vector' => 'd466c034',
|
||||
'javelin-workflow' => 'd466c034',
|
||||
'lightbox-attachment-css' => '4b569463',
|
||||
'lightbox-attachment-css' => 'acc46105',
|
||||
'maniphest-task-summary-css' => 'e30a3fa8',
|
||||
'maniphest-transaction-detail-css' => 'e30a3fa8',
|
||||
'phabricator-busy' => 'bc0774e5',
|
||||
'phabricator-content-source-view-css' => '8aaacd1b',
|
||||
'phabricator-core-buttons-css' => '4b569463',
|
||||
'phabricator-core-css' => '4b569463',
|
||||
'phabricator-crumbs-view-css' => '4b569463',
|
||||
'phabricator-directory-css' => '4b569463',
|
||||
'phabricator-core-buttons-css' => 'acc46105',
|
||||
'phabricator-core-css' => 'acc46105',
|
||||
'phabricator-crumbs-view-css' => 'acc46105',
|
||||
'phabricator-directory-css' => 'acc46105',
|
||||
'phabricator-drag-and-drop-file-upload' => '95d0d865',
|
||||
'phabricator-dropdown-menu' => 'bc0774e5',
|
||||
'phabricator-file-upload' => 'bc0774e5',
|
||||
'phabricator-filetree-view-css' => '4b569463',
|
||||
'phabricator-flag-css' => '4b569463',
|
||||
'phabricator-form-view-css' => '4b569463',
|
||||
'phabricator-header-view-css' => '4b569463',
|
||||
'phabricator-jump-nav' => '4b569463',
|
||||
'phabricator-filetree-view-css' => 'acc46105',
|
||||
'phabricator-flag-css' => 'acc46105',
|
||||
'phabricator-form-view-css' => 'acc46105',
|
||||
'phabricator-header-view-css' => 'acc46105',
|
||||
'phabricator-jump-nav' => 'acc46105',
|
||||
'phabricator-keyboard-shortcut' => 'bc0774e5',
|
||||
'phabricator-keyboard-shortcut-manager' => 'bc0774e5',
|
||||
'phabricator-main-menu-view' => '4b569463',
|
||||
'phabricator-main-menu-view' => 'acc46105',
|
||||
'phabricator-menu-item' => 'bc0774e5',
|
||||
'phabricator-nav-view-css' => '4b569463',
|
||||
'phabricator-nav-view-css' => 'acc46105',
|
||||
'phabricator-notification' => 'bc0774e5',
|
||||
'phabricator-notification-css' => '4b569463',
|
||||
'phabricator-notification-menu-css' => '4b569463',
|
||||
'phabricator-object-item-list-view-css' => '4b569463',
|
||||
'phabricator-notification-css' => 'acc46105',
|
||||
'phabricator-notification-menu-css' => 'acc46105',
|
||||
'phabricator-object-item-list-view-css' => 'acc46105',
|
||||
'phabricator-object-selector-css' => '8aaacd1b',
|
||||
'phabricator-paste-file-upload' => 'bc0774e5',
|
||||
'phabricator-prefab' => 'bc0774e5',
|
||||
'phabricator-project-tag-css' => 'e30a3fa8',
|
||||
'phabricator-remarkup-css' => '4b569463',
|
||||
'phabricator-remarkup-css' => 'acc46105',
|
||||
'phabricator-shaped-request' => '95d0d865',
|
||||
'phabricator-side-menu-view-css' => '4b569463',
|
||||
'phabricator-standard-page-view' => '4b569463',
|
||||
'phabricator-side-menu-view-css' => 'acc46105',
|
||||
'phabricator-standard-page-view' => 'acc46105',
|
||||
'phabricator-textareautils' => 'bc0774e5',
|
||||
'phabricator-tooltip' => 'bc0774e5',
|
||||
'phabricator-transaction-view-css' => '4b569463',
|
||||
'phabricator-zindex-css' => '4b569463',
|
||||
'sprite-apps-large-css' => '4b569463',
|
||||
'sprite-gradient-css' => '4b569463',
|
||||
'sprite-icon-css' => '4b569463',
|
||||
'sprite-menu-css' => '4b569463',
|
||||
'syntax-highlighting-css' => '4b569463',
|
||||
'phabricator-transaction-view-css' => 'acc46105',
|
||||
'phabricator-zindex-css' => 'acc46105',
|
||||
'sprite-apps-large-css' => 'acc46105',
|
||||
'sprite-gradient-css' => 'acc46105',
|
||||
'sprite-icon-css' => 'acc46105',
|
||||
'sprite-menu-css' => 'acc46105',
|
||||
'syntax-highlighting-css' => 'acc46105',
|
||||
),
|
||||
));
|
||||
|
|
|
@ -1259,6 +1259,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorSetupCheckExtraConfig' => 'applications/config/check/PhabricatorSetupCheckExtraConfig.php',
|
||||
'PhabricatorSetupCheckFacebook' => 'applications/config/check/PhabricatorSetupCheckFacebook.php',
|
||||
'PhabricatorSetupCheckGD' => 'applications/config/check/PhabricatorSetupCheckGD.php',
|
||||
'PhabricatorSetupCheckImagemagick' => 'applications/config/check/PhabricatorSetupCheckImagemagick.php',
|
||||
'PhabricatorSetupCheckInvalidConfig' => 'applications/config/check/PhabricatorSetupCheckInvalidConfig.php',
|
||||
'PhabricatorSetupCheckMail' => 'applications/config/check/PhabricatorSetupCheckMail.php',
|
||||
'PhabricatorSetupCheckMySQL' => 'applications/config/check/PhabricatorSetupCheckMySQL.php',
|
||||
|
@ -1409,6 +1410,7 @@ phutil_register_library_map(array(
|
|||
'PholioController' => 'applications/pholio/controller/PholioController.php',
|
||||
'PholioDAO' => 'applications/pholio/storage/PholioDAO.php',
|
||||
'PholioImage' => 'applications/pholio/storage/PholioImage.php',
|
||||
'PholioInlineController' => 'applications/pholio/controller/PholioInlineController.php',
|
||||
'PholioInlineSaveController' => 'applications/pholio/controller/PholioInlineSaveController.php',
|
||||
'PholioMock' => 'applications/pholio/storage/PholioMock.php',
|
||||
'PholioMockCommentController' => 'applications/pholio/controller/PholioMockCommentController.php',
|
||||
|
@ -2673,6 +2675,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorSetupCheckExtraConfig' => 'PhabricatorSetupCheck',
|
||||
'PhabricatorSetupCheckFacebook' => 'PhabricatorSetupCheck',
|
||||
'PhabricatorSetupCheckGD' => 'PhabricatorSetupCheck',
|
||||
'PhabricatorSetupCheckImagemagick' => 'PhabricatorSetupCheck',
|
||||
'PhabricatorSetupCheckInvalidConfig' => 'PhabricatorSetupCheck',
|
||||
'PhabricatorSetupCheckMail' => 'PhabricatorSetupCheck',
|
||||
'PhabricatorSetupCheckMySQL' => 'PhabricatorSetupCheck',
|
||||
|
@ -2827,6 +2830,7 @@ phutil_register_library_map(array(
|
|||
0 => 'PholioDAO',
|
||||
1 => 'PhabricatorMarkupInterface',
|
||||
),
|
||||
'PholioInlineController' => 'PholioController',
|
||||
'PholioInlineSaveController' => 'PholioController',
|
||||
'PholioMock' =>
|
||||
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');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -64,6 +64,7 @@ final class ConpherenceUpdateController extends
|
|||
$top = $request->getInt('image_y');
|
||||
$left = $request->getInt('image_x');
|
||||
$file_id = $request->getInt('file_id');
|
||||
$title = $request->getStr('title');
|
||||
if ($file_id) {
|
||||
$orig_file = id(new PhabricatorFileQuery())
|
||||
->setViewer($user)
|
||||
|
@ -101,6 +102,8 @@ final class ConpherenceUpdateController extends
|
|||
pht('This server only supports these image formats: %s.',
|
||||
implode(', ', $supported_formats));
|
||||
}
|
||||
// use the existing title in this image upload case
|
||||
$title = $conpherence->getTitle();
|
||||
} else if ($top !== null || $left !== null) {
|
||||
$file = $conpherence->getImage(ConpherenceImageData::SIZE_ORIG);
|
||||
$xformer = new PhabricatorImageTransformer();
|
||||
|
@ -119,7 +122,6 @@ final class ConpherenceUpdateController extends
|
|||
)
|
||||
->setNewValue($image_phid);
|
||||
}
|
||||
$title = $request->getStr('title');
|
||||
if ($title != $conpherence->getTitle()) {
|
||||
$xactions[] = id(new ConpherenceTransaction())
|
||||
->setTransactionType(ConpherenceTransactionType::TYPE_TITLE)
|
||||
|
|
|
@ -5,6 +5,16 @@
|
|||
*/
|
||||
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) {
|
||||
if (!($mail_receiver instanceof ConpherenceThread)) {
|
||||
throw new Exception("Mail receiver is not a ConpherenceThread!");
|
||||
|
@ -67,14 +77,25 @@ final class ConpherenceReplyHandler extends PhabricatorMailReplyHandler {
|
|||
$file_phids,
|
||||
'{F%d}'
|
||||
);
|
||||
$xactions = $editor->generateTransactionsFromText(
|
||||
|
||||
$xactions = array();
|
||||
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);
|
||||
|
||||
return null;
|
||||
return $conpherence;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -46,12 +46,17 @@ final class ConpherenceTransaction extends PhabricatorApplicationTransaction {
|
|||
|
||||
switch ($this->getTransactionType()) {
|
||||
case ConpherenceTransactionType::TYPE_TITLE:
|
||||
if ($old) {
|
||||
if ($old && $new) {
|
||||
$title = pht(
|
||||
'%s renamed this conpherence from "%s" to "%s".',
|
||||
$this->renderHandleLink($author_phid),
|
||||
phutil_escape_html($old),
|
||||
phutil_escape_html($new));
|
||||
} else if ($old) {
|
||||
$title = pht(
|
||||
'%s deleted the conpherence name "%s".',
|
||||
$this->renderHandleLink($author_phid),
|
||||
phutil_escape_html($old));
|
||||
} else {
|
||||
$title = pht(
|
||||
'%s named this conpherence "%s".',
|
||||
|
|
|
@ -172,7 +172,7 @@ class DifferentialReplyHandler extends PhabricatorMailReplyHandler {
|
|||
DifferentialRevisionEditor::removeCCAndUpdateRevision(
|
||||
$revision,
|
||||
$user->getPHID(),
|
||||
$user->getPHID());
|
||||
$user);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -59,13 +59,13 @@ final class DifferentialSubscribeController extends DifferentialController {
|
|||
DifferentialRevisionEditor::addCCAndUpdateRevision(
|
||||
$revision,
|
||||
$phid,
|
||||
$phid);
|
||||
$user);
|
||||
break;
|
||||
case 'rem':
|
||||
DifferentialRevisionEditor::removeCCAndUpdateRevision(
|
||||
$revision,
|
||||
$phid,
|
||||
$phid);
|
||||
$user);
|
||||
break;
|
||||
default:
|
||||
return new Aphront400Response();
|
||||
|
|
|
@ -496,12 +496,13 @@ final class DifferentialRevisionEditor extends PhabricatorEditor {
|
|||
public static function addCCAndUpdateRevision(
|
||||
$revision,
|
||||
$phid,
|
||||
$reason) {
|
||||
PhabricatorUser $actor) {
|
||||
|
||||
self::addCC($revision, $phid, $reason);
|
||||
self::addCC($revision, $phid, $actor->getPHID());
|
||||
|
||||
$type = PhabricatorEdgeConfig::TYPE_OBJECT_HAS_UNSUBSCRIBER;
|
||||
id(new PhabricatorEdgeEditor())
|
||||
->setActor($actor)
|
||||
->removeEdge($revision->getPHID(), $type, $phid)
|
||||
->save();
|
||||
}
|
||||
|
@ -509,12 +510,13 @@ final class DifferentialRevisionEditor extends PhabricatorEditor {
|
|||
public static function removeCCAndUpdateRevision(
|
||||
$revision,
|
||||
$phid,
|
||||
$reason) {
|
||||
PhabricatorUser $actor) {
|
||||
|
||||
self::removeCC($revision, $phid, $reason);
|
||||
self::removeCC($revision, $phid, $actor->getPHID());
|
||||
|
||||
$type = PhabricatorEdgeConfig::TYPE_OBJECT_HAS_UNSUBSCRIBER;
|
||||
id(new PhabricatorEdgeEditor())
|
||||
->setActor($actor)
|
||||
->addEdge($revision->getPHID(), $type, $phid)
|
||||
->save();
|
||||
}
|
||||
|
|
|
@ -253,10 +253,15 @@ final class DifferentialChangesetListView extends AphrontView {
|
|||
|
||||
$repository = $this->repository;
|
||||
if ($repository) {
|
||||
$meta['diffusionURI'] = (string)$repository->getDiffusionBrowseURIForPath(
|
||||
try {
|
||||
$meta['diffusionURI'] =
|
||||
(string)$repository->getDiffusionBrowseURIForPath(
|
||||
$changeset->getAbsoluteRepositoryPath($repository, $this->diff),
|
||||
idx($changeset->getMetadata(), 'line:first'),
|
||||
$this->getBranch());
|
||||
} catch (DiffusionSetupException $e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
|
||||
$change = $changeset->getChangeType();
|
||||
|
|
|
@ -2,6 +2,9 @@
|
|||
|
||||
final class DivinerGenerateWorkflow extends DivinerWorkflow {
|
||||
|
||||
private $config;
|
||||
private $atomCache;
|
||||
|
||||
public function didConstruct() {
|
||||
$this
|
||||
->setName('generate')
|
||||
|
@ -12,10 +15,37 @@ final class DivinerGenerateWorkflow extends DivinerWorkflow {
|
|||
'name' => 'clean',
|
||||
'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) {
|
||||
$this->readBookConfiguration($args);
|
||||
|
||||
if ($args->getArg('clean')) {
|
||||
$this->log(pht('CLEARING CACHES'));
|
||||
$this->getAtomCache()->delete();
|
||||
|
@ -170,7 +200,7 @@ final class DivinerGenerateWorkflow extends DivinerWorkflow {
|
|||
|
||||
|
||||
private function findFilesInProject() {
|
||||
$file_hashes = id(new FileFinder($this->getRoot()))
|
||||
$file_hashes = id(new FileFinder($this->getConfig('root')))
|
||||
->excludePath('*/.*')
|
||||
->withType('f')
|
||||
->setGenerateChecksums(true)
|
||||
|
@ -222,11 +252,11 @@ final class DivinerGenerateWorkflow extends DivinerWorkflow {
|
|||
foreach ($atomizers as $class => $files) {
|
||||
foreach (array_chunk($files, 32) as $chunk) {
|
||||
$future = new ExecFuture(
|
||||
'%s atomize --atomizer %s -- %Ls',
|
||||
'%s atomize --ugly --atomizer %s -- %Ls',
|
||||
dirname(phutil_get_library_root('phabricator')).'/bin/diviner',
|
||||
$class,
|
||||
$chunk);
|
||||
$future->setCWD($this->getRoot());
|
||||
$future->setCWD($this->getConfig('root'));
|
||||
|
||||
$futures[] = $future;
|
||||
}
|
||||
|
@ -381,4 +411,42 @@ final class DivinerGenerateWorkflow extends DivinerWorkflow {
|
|||
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 {
|
||||
|
||||
private $atomCache;
|
||||
|
||||
public function isExecutable() {
|
||||
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;
|
||||
}
|
||||
|
||||
$cropped = $this->applyScaleWithImagemagick($file, $x, $scaled_y);
|
||||
|
||||
if ($cropped != null) {
|
||||
return $cropped;
|
||||
}
|
||||
|
||||
$img = $this->applyScaleTo(
|
||||
$img,
|
||||
$file,
|
||||
$x,
|
||||
$scaled_y);
|
||||
|
||||
|
@ -131,11 +137,13 @@ final class PhabricatorImageTransformer {
|
|||
* Very crudely scale an image up or down to an exact size.
|
||||
*/
|
||||
private function crudelyScaleTo(PhabricatorFile $file, $dx, $dy) {
|
||||
$data = $file->loadFileData();
|
||||
$src = imagecreatefromstring($data);
|
||||
$scaled = $this->applyScaleWithImagemagick($file, $dx, $dy);
|
||||
|
||||
$dst = $this->applyScaleTo($src, $dx, $dy);
|
||||
if ($scaled != null) {
|
||||
return $scaled;
|
||||
}
|
||||
|
||||
$dst = $this->applyScaleTo($file, $dx, $dy);
|
||||
return $this->saveImageDataInAnyFormat($dst, $file->getMimeType());
|
||||
}
|
||||
|
||||
|
@ -147,17 +155,22 @@ final class PhabricatorImageTransformer {
|
|||
return $dst;
|
||||
}
|
||||
|
||||
private function applyScaleTo($src, $dx, $dy) {
|
||||
private function applyScaleTo(PhabricatorFile $file, $dx, $dy) {
|
||||
$data = $file->loadFileData();
|
||||
$src = imagecreatefromstring($data);
|
||||
|
||||
$x = imagesx($src);
|
||||
$y = imagesy($src);
|
||||
|
||||
$scale = min(($dx / $x), ($dy / $y), 1);
|
||||
|
||||
$dst = $this->getBlankDestinationFile($dx, $dy);
|
||||
|
||||
$sdx = $scale * $x;
|
||||
$sdy = $scale * $y;
|
||||
|
||||
$dst = $this->getBlankDestinationFile($dx, $dy);
|
||||
imagesavealpha($dst, true);
|
||||
imagefill($dst, 0, 0, imagecolorallocatealpha($dst, 255, 255, 255, 127));
|
||||
|
||||
imagecopyresampled(
|
||||
$dst,
|
||||
$src,
|
||||
|
@ -167,6 +180,7 @@ final class PhabricatorImageTransformer {
|
|||
$x, $y);
|
||||
|
||||
return $dst;
|
||||
|
||||
}
|
||||
|
||||
public static function getPreviewDimensions(PhabricatorFile $file, $size) {
|
||||
|
@ -337,7 +351,7 @@ final class PhabricatorImageTransformer {
|
|||
|
||||
private function saveImageDataInAnyFormat($data, $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':
|
||||
if (function_exists('imagepng')) {
|
||||
ob_start();
|
||||
|
@ -368,4 +382,43 @@ final class PhabricatorImageTransformer {
|
|||
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 ".
|
||||
"limit."))
|
||||
->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',
|
||||
array(
|
||||
'class' => implode(' ', $classes),
|
||||
));
|
||||
),
|
||||
'');
|
||||
|
||||
$create_button = phutil_tag(
|
||||
'a',
|
||||
|
|
|
@ -78,7 +78,10 @@ final class PhabricatorMetaMTAReceivedMail extends PhabricatorMetaMTADAO {
|
|||
/**
|
||||
* Parses "to" addresses, looking for a public create email address
|
||||
* 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() {
|
||||
// Only one "public" create address so far
|
||||
|
@ -99,6 +102,8 @@ final class PhabricatorMetaMTAReceivedMail extends PhabricatorMetaMTADAO {
|
|||
$receiver_name = null;
|
||||
$user_id = null;
|
||||
$hash = null;
|
||||
$user_phids = array();
|
||||
$user_names = array();
|
||||
foreach ($this->getToAddresses() as $address) {
|
||||
if ($address == $create_task) {
|
||||
$phabricator_address = $address;
|
||||
|
@ -121,13 +126,31 @@ final class PhabricatorMetaMTAReceivedMail extends PhabricatorMetaMTADAO {
|
|||
$hash = $matches[3];
|
||||
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(
|
||||
$phabricator_address,
|
||||
$receiver_name,
|
||||
$user_id,
|
||||
$hash
|
||||
$hash,
|
||||
$user_phids
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -170,8 +193,9 @@ final class PhabricatorMetaMTAReceivedMail extends PhabricatorMetaMTADAO {
|
|||
list($to,
|
||||
$receiver_name,
|
||||
$user_id,
|
||||
$hash) = $this->getPhabricatorToInformation();
|
||||
if (!$to) {
|
||||
$hash,
|
||||
$user_phids) = $this->getPhabricatorToInformation();
|
||||
if (!$to && !$user_phids) {
|
||||
$raw_to = idx($this->headers, 'to');
|
||||
return $this->setMessage("Unrecognized 'to' format: {$raw_to}")->save();
|
||||
}
|
||||
|
@ -186,7 +210,7 @@ final class PhabricatorMetaMTAReceivedMail extends PhabricatorMetaMTADAO {
|
|||
if ($create_task && $to == $create_task) {
|
||||
$receiver = new ManiphestTask();
|
||||
|
||||
$user = $this->lookupPublicUser();
|
||||
$user = $this->lookupSender();
|
||||
if ($user) {
|
||||
$this->setAuthorPHID($user->getPHID());
|
||||
} else {
|
||||
|
@ -230,12 +254,32 @@ final class PhabricatorMetaMTAReceivedMail extends PhabricatorMetaMTADAO {
|
|||
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 (!PhabricatorEnv::getEnvConfig('metamta.public-replies')) {
|
||||
return $this->setMessage("Public replies not enabled.")->save();
|
||||
}
|
||||
|
||||
$user = $this->lookupPublicUser();
|
||||
$user = $this->lookupSender();
|
||||
|
||||
if (!$user) {
|
||||
return $this->setMessage("Invalid public user '{$from}'.")->save();
|
||||
|
@ -373,7 +417,7 @@ final class PhabricatorMetaMTAReceivedMail extends PhabricatorMetaMTADAO {
|
|||
return array_filter($raw_addresses);
|
||||
}
|
||||
|
||||
private function lookupPublicUser() {
|
||||
private function lookupSender() {
|
||||
$from = idx($this->headers, 'from');
|
||||
$from = $this->getRawEmailAddress($from);
|
||||
|
||||
|
|
|
@ -43,7 +43,8 @@ final class PhabricatorApplicationPholio extends PhabricatorApplication {
|
|||
'new/' => 'PholioMockEditController',
|
||||
'edit/(?P<id>\d+)/' => 'PholioMockEditController',
|
||||
'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 {
|
||||
|
||||
public function getShortDescription() {
|
||||
return 'Wiki';
|
||||
return pht('Wiki');
|
||||
}
|
||||
|
||||
public function getBaseURI() {
|
||||
|
|
|
@ -9,7 +9,7 @@ abstract class PhrictionController extends PhabricatorController {
|
|||
|
||||
$page = $this->buildStandardPageView();
|
||||
|
||||
$page->setApplicationName('Phriction');
|
||||
$page->setApplicationName(pht('Phriction'));
|
||||
$page->setBaseURI('/w/');
|
||||
$page->setTitle(idx($data, 'title'));
|
||||
$page->setGlyph("\xE2\x9A\xA1");
|
||||
|
@ -32,7 +32,7 @@ abstract class PhrictionController extends PhabricatorController {
|
|||
$nav->addFilter('', pht('Create Document'), '/phriction/new');
|
||||
}
|
||||
|
||||
$nav->addLabel('Filters');
|
||||
$nav->addLabel(pht('Filters'));
|
||||
$nav->addFilter('active', pht('Active Documents'));
|
||||
$nav->addFilter('all', pht('All Documents'));
|
||||
$nav->addFilter('updates', pht('Recently Updated'));
|
||||
|
|
|
@ -32,11 +32,11 @@ final class PhrictionDeleteController extends PhrictionController {
|
|||
|
||||
$dialog = id(new AphrontDialogView())
|
||||
->setUser($user)
|
||||
->setTitle('Delete document?')
|
||||
->setTitle(pht('Delete document?'))
|
||||
->appendChild(
|
||||
'Really delete this document? You can recover it later by reverting '.
|
||||
'to a previous version.')
|
||||
->addSubmitButton('Delete')
|
||||
pht('Really delete this document? You can recover it later by '.
|
||||
'reverting to a previous version.'))
|
||||
->addSubmitButton(pht('Delete'))
|
||||
->addCancelButton($document_uri);
|
||||
|
||||
return id(new AphrontDialogResponse())->setDialog($dialog);
|
||||
|
|
|
@ -138,9 +138,9 @@ final class PhrictionDiffController
|
|||
array(
|
||||
'href' => $uri->alter('l', $l - 1)->alter('r', $r - 1),
|
||||
),
|
||||
"\xC2\xAB Previous Change");
|
||||
pht("\xC2\xAB Previous Change"));
|
||||
} else {
|
||||
$link_l = 'Original Change';
|
||||
$link_l = pht('Original Change');
|
||||
}
|
||||
|
||||
$link_r = null;
|
||||
|
@ -150,9 +150,9 @@ final class PhrictionDiffController
|
|||
array(
|
||||
'href' => $uri->alter('l', $l + 1)->alter('r', $r + 1),
|
||||
),
|
||||
"Next Change \xC2\xBB");
|
||||
pht("Next Change \xC2\xBB"));
|
||||
} else {
|
||||
$link_r = 'Most Recent Change';
|
||||
$link_r = pht('Most Recent Change');
|
||||
}
|
||||
|
||||
$navigation_table =
|
||||
|
@ -184,7 +184,7 @@ final class PhrictionDiffController
|
|||
$output,
|
||||
),
|
||||
array(
|
||||
'title' => 'Document History',
|
||||
'title' => pht('Document History'),
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -208,7 +208,7 @@ final class PhrictionDiffController
|
|||
'href' => '/phriction/edit/'.$document_id.'/',
|
||||
'class' => 'button',
|
||||
),
|
||||
'Edit Current Version');
|
||||
pht('Edit Current Version'));
|
||||
}
|
||||
|
||||
|
||||
|
@ -218,7 +218,7 @@ final class PhrictionDiffController
|
|||
'href' => '/phriction/edit/'.$document_id.'/?revert='.$version,
|
||||
'class' => 'button',
|
||||
),
|
||||
'Revert to Version '.$version.'...');
|
||||
pht('Revert to Version %s...', $version));
|
||||
}
|
||||
|
||||
private function renderComparisonTable(array $content) {
|
||||
|
@ -244,11 +244,11 @@ final class PhrictionDiffController
|
|||
$table = new AphrontTableView($rows);
|
||||
$table->setHeaders(
|
||||
array(
|
||||
'Date',
|
||||
'Time',
|
||||
'Version',
|
||||
'Author',
|
||||
'Description',
|
||||
pht('Date'),
|
||||
pht('Time'),
|
||||
pht('Version'),
|
||||
pht('Author'),
|
||||
pht('Description'),
|
||||
));
|
||||
$table->setColumnClasses(
|
||||
array(
|
||||
|
|
|
@ -45,7 +45,6 @@ final class PhrictionDocumentController
|
|||
}
|
||||
}
|
||||
$create_uri = '/phriction/edit/?slug='.$slug;
|
||||
|
||||
$page_content = hsprintf(
|
||||
'<div class="phriction-content">'.
|
||||
'<em>No content here!</em><br />'.
|
||||
|
@ -54,7 +53,7 @@ final class PhrictionDocumentController
|
|||
'</div>',
|
||||
$slug,
|
||||
$create_uri);
|
||||
$page_title = 'Page Not Found';
|
||||
$page_title = pht('Page Not Found');
|
||||
} else {
|
||||
$version = $request->getInt('v');
|
||||
if ($version) {
|
||||
|
@ -67,13 +66,13 @@ final class PhrictionDocumentController
|
|||
}
|
||||
|
||||
if ($content->getID() != $document->getContentID()) {
|
||||
$vdate = phabricator_datetime($content->getDateCreated(), $user);
|
||||
$version_note = new AphrontErrorView();
|
||||
$version_note->setSeverity(AphrontErrorView::SEVERITY_NOTICE);
|
||||
$version_note->setTitle('Older Version');
|
||||
$version_note->appendChild(
|
||||
'You are viewing an older version of this document, as it '.
|
||||
'appeared on '.
|
||||
phabricator_datetime($content->getDateCreated(), $user).'.');
|
||||
pht('You are viewing an older version of this document, as it '.
|
||||
'appeared on %s.', $vdate));
|
||||
}
|
||||
} else {
|
||||
$content = id(new PhrictionContent())->load($document->getContentID());
|
||||
|
@ -139,8 +138,8 @@ final class PhrictionDocumentController
|
|||
$notice->setSeverity(AphrontErrorView::SEVERITY_NOTICE);
|
||||
$notice->setTitle('Document Deleted');
|
||||
$notice->appendChild(
|
||||
'This document has been deleted. You can edit it to put new content '.
|
||||
'here, or use history to revert to an earlier version.');
|
||||
pht('This document has been deleted. You can edit it to put new '.
|
||||
'content here, or use history to revert to an earlier version.'));
|
||||
$core_content = $notice->render();
|
||||
} else {
|
||||
throw new Exception("Unknown document status '{$doc_status}'!");
|
||||
|
@ -323,20 +322,22 @@ final class PhrictionDocumentController
|
|||
}
|
||||
}
|
||||
if ($more_children) {
|
||||
$list[] = '<li>More...</li>';
|
||||
$list[] = '<li>'.pht('More...').'</li>';
|
||||
}
|
||||
$list[] = '</ul>';
|
||||
$list = implode("\n", $list);
|
||||
|
||||
return
|
||||
'<div class="phriction-children">'.
|
||||
'<div class="phriction-children-header">Document Hierarchy</div>'.
|
||||
'<div class="phriction-children-header">'.
|
||||
pht('Document Hierarchy').
|
||||
'</div>'.
|
||||
$list.
|
||||
'</div>';
|
||||
}
|
||||
|
||||
private function renderChildDocumentLink(array $info) {
|
||||
$title = nonempty($info['title'], '(Untitled Document)');
|
||||
$title = nonempty($info['title'], pht('(Untitled Document)'));
|
||||
$item = phutil_tag(
|
||||
'a',
|
||||
array(
|
||||
|
|
|
@ -95,8 +95,8 @@ final class PhrictionEditController
|
|||
$notes = $request->getStr('description');
|
||||
|
||||
if (!strlen($title)) {
|
||||
$e_title = 'Required';
|
||||
$errors[] = 'Document title is required.';
|
||||
$e_title = pht('Required');
|
||||
$errors[] = pht('Document title is required.');
|
||||
} else {
|
||||
$e_title = null;
|
||||
}
|
||||
|
@ -107,9 +107,9 @@ final class PhrictionEditController
|
|||
|
||||
$dialog = new AphrontDialogView();
|
||||
$dialog->setUser($user);
|
||||
$dialog->setTitle('No Edits');
|
||||
$dialog->setTitle(pht('No Edits'));
|
||||
$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());
|
||||
|
||||
return id(new AphrontDialogResponse())->setDialog($dialog);
|
||||
|
@ -121,9 +121,9 @@ final class PhrictionEditController
|
|||
|
||||
$dialog = new AphrontDialogView();
|
||||
$dialog->setUser($user);
|
||||
$dialog->setTitle('Empty Page');
|
||||
$dialog->setTitle(pht('Empty Page'));
|
||||
$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());
|
||||
|
||||
return id(new AphrontDialogResponse())->setDialog($dialog);
|
||||
|
@ -150,16 +150,16 @@ final class PhrictionEditController
|
|||
$error_view = null;
|
||||
if ($errors) {
|
||||
$error_view = id(new AphrontErrorView())
|
||||
->setTitle('Form Errors')
|
||||
->setTitle(pht('Form Errors'))
|
||||
->setErrors($errors);
|
||||
}
|
||||
|
||||
if ($document->getID()) {
|
||||
$panel_header = 'Edit Phriction Document';
|
||||
$submit_button = 'Save Changes';
|
||||
$panel_header = pht('Edit Phriction Document');
|
||||
$submit_button = pht('Save Changes');
|
||||
} else {
|
||||
$panel_header = 'Create New Phriction Document';
|
||||
$submit_button = 'Create Document';
|
||||
$panel_header = pht('Create New Phriction Document');
|
||||
$submit_button = pht('Create Document');
|
||||
}
|
||||
|
||||
$uri = $document->getSlug();
|
||||
|
@ -178,7 +178,7 @@ final class PhrictionEditController
|
|||
array(
|
||||
'href' => $request->getRequestURI()->alter('nodraft', true),
|
||||
),
|
||||
'discard this draft');
|
||||
pht('discard this draft'));
|
||||
|
||||
$draft_note = new AphrontErrorView();
|
||||
$draft_note->setSeverity(AphrontErrorView::SEVERITY_NOTICE);
|
||||
|
@ -199,17 +199,17 @@ final class PhrictionEditController
|
|||
->addHiddenInput('nodraft', $request->getBool('nodraft'))
|
||||
->appendChild(
|
||||
id(new AphrontFormTextControl())
|
||||
->setLabel('Title')
|
||||
->setLabel(pht('Title'))
|
||||
->setValue($content->getTitle())
|
||||
->setError($e_title)
|
||||
->setName('title'))
|
||||
->appendChild(
|
||||
id(new AphrontFormStaticControl())
|
||||
->setLabel('URI')
|
||||
->setLabel(pht('URI'))
|
||||
->setValue($uri))
|
||||
->appendChild(
|
||||
id(new PhabricatorRemarkupControl())
|
||||
->setLabel('Content')
|
||||
->setLabel(pht('Content'))
|
||||
->setValue($content_text)
|
||||
->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_TALL)
|
||||
->setName('content')
|
||||
|
@ -217,7 +217,7 @@ final class PhrictionEditController
|
|||
->setUser($user))
|
||||
->appendChild(
|
||||
id(new AphrontFormTextControl())
|
||||
->setLabel('Edit Notes')
|
||||
->setLabel(pht('Edit Notes'))
|
||||
->setValue($notes)
|
||||
->setError(null)
|
||||
->setName('description'))
|
||||
|
@ -227,18 +227,18 @@ final class PhrictionEditController
|
|||
->setValue($submit_button));
|
||||
|
||||
$panel = id(new AphrontPanelView())
|
||||
->setWidth(AphrontPanelView::WIDTH_WIDE)
|
||||
->setNoBackground()
|
||||
->setHeader($panel_header)
|
||||
->appendChild($form);
|
||||
|
||||
$preview_panel =
|
||||
'<div class="aphront-panel-preview aphront-panel-preview-wide">
|
||||
<div class="phriction-document-preview-header">
|
||||
Document Preview
|
||||
'.pht('Document Preview').'
|
||||
</div>
|
||||
<div id="document-preview">
|
||||
<div class="aphront-panel-preview-loading-text">
|
||||
Loading preview...
|
||||
'.pht('Loading preview...').'
|
||||
</div>
|
||||
</div>
|
||||
</div>';
|
||||
|
@ -259,7 +259,7 @@ final class PhrictionEditController
|
|||
$preview_panel,
|
||||
),
|
||||
array(
|
||||
'title' => 'Edit Document',
|
||||
'title' => pht('Edit Document'),
|
||||
));
|
||||
}
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ final class PhrictionHistoryController
|
|||
|
||||
$diff_uri = new PhutilURI('/phriction/diff/'.$document->getID().'/');
|
||||
|
||||
$vs_previous = '<em>Created</em>';
|
||||
$vs_previous = '<em>'.pht('Created').'</em>';
|
||||
if ($content->getVersion() != 1) {
|
||||
$uri = $diff_uri
|
||||
->alter('l', $content->getVersion() - 1)
|
||||
|
@ -59,10 +59,10 @@ final class PhrictionHistoryController
|
|||
array(
|
||||
'href' => $uri,
|
||||
),
|
||||
'Show Change');
|
||||
pht('Show Change'));
|
||||
}
|
||||
|
||||
$vs_head = '<em>Current</em>';
|
||||
$vs_head = '<em>'.pht('Current').'</em>';
|
||||
if ($content->getID() != $document->getContentID()) {
|
||||
$uri = $diff_uri
|
||||
->alter('l', $content->getVersion())
|
||||
|
@ -73,7 +73,7 @@ final class PhrictionHistoryController
|
|||
array(
|
||||
'href' => $uri,
|
||||
),
|
||||
'Show Later Changes');
|
||||
pht('Show Later Changes'));
|
||||
}
|
||||
|
||||
$change_type = PhrictionChangeType::getChangeTypeLabel(
|
||||
|
@ -87,7 +87,7 @@ final class PhrictionHistoryController
|
|||
array(
|
||||
'href' => $slug_uri.'?v='.$version,
|
||||
),
|
||||
'Version '.$version),
|
||||
pht('Version %s', $version)),
|
||||
$handles[$content->getAuthorPHID()]->renderLink(),
|
||||
$change_type,
|
||||
phutil_escape_html($content->getDescription()),
|
||||
|
@ -99,14 +99,14 @@ final class PhrictionHistoryController
|
|||
$table = new AphrontTableView($rows);
|
||||
$table->setHeaders(
|
||||
array(
|
||||
'Date',
|
||||
'Time',
|
||||
'Version',
|
||||
'Author',
|
||||
'Type',
|
||||
'Description',
|
||||
'Against Previous',
|
||||
'Against Current',
|
||||
pht('Date'),
|
||||
pht('Time'),
|
||||
pht('Version'),
|
||||
pht('Author'),
|
||||
pht('Type'),
|
||||
pht('Description'),
|
||||
pht('Against Previous'),
|
||||
pht('Against Current'),
|
||||
));
|
||||
$table->setColumnClasses(
|
||||
array(
|
||||
|
@ -132,7 +132,8 @@ final class PhrictionHistoryController
|
|||
PhrictionDocument::getSlugURI($document->getSlug(), 'history')));
|
||||
|
||||
$panel = new AphrontPanelView();
|
||||
$panel->setHeader('Document History');
|
||||
$panel->setHeader(pht('Document History'));
|
||||
$panel->setNoBackground();
|
||||
$panel->appendChild($table);
|
||||
$panel->appendChild($pager);
|
||||
|
||||
|
@ -142,7 +143,7 @@ final class PhrictionHistoryController
|
|||
$panel,
|
||||
),
|
||||
array(
|
||||
'title' => 'Document History',
|
||||
'title' => pht('Document History'),
|
||||
'device' => true,
|
||||
));
|
||||
|
||||
|
|
|
@ -67,10 +67,10 @@ final class PhrictionListController
|
|||
$document_table = new AphrontTableView($rows);
|
||||
$document_table->setHeaders(
|
||||
array(
|
||||
'Last Editor',
|
||||
'Title',
|
||||
'Last Update',
|
||||
'Time',
|
||||
pht('Last Editor'),
|
||||
pht('Title'),
|
||||
pht('Last Update'),
|
||||
pht('Time'),
|
||||
));
|
||||
|
||||
$document_table->setColumnClasses(
|
||||
|
@ -84,6 +84,7 @@ final class PhrictionListController
|
|||
$view_header = $views[$this->view];
|
||||
|
||||
$panel = new AphrontPanelView();
|
||||
$panel->setNoBackground();
|
||||
$panel->appendChild($document_table);
|
||||
$panel->appendChild($pager);
|
||||
|
||||
|
|
|
@ -78,7 +78,7 @@ final class PhrictionContent extends PhrictionDAO
|
|||
$toc =
|
||||
'<div class="phabricator-remarkup-toc">'.
|
||||
'<div class="phabricator-remarkup-toc-header">'.
|
||||
'Table of Contents'.
|
||||
pht('Table of Contents').
|
||||
'</div>'.
|
||||
$toc.
|
||||
'</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:
|
||||
|
||||
phabricator/ $ ./bin/aphlict --foreground
|
||||
phabricator/ $ sudo ./bin/aphlict --foreground
|
||||
|
||||
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
|
||||
|
|
|
@ -9,16 +9,16 @@ extends PhabricatorBaseProtocolAdapter {
|
|||
private $readHandles;
|
||||
private $multiHandle;
|
||||
private $active;
|
||||
private $rooms;
|
||||
private $inRooms = array();
|
||||
|
||||
public function connect() {
|
||||
$this->server = idx($this->config, 'server');
|
||||
$this->authtoken = idx($this->config, 'authtoken');
|
||||
$ssl = idx($this->config, 'ssl', false);
|
||||
$this->rooms = idx($this->config, 'join');
|
||||
$rooms = idx($this->config, 'join');
|
||||
|
||||
// First, join the room
|
||||
if (!$this->rooms) {
|
||||
if (!$rooms) {
|
||||
throw new Exception("Not configured to join any rooms!");
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,7 @@ extends PhabricatorBaseProtocolAdapter {
|
|||
$this->multiHandle = curl_multi_init();
|
||||
$this->readHandles = array();
|
||||
|
||||
foreach ($this->rooms as $room_id) {
|
||||
foreach ($rooms as $room_id) {
|
||||
$this->joinRoom($room_id);
|
||||
|
||||
// Set up the curl stream for reading
|
||||
|
@ -138,10 +138,12 @@ extends PhabricatorBaseProtocolAdapter {
|
|||
|
||||
private function joinRoom($room_id) {
|
||||
$this->performPost("/room/{$room_id}/join.json");
|
||||
$this->inRooms[$room_id] = true;
|
||||
}
|
||||
|
||||
private function leaveRoom($room_id) {
|
||||
$this->performPost("/room/{$room_id}/leave.json");
|
||||
unset($this->inRooms[$room_id]);
|
||||
}
|
||||
|
||||
private function speak($message, $room_id) {
|
||||
|
@ -154,48 +156,42 @@ extends PhabricatorBaseProtocolAdapter {
|
|||
}
|
||||
|
||||
private function performPost($endpoint, $data = Null) {
|
||||
$url = $this->server.$endpoint;
|
||||
$uri = new PhutilURI($this->server);
|
||||
$uri->setPath($endpoint);
|
||||
|
||||
$payload = json_encode($data);
|
||||
|
||||
// cURL init & config
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_URL, $url);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_POST, 1);
|
||||
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
|
||||
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);
|
||||
list($output) = id(new HTTPSFuture($uri))
|
||||
->setMethod('POST')
|
||||
->addHeader('Content-Type', 'application/json')
|
||||
->addHeader('Authorization', $this->getAuthorizationHeader())
|
||||
->setData($payload)
|
||||
->resolvex();
|
||||
|
||||
$output = trim($output);
|
||||
|
||||
if (strlen($output)) {
|
||||
return json_decode($output);
|
||||
return json_decode($output, true);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function __destruct() {
|
||||
if ($this->rooms) {
|
||||
foreach ($this->rooms as $room_id) {
|
||||
foreach ($this->inRooms as $room_id => $ignored) {
|
||||
$this->leaveRoom($room_id);
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->readHandles) {
|
||||
foreach ($this->readHandles as $read_handle) {
|
||||
curl_multi_remove_handle($this->multiHandle, $read_handle);
|
||||
curl_close($read_handle);
|
||||
}
|
||||
}
|
||||
|
||||
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(
|
||||
'button',
|
||||
array(
|
||||
'type' => 'submit',
|
||||
'name' => '__submit__',
|
||||
'disabled' => $this->getDisabled() ? 'disabled' : null,
|
||||
),
|
||||
|
|
|
@ -7,6 +7,9 @@ body {
|
|||
scrollbar to a page with a scrollbar doesn't make content jump a few
|
||||
pixels left when the viewport narrows. */
|
||||
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 {
|
||||
|
|
|
@ -35,6 +35,7 @@ JX.behavior('pholio-mock-view', function(config) {
|
|||
main.src = data.fullSizeURI;
|
||||
|
||||
JX.DOM.setContent(wrapper,main);
|
||||
load_inline_comments();
|
||||
});
|
||||
|
||||
|
||||
|
@ -123,7 +124,7 @@ JX.behavior('pholio-mock-view', function(config) {
|
|||
|
||||
selection_fill.title = comment;
|
||||
|
||||
var saveURL = "/pholio/inline/" + imageData['imageID'] + "/";
|
||||
var saveURL = "/pholio/inline/save/";
|
||||
|
||||
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