1
0
Fork 0
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:
epriestley 2013-02-08 17:29:15 -08:00
commit 7ec8e885e1
35 changed files with 498 additions and 201 deletions

View file

@ -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

View file

@ -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',
), ),
)); ));

View file

@ -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(

View file

@ -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');
}
}
}
}

View file

@ -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(

View file

@ -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)

View file

@ -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;
} }
} }

View file

@ -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".',

View file

@ -172,7 +172,7 @@ class DifferentialReplyHandler extends PhabricatorMailReplyHandler {
DifferentialRevisionEditor::removeCCAndUpdateRevision( DifferentialRevisionEditor::removeCCAndUpdateRevision(
$revision, $revision,
$user->getPHID(), $user->getPHID(),
$user->getPHID()); $user);
} }

View file

@ -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();

View file

@ -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();
} }

View file

@ -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();

View file

@ -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;
}
} }

View file

@ -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");
}
} }

View file

@ -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;
}
}
} }

View file

@ -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")),
); );
} }

View file

@ -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',

View file

@ -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);

View file

@ -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',
), ),
); );
} }

View file

@ -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);
}
}

View file

@ -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() {

View file

@ -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'));

View file

@ -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);

View file

@ -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(

View file

@ -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(

View file

@ -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'),
)); ));
} }

View file

@ -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,
)); ));

View file

@ -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);

View file

@ -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
View file

@ -0,0 +1,4 @@
{
"name" : "phabricator",
"root" : "../../../"
}

View file

@ -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

View file

@ -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');
}
} }

View file

@ -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,
), ),

View file

@ -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 {

View file

@ -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();
}); });