From 5f9a06333356dc4d44c155ff4484c4e85fea2285 Mon Sep 17 00:00:00 2001 From: epriestley Date: Thu, 7 Feb 2013 10:32:33 -0800 Subject: [PATCH 01/13] Use some HTTPSFuture in CampfireBot Summary: - Use PhutilURI to correct for specifying "https://yourname.campfire.com/" instead of "https://yourname.campfire.com". - Use HTTPSFuture to get logging via `--trace` and error detection (CA stuff should be OK since 37signals has real certs). - On destruction, only try to leave rooms we've actually joined. Test Plan: Setup a bot, had it join a room, talked to it. Reviewers: indiefan Reviewed By: indiefan CC: aran Differential Revision: https://secure.phabricator.com/D4849 --- .../PhabricatorCampfireProtocolAdapter.php | 50 +++++++++---------- 1 file changed, 23 insertions(+), 27 deletions(-) diff --git a/src/infrastructure/daemon/bot/adapter/PhabricatorCampfireProtocolAdapter.php b/src/infrastructure/daemon/bot/adapter/PhabricatorCampfireProtocolAdapter.php index 59323baf6f..1c94d0c27b 100644 --- a/src/infrastructure/daemon/bot/adapter/PhabricatorCampfireProtocolAdapter.php +++ b/src/infrastructure/daemon/bot/adapter/PhabricatorCampfireProtocolAdapter.php @@ -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) { - $this->leaveRoom($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'); + } } From 56c8387403aa3d60b7f9abde9013c203cd936a52 Mon Sep 17 00:00:00 2001 From: Bob Trahan Date: Thu, 7 Feb 2013 10:46:08 -0800 Subject: [PATCH 02/13] rebuild celerity map - conpherence wasn't working. Summary: . Test Plan: conpherence loaded Reviewers: epriestley, chad, vrana CC: aran, Korvin Differential Revision: https://secure.phabricator.com/D4851 --- src/__celerity_resource_map__.php | 112 ++++++++++++++++++------------ 1 file changed, 69 insertions(+), 43 deletions(-) diff --git a/src/__celerity_resource_map__.php b/src/__celerity_resource_map__.php index b245c6583f..09209d64b1 100644 --- a/src/__celerity_resource_map__.php +++ b/src/__celerity_resource_map__.php @@ -639,7 +639,7 @@ celerity_register_resource_map(array( ), 'aphront-form-view-css' => array( - 'uri' => '/res/428fbcd8/rsrc/css/aphront/form-view.css', + 'uri' => '/res/ec323d34/rsrc/css/aphront/form-view.css', 'type' => 'css', 'requires' => array( @@ -748,7 +748,7 @@ celerity_register_resource_map(array( ), 'conpherence-header-pane-css' => array( - 'uri' => '/res/4b8aebd2/rsrc/css/application/conpherence/header-pane.css', + 'uri' => '/res/11c32adc/rsrc/css/application/conpherence/header-pane.css', 'type' => 'css', 'requires' => array( @@ -775,7 +775,7 @@ celerity_register_resource_map(array( ), 'conpherence-update-css' => array( - 'uri' => '/res/8e4757b5/rsrc/css/application/conpherence/update.css', + 'uri' => '/res/92094ed7/rsrc/css/application/conpherence/update.css', 'type' => 'css', 'requires' => array( @@ -1042,6 +1042,19 @@ celerity_register_resource_map(array( ), 'disk' => '/rsrc/js/application/core/behavior-tokenizer.js', ), + 'javelin-behavior-aphront-crop' => + array( + 'uri' => '/res/cda1eace/rsrc/js/application/core/behavior-crop.js', + 'type' => 'js', + 'requires' => + array( + 0 => 'javelin-behavior', + 1 => 'javelin-dom', + 2 => 'javelin-vector', + 3 => 'javelin-magical-init', + ), + 'disk' => '/rsrc/js/application/core/behavior-crop.js', + ), 'javelin-behavior-aphront-drag-and-drop' => array( 'uri' => '/res/3d809b40/rsrc/js/application/core/behavior-drag-and-drop.js', @@ -1106,6 +1119,19 @@ celerity_register_resource_map(array( ), 'disk' => '/rsrc/js/application/diffusion/behavior-audit-preview.js', ), + 'javelin-behavior-conpherence-drag-and-drop-photo' => + array( + 'uri' => '/res/9e3eb1cd/rsrc/js/application/conpherence/behavior-drag-and-drop-photo.js', + 'type' => 'js', + 'requires' => + array( + 0 => 'javelin-behavior', + 1 => 'javelin-dom', + 2 => 'javelin-workflow', + 3 => 'phabricator-drag-and-drop-file-upload', + ), + 'disk' => '/rsrc/js/application/conpherence/behavior-drag-and-drop-photo.js', + ), 'javelin-behavior-conpherence-init' => array( 'uri' => '/res/bd911b43/rsrc/js/application/conpherence/behavior-init.js', @@ -3397,7 +3423,7 @@ celerity_register_resource_map(array( ), array( 'packages' => array( - '7d347135' => + '23503cb9' => array( 'name' => 'core.pkg.css', 'symbols' => @@ -3441,7 +3467,7 @@ celerity_register_resource_map(array( 36 => 'phabricator-object-item-list-view-css', 37 => 'global-drag-and-drop-css', ), - 'uri' => '/res/pkg/7d347135/core.pkg.css', + 'uri' => '/res/pkg/23503cb9/core.pkg.css', 'type' => 'css', ), '58743fec' => @@ -3631,19 +3657,19 @@ celerity_register_resource_map(array( 'reverse' => array( 'aphront-attached-file-view-css' => 'e30a3fa8', - 'aphront-crumbs-view-css' => '7d347135', - 'aphront-dialog-view-css' => '7d347135', - 'aphront-error-view-css' => '7d347135', - 'aphront-form-view-css' => '7d347135', + 'aphront-crumbs-view-css' => '23503cb9', + 'aphront-dialog-view-css' => '23503cb9', + 'aphront-error-view-css' => '23503cb9', + 'aphront-form-view-css' => '23503cb9', 'aphront-headsup-action-list-view-css' => 'ec01d039', - 'aphront-headsup-view-css' => '7d347135', - 'aphront-list-filter-view-css' => '7d347135', - 'aphront-pager-view-css' => '7d347135', - 'aphront-panel-view-css' => '7d347135', - 'aphront-table-view-css' => '7d347135', - 'aphront-tokenizer-control-css' => '7d347135', - 'aphront-tooltip-css' => '7d347135', - 'aphront-typeahead-control-css' => '7d347135', + 'aphront-headsup-view-css' => '23503cb9', + 'aphront-list-filter-view-css' => '23503cb9', + 'aphront-pager-view-css' => '23503cb9', + 'aphront-panel-view-css' => '23503cb9', + 'aphront-table-view-css' => '23503cb9', + 'aphront-tokenizer-control-css' => '23503cb9', + 'aphront-tooltip-css' => '23503cb9', + 'aphront-typeahead-control-css' => '23503cb9', 'differential-changeset-view-css' => 'ec01d039', 'differential-core-view-css' => 'ec01d039', 'differential-inline-comment-editor' => '95d0d865', @@ -3657,7 +3683,7 @@ celerity_register_resource_map(array( 'differential-table-of-contents-css' => 'ec01d039', 'diffusion-commit-view-css' => 'c8ce2d88', 'diffusion-icons-css' => 'c8ce2d88', - 'global-drag-and-drop-css' => '7d347135', + 'global-drag-and-drop-css' => '23503cb9', 'inline-comment-summary-css' => 'ec01d039', 'javelin-aphlict' => '58743fec', 'javelin-behavior' => '88225b70', @@ -3727,48 +3753,48 @@ celerity_register_resource_map(array( 'javelin-util' => '88225b70', 'javelin-vector' => '88225b70', 'javelin-workflow' => '88225b70', - 'lightbox-attachment-css' => '7d347135', + 'lightbox-attachment-css' => '23503cb9', 'maniphest-task-summary-css' => 'e30a3fa8', 'maniphest-transaction-detail-css' => 'e30a3fa8', 'phabricator-busy' => '58743fec', 'phabricator-content-source-view-css' => 'ec01d039', - 'phabricator-core-buttons-css' => '7d347135', - 'phabricator-core-css' => '7d347135', - 'phabricator-crumbs-view-css' => '7d347135', - 'phabricator-directory-css' => '7d347135', + 'phabricator-core-buttons-css' => '23503cb9', + 'phabricator-core-css' => '23503cb9', + 'phabricator-crumbs-view-css' => '23503cb9', + 'phabricator-directory-css' => '23503cb9', 'phabricator-drag-and-drop-file-upload' => '95d0d865', 'phabricator-dropdown-menu' => '58743fec', 'phabricator-file-upload' => '58743fec', - 'phabricator-filetree-view-css' => '7d347135', - 'phabricator-flag-css' => '7d347135', - 'phabricator-form-view-css' => '7d347135', - 'phabricator-header-view-css' => '7d347135', - 'phabricator-jump-nav' => '7d347135', + 'phabricator-filetree-view-css' => '23503cb9', + 'phabricator-flag-css' => '23503cb9', + 'phabricator-form-view-css' => '23503cb9', + 'phabricator-header-view-css' => '23503cb9', + 'phabricator-jump-nav' => '23503cb9', 'phabricator-keyboard-shortcut' => '58743fec', 'phabricator-keyboard-shortcut-manager' => '58743fec', - 'phabricator-main-menu-view' => '7d347135', + 'phabricator-main-menu-view' => '23503cb9', 'phabricator-menu-item' => '58743fec', - 'phabricator-nav-view-css' => '7d347135', + 'phabricator-nav-view-css' => '23503cb9', 'phabricator-notification' => '58743fec', - 'phabricator-notification-css' => '7d347135', - 'phabricator-notification-menu-css' => '7d347135', - 'phabricator-object-item-list-view-css' => '7d347135', + 'phabricator-notification-css' => '23503cb9', + 'phabricator-notification-menu-css' => '23503cb9', + 'phabricator-object-item-list-view-css' => '23503cb9', 'phabricator-object-selector-css' => 'ec01d039', 'phabricator-paste-file-upload' => '58743fec', 'phabricator-prefab' => '58743fec', 'phabricator-project-tag-css' => 'e30a3fa8', - 'phabricator-remarkup-css' => '7d347135', + 'phabricator-remarkup-css' => '23503cb9', 'phabricator-shaped-request' => '95d0d865', - 'phabricator-side-menu-view-css' => '7d347135', - 'phabricator-standard-page-view' => '7d347135', + 'phabricator-side-menu-view-css' => '23503cb9', + 'phabricator-standard-page-view' => '23503cb9', 'phabricator-textareautils' => '58743fec', 'phabricator-tooltip' => '58743fec', - 'phabricator-transaction-view-css' => '7d347135', - 'phabricator-zindex-css' => '7d347135', - 'sprite-apps-large-css' => '7d347135', - 'sprite-gradient-css' => '7d347135', - 'sprite-icon-css' => '7d347135', - 'sprite-menu-css' => '7d347135', - 'syntax-highlighting-css' => '7d347135', + 'phabricator-transaction-view-css' => '23503cb9', + 'phabricator-zindex-css' => '23503cb9', + 'sprite-apps-large-css' => '23503cb9', + 'sprite-gradient-css' => '23503cb9', + 'sprite-icon-css' => '23503cb9', + 'sprite-menu-css' => '23503cb9', + 'syntax-highlighting-css' => '23503cb9', ), )); From 07f72cf4635c919141e987fd2eeb945a87f5aa4e Mon Sep 17 00:00:00 2001 From: Bob Trahan Date: Thu, 7 Feb 2013 11:17:20 -0800 Subject: [PATCH 03/13] Fix conpherence name clearing bug Summary: pre-patch, when you upload a photo if the conphernece has a name it gets cleared. Post patch this no longer happens. Patch also makes the case where you delete the conpherence name have more sensical text. Test Plan: named a conpherence, uploaded an image, verified the name stayed the same. Deleted a conpherence name by changing the text to nothing and verified it work correctly, including having good transaction text. Reviewers: epriestley, chad Reviewed By: epriestley CC: aran, Korvin Maniphest Tasks: T2399 Differential Revision: https://secure.phabricator.com/D4852 --- .../conpherence/controller/ConpherenceUpdateController.php | 4 +++- .../conpherence/storage/ConpherenceTransaction.php | 7 ++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/applications/conpherence/controller/ConpherenceUpdateController.php b/src/applications/conpherence/controller/ConpherenceUpdateController.php index ad3bf86fa1..b9b7131be3 100644 --- a/src/applications/conpherence/controller/ConpherenceUpdateController.php +++ b/src/applications/conpherence/controller/ConpherenceUpdateController.php @@ -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) diff --git a/src/applications/conpherence/storage/ConpherenceTransaction.php b/src/applications/conpherence/storage/ConpherenceTransaction.php index 22a4aa666e..64afcf9157 100644 --- a/src/applications/conpherence/storage/ConpherenceTransaction.php +++ b/src/applications/conpherence/storage/ConpherenceTransaction.php @@ -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".', From 4cafbbc525f73a5eda585a540d092328f0a5f638 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Thu, 7 Feb 2013 13:41:46 -0800 Subject: [PATCH 04/13] Fix IE7 and IE8 issues. Summary: Resolves submit issues in IE7, scrollbars in IE7 and homepage layout issues in IE7 and IE8. Test Plan: used IE7 and IE8. Logged in, bounced around. Checked Chrome as well. Reviewers: epriestley, btrahan Reviewed By: epriestley CC: aran, Korvin Maniphest Tasks: T2469, T2470 Differential Revision: https://secure.phabricator.com/D4853 --- src/__celerity_resource_map__.php | 82 +++++++++---------- .../view/PhabricatorApplicationLaunchView.php | 3 +- .../form/control/AphrontFormSubmitControl.php | 1 + webroot/rsrc/css/core/core.css | 3 + 4 files changed, 47 insertions(+), 42 deletions(-) diff --git a/src/__celerity_resource_map__.php b/src/__celerity_resource_map__.php index 09209d64b1..a89caf7ced 100644 --- a/src/__celerity_resource_map__.php +++ b/src/__celerity_resource_map__.php @@ -2614,7 +2614,7 @@ celerity_register_resource_map(array( ), 'phabricator-core-css' => array( - 'uri' => '/res/03c97d00/rsrc/css/core/core.css', + 'uri' => '/res/27afb689/rsrc/css/core/core.css', 'type' => 'css', 'requires' => array( @@ -3423,7 +3423,7 @@ celerity_register_resource_map(array( ), array( 'packages' => array( - '23503cb9' => + '77c4590d' => array( 'name' => 'core.pkg.css', 'symbols' => @@ -3467,7 +3467,7 @@ celerity_register_resource_map(array( 36 => 'phabricator-object-item-list-view-css', 37 => 'global-drag-and-drop-css', ), - 'uri' => '/res/pkg/23503cb9/core.pkg.css', + 'uri' => '/res/pkg/77c4590d/core.pkg.css', 'type' => 'css', ), '58743fec' => @@ -3657,19 +3657,19 @@ celerity_register_resource_map(array( 'reverse' => array( 'aphront-attached-file-view-css' => 'e30a3fa8', - 'aphront-crumbs-view-css' => '23503cb9', - 'aphront-dialog-view-css' => '23503cb9', - 'aphront-error-view-css' => '23503cb9', - 'aphront-form-view-css' => '23503cb9', + 'aphront-crumbs-view-css' => '77c4590d', + 'aphront-dialog-view-css' => '77c4590d', + 'aphront-error-view-css' => '77c4590d', + 'aphront-form-view-css' => '77c4590d', 'aphront-headsup-action-list-view-css' => 'ec01d039', - 'aphront-headsup-view-css' => '23503cb9', - 'aphront-list-filter-view-css' => '23503cb9', - 'aphront-pager-view-css' => '23503cb9', - 'aphront-panel-view-css' => '23503cb9', - 'aphront-table-view-css' => '23503cb9', - 'aphront-tokenizer-control-css' => '23503cb9', - 'aphront-tooltip-css' => '23503cb9', - 'aphront-typeahead-control-css' => '23503cb9', + 'aphront-headsup-view-css' => '77c4590d', + 'aphront-list-filter-view-css' => '77c4590d', + 'aphront-pager-view-css' => '77c4590d', + 'aphront-panel-view-css' => '77c4590d', + 'aphront-table-view-css' => '77c4590d', + 'aphront-tokenizer-control-css' => '77c4590d', + 'aphront-tooltip-css' => '77c4590d', + 'aphront-typeahead-control-css' => '77c4590d', 'differential-changeset-view-css' => 'ec01d039', 'differential-core-view-css' => 'ec01d039', 'differential-inline-comment-editor' => '95d0d865', @@ -3683,7 +3683,7 @@ celerity_register_resource_map(array( 'differential-table-of-contents-css' => 'ec01d039', 'diffusion-commit-view-css' => 'c8ce2d88', 'diffusion-icons-css' => 'c8ce2d88', - 'global-drag-and-drop-css' => '23503cb9', + 'global-drag-and-drop-css' => '77c4590d', 'inline-comment-summary-css' => 'ec01d039', 'javelin-aphlict' => '58743fec', 'javelin-behavior' => '88225b70', @@ -3753,48 +3753,48 @@ celerity_register_resource_map(array( 'javelin-util' => '88225b70', 'javelin-vector' => '88225b70', 'javelin-workflow' => '88225b70', - 'lightbox-attachment-css' => '23503cb9', + 'lightbox-attachment-css' => '77c4590d', 'maniphest-task-summary-css' => 'e30a3fa8', 'maniphest-transaction-detail-css' => 'e30a3fa8', 'phabricator-busy' => '58743fec', 'phabricator-content-source-view-css' => 'ec01d039', - 'phabricator-core-buttons-css' => '23503cb9', - 'phabricator-core-css' => '23503cb9', - 'phabricator-crumbs-view-css' => '23503cb9', - 'phabricator-directory-css' => '23503cb9', + 'phabricator-core-buttons-css' => '77c4590d', + 'phabricator-core-css' => '77c4590d', + 'phabricator-crumbs-view-css' => '77c4590d', + 'phabricator-directory-css' => '77c4590d', 'phabricator-drag-and-drop-file-upload' => '95d0d865', 'phabricator-dropdown-menu' => '58743fec', 'phabricator-file-upload' => '58743fec', - 'phabricator-filetree-view-css' => '23503cb9', - 'phabricator-flag-css' => '23503cb9', - 'phabricator-form-view-css' => '23503cb9', - 'phabricator-header-view-css' => '23503cb9', - 'phabricator-jump-nav' => '23503cb9', + 'phabricator-filetree-view-css' => '77c4590d', + 'phabricator-flag-css' => '77c4590d', + 'phabricator-form-view-css' => '77c4590d', + 'phabricator-header-view-css' => '77c4590d', + 'phabricator-jump-nav' => '77c4590d', 'phabricator-keyboard-shortcut' => '58743fec', 'phabricator-keyboard-shortcut-manager' => '58743fec', - 'phabricator-main-menu-view' => '23503cb9', + 'phabricator-main-menu-view' => '77c4590d', 'phabricator-menu-item' => '58743fec', - 'phabricator-nav-view-css' => '23503cb9', + 'phabricator-nav-view-css' => '77c4590d', 'phabricator-notification' => '58743fec', - 'phabricator-notification-css' => '23503cb9', - 'phabricator-notification-menu-css' => '23503cb9', - 'phabricator-object-item-list-view-css' => '23503cb9', + 'phabricator-notification-css' => '77c4590d', + 'phabricator-notification-menu-css' => '77c4590d', + 'phabricator-object-item-list-view-css' => '77c4590d', 'phabricator-object-selector-css' => 'ec01d039', 'phabricator-paste-file-upload' => '58743fec', 'phabricator-prefab' => '58743fec', 'phabricator-project-tag-css' => 'e30a3fa8', - 'phabricator-remarkup-css' => '23503cb9', + 'phabricator-remarkup-css' => '77c4590d', 'phabricator-shaped-request' => '95d0d865', - 'phabricator-side-menu-view-css' => '23503cb9', - 'phabricator-standard-page-view' => '23503cb9', + 'phabricator-side-menu-view-css' => '77c4590d', + 'phabricator-standard-page-view' => '77c4590d', 'phabricator-textareautils' => '58743fec', 'phabricator-tooltip' => '58743fec', - 'phabricator-transaction-view-css' => '23503cb9', - 'phabricator-zindex-css' => '23503cb9', - 'sprite-apps-large-css' => '23503cb9', - 'sprite-gradient-css' => '23503cb9', - 'sprite-icon-css' => '23503cb9', - 'sprite-menu-css' => '23503cb9', - 'syntax-highlighting-css' => '23503cb9', + 'phabricator-transaction-view-css' => '77c4590d', + 'phabricator-zindex-css' => '77c4590d', + 'sprite-apps-large-css' => '77c4590d', + 'sprite-gradient-css' => '77c4590d', + 'sprite-icon-css' => '77c4590d', + 'sprite-menu-css' => '77c4590d', + 'syntax-highlighting-css' => '77c4590d', ), )); diff --git a/src/applications/meta/view/PhabricatorApplicationLaunchView.php b/src/applications/meta/view/PhabricatorApplicationLaunchView.php index c5c45ae1ef..726c7ef704 100644 --- a/src/applications/meta/view/PhabricatorApplicationLaunchView.php +++ b/src/applications/meta/view/PhabricatorApplicationLaunchView.php @@ -101,7 +101,8 @@ final class PhabricatorApplicationLaunchView extends AphrontView { 'span', array( 'class' => implode(' ', $classes), - )); + ), + ''); $create_button = phutil_render_tag( 'a', diff --git a/src/view/form/control/AphrontFormSubmitControl.php b/src/view/form/control/AphrontFormSubmitControl.php index 9ec7593dcd..2c793c0812 100644 --- a/src/view/form/control/AphrontFormSubmitControl.php +++ b/src/view/form/control/AphrontFormSubmitControl.php @@ -25,6 +25,7 @@ final class AphrontFormSubmitControl extends AphrontFormControl { $submit_button = phutil_render_tag( 'button', array( + 'type' => 'submit', 'name' => '__submit__', 'disabled' => $this->getDisabled() ? 'disabled' : null, ), diff --git a/webroot/rsrc/css/core/core.css b/webroot/rsrc/css/core/core.css index 024bd4ad6e..608af924cf 100644 --- a/webroot/rsrc/css/core/core.css +++ b/webroot/rsrc/css/core/core.css @@ -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 { From 275f708f1447277f3dc05558b32d9ea400ecd2e7 Mon Sep 17 00:00:00 2001 From: Bob Trahan Date: Thu, 7 Feb 2013 15:17:11 -0800 Subject: [PATCH 05/13] Conpherence - make messages to btrahan@metamta.domain start conpherences Summary: I'm not super happy with the prettiness of the code, but I wasn't able to come up with a good way to clean it up. Happy for suggestions. Test Plan: sent message to btrahan@phabricator.dev from gmail. Copied raw email and piped it to mail_handler.php -- it created a conpherence! Repeated but sent to btrahan and xerxes and noted that the conpherence was created for both users Reviewers: epriestley, chad Reviewed By: epriestley CC: aran, Korvin Maniphest Tasks: T2431 Differential Revision: https://secure.phabricator.com/D4854 --- .../mail/ConpherenceReplyHandler.php | 29 ++++++++-- .../PhabricatorMetaMTAReceivedMail.php | 58 ++++++++++++++++--- 2 files changed, 76 insertions(+), 11 deletions(-) diff --git a/src/applications/conpherence/mail/ConpherenceReplyHandler.php b/src/applications/conpherence/mail/ConpherenceReplyHandler.php index f7de36cb25..0955a6a961 100644 --- a/src/applications/conpherence/mail/ConpherenceReplyHandler.php +++ b/src/applications/conpherence/mail/ConpherenceReplyHandler.php @@ -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( - $conpherence, - $body + + $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; } } diff --git a/src/applications/metamta/storage/PhabricatorMetaMTAReceivedMail.php b/src/applications/metamta/storage/PhabricatorMetaMTAReceivedMail.php index ca7dee2acf..d547e458bd 100644 --- a/src/applications/metamta/storage/PhabricatorMetaMTAReceivedMail.php +++ b/src/applications/metamta/storage/PhabricatorMetaMTAReceivedMail.php @@ -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); From 714a3cc5369c7f7b74abd44f29961e8be855d921 Mon Sep 17 00:00:00 2001 From: Nick Harper Date: Thu, 7 Feb 2013 16:59:14 -0800 Subject: [PATCH 06/13] Catch exception in differential Summary: This masks possible configuration issues and slightly degrades functionality with the tradeoff of having differential work when phabricator isn't quite configured correctly. Test Plan: remove directory for a repository, load differential revision from that repo, and see differential load. Reviewers: epriestley, vrana Reviewed By: epriestley CC: aran, Korvin Maniphest Tasks: T2512 Differential Revision: https://secure.phabricator.com/D4859 --- .../view/DifferentialChangesetListView.php | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/applications/differential/view/DifferentialChangesetListView.php b/src/applications/differential/view/DifferentialChangesetListView.php index 43f33572a8..06bd074c54 100644 --- a/src/applications/differential/view/DifferentialChangesetListView.php +++ b/src/applications/differential/view/DifferentialChangesetListView.php @@ -251,10 +251,15 @@ final class DifferentialChangesetListView extends AphrontView { $repository = $this->repository; if ($repository) { - $meta['diffusionURI'] = (string)$repository->getDiffusionBrowseURIForPath( - $changeset->getAbsoluteRepositoryPath($repository, $this->diff), - idx($changeset->getMetadata(), 'line:first'), - $this->getBranch()); + 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(); From 7063ee638e0a8df8d963c1e0be060852224b3dac Mon Sep 17 00:00:00 2001 From: vrana Date: Thu, 7 Feb 2013 18:13:38 -0800 Subject: [PATCH 07/13] Pass actor to revision unsubscriber editor Summary: I wonder how I tested this. Test Plan: Subscribed, unsubscribed. Reviewers: epriestley Reviewed By: epriestley CC: aran, Korvin Differential Revision: https://secure.phabricator.com/D4860 --- .../differential/DifferentialReplyHandler.php | 2 +- .../controller/DifferentialSubscribeController.php | 4 ++-- .../differential/editor/DifferentialRevisionEditor.php | 10 ++++++---- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/applications/differential/DifferentialReplyHandler.php b/src/applications/differential/DifferentialReplyHandler.php index 976aac57b5..9a3e3845f1 100644 --- a/src/applications/differential/DifferentialReplyHandler.php +++ b/src/applications/differential/DifferentialReplyHandler.php @@ -172,7 +172,7 @@ class DifferentialReplyHandler extends PhabricatorMailReplyHandler { DifferentialRevisionEditor::removeCCAndUpdateRevision( $revision, $user->getPHID(), - $user->getPHID()); + $user); } diff --git a/src/applications/differential/controller/DifferentialSubscribeController.php b/src/applications/differential/controller/DifferentialSubscribeController.php index bc3e0630af..9d1ade910d 100644 --- a/src/applications/differential/controller/DifferentialSubscribeController.php +++ b/src/applications/differential/controller/DifferentialSubscribeController.php @@ -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(); diff --git a/src/applications/differential/editor/DifferentialRevisionEditor.php b/src/applications/differential/editor/DifferentialRevisionEditor.php index d7c035637a..19f78bb9f8 100644 --- a/src/applications/differential/editor/DifferentialRevisionEditor.php +++ b/src/applications/differential/editor/DifferentialRevisionEditor.php @@ -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(); } From bed728f23e8e2a45d40f3a8f14ca8c914bd5798c Mon Sep 17 00:00:00 2001 From: Lauri-Henrik Jalonen Date: Fri, 8 Feb 2013 07:24:17 -0800 Subject: [PATCH 08/13] Show saved inline comments Summary: Saved inline comments are now shown for images. Test Plan: Verified that inline comments are loaded and shown. Reviewers: epriestley CC: aran, Korvin Maniphest Tasks: T2446 Differential Revision: https://secure.phabricator.com/D4866 --- src/__phutil_library_map__.php | 2 + .../PhabricatorApplicationPholio.php | 3 +- .../controller/PholioInlineController.php | 38 +++++++++++++++++++ .../pholio/view/PholioMockImagesView.php | 2 +- .../pholio/behavior-pholio-mock-view.js | 33 +++++++++++++++- 5 files changed, 75 insertions(+), 3 deletions(-) create mode 100644 src/applications/pholio/controller/PholioInlineController.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index add675ee98..49650e27dd 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1410,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', @@ -2829,6 +2830,7 @@ phutil_register_library_map(array( 0 => 'PholioDAO', 1 => 'PhabricatorMarkupInterface', ), + 'PholioInlineController' => 'PholioController', 'PholioInlineSaveController' => 'PholioController', 'PholioMock' => array( diff --git a/src/applications/pholio/application/PhabricatorApplicationPholio.php b/src/applications/pholio/application/PhabricatorApplicationPholio.php index 10e4cafb07..f341b427dc 100644 --- a/src/applications/pholio/application/PhabricatorApplicationPholio.php +++ b/src/applications/pholio/application/PhabricatorApplicationPholio.php @@ -43,7 +43,8 @@ final class PhabricatorApplicationPholio extends PhabricatorApplication { 'new/' => 'PholioMockEditController', 'edit/(?P\d+)/' => 'PholioMockEditController', 'comment/(?P\d+)/' => 'PholioMockCommentController', - 'inline/(?P\d+)/' => 'PholioInlineSaveController', + 'inline/(?P\d+)/' => 'PholioInlineController', + 'inline/save/' => 'PholioInlineSaveController', ), ); } diff --git a/src/applications/pholio/controller/PholioInlineController.php b/src/applications/pholio/controller/PholioInlineController.php new file mode 100644 index 0000000000..618ff863ee --- /dev/null +++ b/src/applications/pholio/controller/PholioInlineController.php @@ -0,0 +1,38 @@ +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); + } + +} diff --git a/src/applications/pholio/view/PholioMockImagesView.php b/src/applications/pholio/view/PholioMockImagesView.php index 1f29b39db6..6500a8e78a 100644 --- a/src/applications/pholio/view/PholioMockImagesView.php +++ b/src/applications/pholio/view/PholioMockImagesView.php @@ -24,7 +24,7 @@ final class PholioMockImagesView extends AphrontView { $main_image = head($this->mock->getImages()); - $main_image_tag = javelin_render_tag( + $main_image_tag = javelin_render_tag( 'img', array( 'id' => $main_image_id, diff --git a/webroot/rsrc/js/application/pholio/behavior-pholio-mock-view.js b/webroot/rsrc/js/application/pholio/behavior-pholio-mock-view.js index 7b0e0fb1d1..22ea7ab763 100644 --- a/webroot/rsrc/js/application/pholio/behavior-pholio-mock-view.js +++ b/webroot/rsrc/js/application/pholio/behavior-pholio-mock-view.js @@ -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(); + }); From cc084822dabb122ac8abb2071d569a9f483a3a32 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Fri, 8 Feb 2013 08:00:17 -0800 Subject: [PATCH 09/13] Remove panel background in Phriction Summary: For consistency, remove panel backgrounds on forms. Test Plan: Reload pages Reviewers: btrahan, epriestley Reviewed By: epriestley CC: aran, Korvin Differential Revision: https://secure.phabricator.com/D4863 --- .../phriction/controller/PhrictionEditController.php | 2 +- .../phriction/controller/PhrictionHistoryController.php | 1 + .../phriction/controller/PhrictionListController.php | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/applications/phriction/controller/PhrictionEditController.php b/src/applications/phriction/controller/PhrictionEditController.php index 2c35ce4bed..f701839262 100644 --- a/src/applications/phriction/controller/PhrictionEditController.php +++ b/src/applications/phriction/controller/PhrictionEditController.php @@ -226,7 +226,7 @@ final class PhrictionEditController ->setValue($submit_button)); $panel = id(new AphrontPanelView()) - ->setWidth(AphrontPanelView::WIDTH_WIDE) + ->setNoBackground() ->setHeader($panel_header) ->appendChild($form); diff --git a/src/applications/phriction/controller/PhrictionHistoryController.php b/src/applications/phriction/controller/PhrictionHistoryController.php index 35cc7e1a44..e6bb0a9aa1 100644 --- a/src/applications/phriction/controller/PhrictionHistoryController.php +++ b/src/applications/phriction/controller/PhrictionHistoryController.php @@ -133,6 +133,7 @@ final class PhrictionHistoryController $panel = new AphrontPanelView(); $panel->setHeader('Document History'); + $panel->setNoBackground(); $panel->appendChild($table); $panel->appendChild($pager); diff --git a/src/applications/phriction/controller/PhrictionListController.php b/src/applications/phriction/controller/PhrictionListController.php index abd90432e9..269a70288c 100644 --- a/src/applications/phriction/controller/PhrictionListController.php +++ b/src/applications/phriction/controller/PhrictionListController.php @@ -84,6 +84,7 @@ final class PhrictionListController $view_header = $views[$this->view]; $panel = new AphrontPanelView(); + $panel->setNoBackground(); $panel->appendChild($document_table); $panel->appendChild($pager); From 9c19e9b7d86933f015cbde0575b0d70abf2ba4d7 Mon Sep 17 00:00:00 2001 From: Afaque Hussain Date: Fri, 8 Feb 2013 09:14:28 -0800 Subject: [PATCH 10/13] Preserving the Animation of Gif Images Summary: Preserving animation of GIF profile Pictures Test Plan: Uploaded Animated images as profile pictures to check if the animation of gif images is preserved and it does :) somewhat ! Reviewers: epriestley Reviewed By: epriestley CC: aran, Korvin Differential Revision: https://secure.phabricator.com/D4833 --- conf/default.conf.php | 4 ++ src/__phutil_library_map__.php | 2 + .../PhabricatorSetupCheckImagemagick.php | 25 +++++++ .../option/PhabricatorCoreConfigOptions.php | 2 +- .../files/PhabricatorImageTransformer.php | 69 ++++++++++++++++--- .../config/PhabricatorFilesConfigOptions.php | 10 +++ 6 files changed, 103 insertions(+), 9 deletions(-) create mode 100644 src/applications/config/check/PhabricatorSetupCheckImagemagick.php diff --git a/conf/default.conf.php b/conf/default.conf.php index b22e053827..0d13f5e895 100644 --- a/conf/default.conf.php +++ b/conf/default.conf.php @@ -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 diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 49650e27dd..8176961f8f 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1261,6 +1261,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', @@ -2677,6 +2678,7 @@ phutil_register_library_map(array( 'PhabricatorSetupCheckExtraConfig' => 'PhabricatorSetupCheck', 'PhabricatorSetupCheckFacebook' => 'PhabricatorSetupCheck', 'PhabricatorSetupCheckGD' => 'PhabricatorSetupCheck', + 'PhabricatorSetupCheckImagemagick' => 'PhabricatorSetupCheck', 'PhabricatorSetupCheckInvalidConfig' => 'PhabricatorSetupCheck', 'PhabricatorSetupCheckMail' => 'PhabricatorSetupCheck', 'PhabricatorSetupCheckMySQL' => 'PhabricatorSetupCheck', diff --git a/src/applications/config/check/PhabricatorSetupCheckImagemagick.php b/src/applications/config/check/PhabricatorSetupCheckImagemagick.php new file mode 100644 index 0000000000..efcd65fb35 --- /dev/null +++ b/src/applications/config/check/PhabricatorSetupCheckImagemagick.php @@ -0,0 +1,25 @@ +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'); + } + } + } +} + diff --git a/src/applications/config/option/PhabricatorCoreConfigOptions.php b/src/applications/config/option/PhabricatorCoreConfigOptions.php index 6dadb5c816..ebcf6401c9 100644 --- a/src/applications/config/option/PhabricatorCoreConfigOptions.php +++ b/src/applications/config/option/PhabricatorCoreConfigOptions.php @@ -133,7 +133,7 @@ final class PhabricatorCoreConfigOptions ->setDescription( pht('Array containing list of Uninstalled applications.') ), - ); + ); } protected function didValidateOption( diff --git a/src/applications/files/PhabricatorImageTransformer.php b/src/applications/files/PhabricatorImageTransformer.php index 8e651eba69..49991a9da4 100644 --- a/src/applications/files/PhabricatorImageTransformer.php +++ b/src/applications/files/PhabricatorImageTransformer.php @@ -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; + } + + } + } diff --git a/src/applications/files/config/PhabricatorFilesConfigOptions.php b/src/applications/files/config/PhabricatorFilesConfigOptions.php index b960cd6ee5..45b7512597 100644 --- a/src/applications/files/config/PhabricatorFilesConfigOptions.php +++ b/src/applications/files/config/PhabricatorFilesConfigOptions.php @@ -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")), + ); } From 51dfeb795004b9fc405c1c9478a732a2418acb04 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Fri, 8 Feb 2013 09:54:27 -0800 Subject: [PATCH 11/13] pht for phriction Summary: Scan all phriction app files for text to pht Test Plan: Use phriction in ALL CAPS, seems reasonably usable. Reviewers: epriestley, btrahan Reviewed By: epriestley CC: aran, Korvin Differential Revision: https://secure.phabricator.com/D4862 --- .../PhabricatorApplicationPhriction.php | 2 +- .../controller/PhrictionController.php | 4 +- .../controller/PhrictionDeleteController.php | 8 ++-- .../controller/PhrictionDiffController.php | 24 +++++------ .../PhrictionDocumentController.php | 28 +++++++------ .../controller/PhrictionEditController.php | 41 ++++++++++--------- .../controller/PhrictionHistoryController.php | 30 +++++++------- .../controller/PhrictionListController.php | 8 ++-- .../phriction/storage/PhrictionContent.php | 2 +- 9 files changed, 75 insertions(+), 72 deletions(-) diff --git a/src/applications/phriction/application/PhabricatorApplicationPhriction.php b/src/applications/phriction/application/PhabricatorApplicationPhriction.php index f6119bff57..212b984ca5 100644 --- a/src/applications/phriction/application/PhabricatorApplicationPhriction.php +++ b/src/applications/phriction/application/PhabricatorApplicationPhriction.php @@ -3,7 +3,7 @@ final class PhabricatorApplicationPhriction extends PhabricatorApplication { public function getShortDescription() { - return 'Wiki'; + return pht('Wiki'); } public function getBaseURI() { diff --git a/src/applications/phriction/controller/PhrictionController.php b/src/applications/phriction/controller/PhrictionController.php index 0b7fa32ede..c242c4f64f 100644 --- a/src/applications/phriction/controller/PhrictionController.php +++ b/src/applications/phriction/controller/PhrictionController.php @@ -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')); diff --git a/src/applications/phriction/controller/PhrictionDeleteController.php b/src/applications/phriction/controller/PhrictionDeleteController.php index 13d43d25b8..16cb4a9edc 100644 --- a/src/applications/phriction/controller/PhrictionDeleteController.php +++ b/src/applications/phriction/controller/PhrictionDeleteController.php @@ -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); diff --git a/src/applications/phriction/controller/PhrictionDiffController.php b/src/applications/phriction/controller/PhrictionDiffController.php index ee03806fac..3701b7810f 100644 --- a/src/applications/phriction/controller/PhrictionDiffController.php +++ b/src/applications/phriction/controller/PhrictionDiffController.php @@ -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 '.phutil_escape_html($version).'...'); + pht('Revert to Version %s...', phutil_escape_html($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( diff --git a/src/applications/phriction/controller/PhrictionDocumentController.php b/src/applications/phriction/controller/PhrictionDocumentController.php index 97b328bd67..64f51f9845 100644 --- a/src/applications/phriction/controller/PhrictionDocumentController.php +++ b/src/applications/phriction/controller/PhrictionDocumentController.php @@ -60,15 +60,15 @@ final class PhrictionDocumentController 'href' => $create_uri, 'class' => 'green button', ), - 'Create Page'); + pht('Create Page')); $page_content = '
'. - 'No content here!
'. - 'No document found at '.phutil_escape_html($slug).'. '. - $create_sentence. + ''.pht('No content here!').'
'. + pht('No document found at %s.', phutil_escape_html($slug)). + ' '.$create_sentence. '
'; - $page_title = 'Page Not Found'; + $page_title = pht('Page Not Found'); $buttons = $button; } else { $version = $request->getInt('v'); @@ -82,13 +82,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()); @@ -154,8 +154,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}'!"); @@ -338,20 +338,22 @@ final class PhrictionDocumentController } } if ($more_children) { - $list[] = '
  • More...
  • '; + $list[] = '
  • '.pht('More...').'
  • '; } $list[] = ''; $list = implode("\n", $list); return '
    '. - '
    Document Hierarchy
    '. + '
    '. + pht('Document Hierarchy'). + '
    '. $list. '
    '; } private function renderChildDocumentLink(array $info) { - $title = nonempty($info['title'], '(Untitled Document)'); + $title = nonempty($info['title'], pht('(Untitled Document)')); $item = phutil_render_tag( 'a', array( diff --git a/src/applications/phriction/controller/PhrictionEditController.php b/src/applications/phriction/controller/PhrictionEditController.php index f701839262..08243f4f7a 100644 --- a/src/applications/phriction/controller/PhrictionEditController.php +++ b/src/applications/phriction/controller/PhrictionEditController.php @@ -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( - '

    You did not make any changes to the document.

    '); + '

    '.pht('You did not make any changes to the document.').'

    '); $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( - '

    You can not create an empty document.

    '); + '

    '.pht('You can not create an empty document.').'

    '); $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,13 +178,14 @@ 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); $draft_note->setTitle('Recovered Draft'); $draft_note->appendChild( - '

    Showing a saved draft of your edits, you can '.$discard.'.

    '); + '

    '.pht('Showing a saved draft of your edits, you can %s.', + $discard).'

    '); } else { $content_text = $content->getContent(); $draft_note = null; @@ -198,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') @@ -216,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')) @@ -233,11 +234,11 @@ final class PhrictionEditController $preview_panel = '
    - Document Preview + '.pht('Document Preview').'
    - Loading preview... + '.pht('Loading preview...').'
    '; @@ -258,7 +259,7 @@ final class PhrictionEditController $preview_panel, ), array( - 'title' => 'Edit Document', + 'title' => pht('Edit Document'), )); } diff --git a/src/applications/phriction/controller/PhrictionHistoryController.php b/src/applications/phriction/controller/PhrictionHistoryController.php index e6bb0a9aa1..c822c5e120 100644 --- a/src/applications/phriction/controller/PhrictionHistoryController.php +++ b/src/applications/phriction/controller/PhrictionHistoryController.php @@ -49,7 +49,7 @@ final class PhrictionHistoryController $diff_uri = new PhutilURI('/phriction/diff/'.$document->getID().'/'); - $vs_previous = 'Created'; + $vs_previous = ''.pht('Created').''; 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 = 'Current'; + $vs_head = ''.pht('Current').''; 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,7 @@ 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); @@ -143,7 +143,7 @@ final class PhrictionHistoryController $panel, ), array( - 'title' => 'Document History', + 'title' => pht('Document History'), 'device' => true, )); diff --git a/src/applications/phriction/controller/PhrictionListController.php b/src/applications/phriction/controller/PhrictionListController.php index 269a70288c..c4b8968609 100644 --- a/src/applications/phriction/controller/PhrictionListController.php +++ b/src/applications/phriction/controller/PhrictionListController.php @@ -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( diff --git a/src/applications/phriction/storage/PhrictionContent.php b/src/applications/phriction/storage/PhrictionContent.php index 0307455b7f..6c13c55fb7 100644 --- a/src/applications/phriction/storage/PhrictionContent.php +++ b/src/applications/phriction/storage/PhrictionContent.php @@ -78,7 +78,7 @@ final class PhrictionContent extends PhrictionDAO $toc = '
    '. '
    '. - 'Table of Contents'. + pht('Table of Contents'). '
    '. $toc. '
    '; From 6e5d8d45770e524de6093c5e5279a11c0d1c6ee7 Mon Sep 17 00:00:00 2001 From: epriestley Date: Fri, 8 Feb 2013 10:48:23 -0800 Subject: [PATCH 12/13] Fix documentation to require "sudo" for bin/aphlict Summary: This script must run as root because it requires a privileged port to enable the flash cross-domain stuff. We give you a useful error message if you don't run it as root, but can be more clear in the documentation. Test Plan: Read file Reviewers: Afaque_Hussain, btrahan Reviewed By: Afaque_Hussain CC: aran Differential Revision: https://secure.phabricator.com/D4867 --- src/docs/userguide/notifications.diviner | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/docs/userguide/notifications.diviner b/src/docs/userguide/notifications.diviner index b12fb421ad..218ef11170 100644 --- a/src/docs/userguide/notifications.diviner +++ b/src/docs/userguide/notifications.diviner @@ -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 From 51947ac332b02ba8259359b62609bfd2a1c7b415 Mon Sep 17 00:00:00 2001 From: epriestley Date: Fri, 8 Feb 2013 10:48:30 -0800 Subject: [PATCH 13/13] Make diviner documentation generation book-oriented Summary: I want to allow a single project to generate multiple "books" of documentation, so we can separate user-facing documentation from technical documentation and such. Generalize the ".divinerconfig" file into a "diviner book" configuration file. Since only the "generate" workflow actually reads any of this stuff, move it all down into the generate workflow. Also, namespace the cache. Test Plan: Ran `bin/diviner generate --book src/docs/user.book`, saw appropriate output. Verified cache generated in a namespace in `.divinercache/`. Reviewers: btrahan, indiefan Reviewed By: btrahan CC: aran Maniphest Tasks: T988 Differential Revision: https://secure.phabricator.com/D4857 --- .../workflow/DivinerGenerateWorkflow.php | 74 ++++++++++++++++++- .../diviner/workflow/DivinerWorkflow.php | 24 ------ src/docs/book/user.book | 4 + 3 files changed, 75 insertions(+), 27 deletions(-) create mode 100644 src/docs/book/user.book diff --git a/src/applications/diviner/workflow/DivinerGenerateWorkflow.php b/src/applications/diviner/workflow/DivinerGenerateWorkflow.php index d2b88321c5..8b75f45145 100644 --- a/src/applications/diviner/workflow/DivinerGenerateWorkflow.php +++ b/src/applications/diviner/workflow/DivinerGenerateWorkflow.php @@ -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; + } } diff --git a/src/applications/diviner/workflow/DivinerWorkflow.php b/src/applications/diviner/workflow/DivinerWorkflow.php index 81d9156957..07d09be03b 100644 --- a/src/applications/diviner/workflow/DivinerWorkflow.php +++ b/src/applications/diviner/workflow/DivinerWorkflow.php @@ -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"); - } - } diff --git a/src/docs/book/user.book b/src/docs/book/user.book new file mode 100644 index 0000000000..4f16cdbed4 --- /dev/null +++ b/src/docs/book/user.book @@ -0,0 +1,4 @@ +{ + "name" : "phabricator", + "root" : "../../../" +}