From d6bce34a5db1a838a988440f09f7728747c9e067 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Wed, 26 Apr 2017 10:48:50 -0700 Subject: [PATCH 01/25] Update Conpherence to use EditEngine Summary: Moves Conpherence to use EditEngine. This removes the "First Message" field, but I think that's ok until we have direct messaging of some sort, then maybe have built-ins cover that case. Test Plan: - Visit /new/ and /edit/ for creating new rooms. - Edit a room in full conpherence - Edit a room in durable column - grep for METADATA calls Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Maniphest Tasks: T11729 Differential Revision: https://secure.phabricator.com/D16677 --- resources/celerity/map.php | 26 ++-- src/__phutil_library_map__.php | 6 +- .../PhabricatorConpherenceApplication.php | 6 +- .../constants/ConpherenceUpdateActions.php | 1 - .../controller/ConpherenceController.php | 3 +- .../ConpherenceNewRoomController.php | 117 ----------------- .../ConpherenceRoomEditController.php | 11 ++ .../ConpherenceUpdateController.php | 102 +-------------- .../editor/ConpherenceEditEngine.php | 118 ++++++++++++++++++ .../view/ConpherenceDurableColumnView.php | 4 +- .../view/ConpherenceThreadListView.php | 2 +- .../conpherence/behavior-durable-column.js | 2 +- 12 files changed, 157 insertions(+), 241 deletions(-) delete mode 100644 src/applications/conpherence/controller/ConpherenceNewRoomController.php create mode 100644 src/applications/conpherence/controller/ConpherenceRoomEditController.php create mode 100644 src/applications/conpherence/editor/ConpherenceEditEngine.php diff --git a/resources/celerity/map.php b/resources/celerity/map.php index 8c426f8b7f..3e09edfc4e 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -10,7 +10,7 @@ return array( 'conpherence.pkg.css' => 'ff161f2d', 'conpherence.pkg.js' => 'b5b51108', 'core.pkg.css' => '84ce260a', - 'core.pkg.js' => 'fffe0122', + 'core.pkg.js' => '2ff7879f', 'darkconsole.pkg.js' => '1f9a31bc', 'differential.pkg.css' => '90b30783', 'differential.pkg.js' => 'ddfeb49b', @@ -378,7 +378,7 @@ return array( 'rsrc/js/application/config/behavior-reorder-fields.js' => 'b6993408', 'rsrc/js/application/conpherence/ConpherenceThreadManager.js' => '4d863052', 'rsrc/js/application/conpherence/behavior-conpherence-search.js' => '9bbf3762', - 'rsrc/js/application/conpherence/behavior-durable-column.js' => 'aa3bd034', + 'rsrc/js/application/conpherence/behavior-durable-column.js' => '2ae077e1', 'rsrc/js/application/conpherence/behavior-menu.js' => 'c9b99b77', 'rsrc/js/application/conpherence/behavior-participant-pane.js' => '8604caa8', 'rsrc/js/application/conpherence/behavior-pontificate.js' => '55616e04', @@ -639,7 +639,7 @@ return array( 'javelin-behavior-diffusion-pull-lastmodified' => 'f01586dc', 'javelin-behavior-doorkeeper-tag' => 'e5822781', 'javelin-behavior-drydock-live-operation-status' => '901935ef', - 'javelin-behavior-durable-column' => 'aa3bd034', + 'javelin-behavior-durable-column' => '2ae077e1', 'javelin-behavior-editengine-reorder-configs' => 'd7a74243', 'javelin-behavior-editengine-reorder-fields' => 'b59e1e96', 'javelin-behavior-error-log' => '6882e80a', @@ -1095,6 +1095,16 @@ return array( 'javelin-install', 'javelin-util', ), + '2ae077e1' => array( + 'javelin-behavior', + 'javelin-dom', + 'javelin-stratcom', + 'javelin-behavior-device', + 'javelin-scrollbar', + 'javelin-quicksand', + 'phabricator-keyboard-shortcut', + 'conpherence-thread-manager', + ), '2b8de964' => array( 'javelin-install', 'javelin-util', @@ -1793,16 +1803,6 @@ return array( 'javelin-util', 'phabricator-prefab', ), - 'aa3bd034' => array( - 'javelin-behavior', - 'javelin-dom', - 'javelin-stratcom', - 'javelin-behavior-device', - 'javelin-scrollbar', - 'javelin-quicksand', - 'phabricator-keyboard-shortcut', - 'conpherence-thread-manager', - ), 'ab2f381b' => array( 'javelin-request', 'javelin-behavior', diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 4d6ef65368..ca24aedf75 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -292,13 +292,13 @@ phutil_register_library_map(array( 'ConpherenceCreateThreadConduitAPIMethod' => 'applications/conpherence/conduit/ConpherenceCreateThreadConduitAPIMethod.php', 'ConpherenceDAO' => 'applications/conpherence/storage/ConpherenceDAO.php', 'ConpherenceDurableColumnView' => 'applications/conpherence/view/ConpherenceDurableColumnView.php', + 'ConpherenceEditEngine' => 'applications/conpherence/editor/ConpherenceEditEngine.php', 'ConpherenceEditor' => 'applications/conpherence/editor/ConpherenceEditor.php', 'ConpherenceFulltextQuery' => 'applications/conpherence/query/ConpherenceFulltextQuery.php', 'ConpherenceIndex' => 'applications/conpherence/storage/ConpherenceIndex.php', 'ConpherenceLayoutView' => 'applications/conpherence/view/ConpherenceLayoutView.php', 'ConpherenceListController' => 'applications/conpherence/controller/ConpherenceListController.php', 'ConpherenceMenuItemView' => 'applications/conpherence/view/ConpherenceMenuItemView.php', - 'ConpherenceNewRoomController' => 'applications/conpherence/controller/ConpherenceNewRoomController.php', 'ConpherenceNotificationPanelController' => 'applications/conpherence/controller/ConpherenceNotificationPanelController.php', 'ConpherenceParticipant' => 'applications/conpherence/storage/ConpherenceParticipant.php', 'ConpherenceParticipantController' => 'applications/conpherence/controller/ConpherenceParticipantController.php', @@ -308,6 +308,7 @@ phutil_register_library_map(array( 'ConpherenceQueryThreadConduitAPIMethod' => 'applications/conpherence/conduit/ConpherenceQueryThreadConduitAPIMethod.php', 'ConpherenceQueryTransactionConduitAPIMethod' => 'applications/conpherence/conduit/ConpherenceQueryTransactionConduitAPIMethod.php', 'ConpherenceReplyHandler' => 'applications/conpherence/mail/ConpherenceReplyHandler.php', + 'ConpherenceRoomEditController' => 'applications/conpherence/controller/ConpherenceRoomEditController.php', 'ConpherenceRoomListController' => 'applications/conpherence/controller/ConpherenceRoomListController.php', 'ConpherenceRoomPictureController' => 'applications/conpherence/controller/ConpherenceRoomPictureController.php', 'ConpherenceRoomPreferencesController' => 'applications/conpherence/controller/ConpherenceRoomPreferencesController.php', @@ -5074,13 +5075,13 @@ phutil_register_library_map(array( 'ConpherenceCreateThreadConduitAPIMethod' => 'ConpherenceConduitAPIMethod', 'ConpherenceDAO' => 'PhabricatorLiskDAO', 'ConpherenceDurableColumnView' => 'AphrontTagView', + 'ConpherenceEditEngine' => 'PhabricatorEditEngine', 'ConpherenceEditor' => 'PhabricatorApplicationTransactionEditor', 'ConpherenceFulltextQuery' => 'PhabricatorOffsetPagedQuery', 'ConpherenceIndex' => 'ConpherenceDAO', 'ConpherenceLayoutView' => 'AphrontTagView', 'ConpherenceListController' => 'ConpherenceController', 'ConpherenceMenuItemView' => 'AphrontTagView', - 'ConpherenceNewRoomController' => 'ConpherenceController', 'ConpherenceNotificationPanelController' => 'ConpherenceController', 'ConpherenceParticipant' => 'ConpherenceDAO', 'ConpherenceParticipantController' => 'ConpherenceController', @@ -5090,6 +5091,7 @@ phutil_register_library_map(array( 'ConpherenceQueryThreadConduitAPIMethod' => 'ConpherenceConduitAPIMethod', 'ConpherenceQueryTransactionConduitAPIMethod' => 'ConpherenceConduitAPIMethod', 'ConpherenceReplyHandler' => 'PhabricatorMailReplyHandler', + 'ConpherenceRoomEditController' => 'ConpherenceController', 'ConpherenceRoomListController' => 'ConpherenceController', 'ConpherenceRoomPictureController' => 'ConpherenceController', 'ConpherenceRoomPreferencesController' => 'ConpherenceController', diff --git a/src/applications/conpherence/application/PhabricatorConpherenceApplication.php b/src/applications/conpherence/application/PhabricatorConpherenceApplication.php index e969b48447..a0c21bd33a 100644 --- a/src/applications/conpherence/application/PhabricatorConpherenceApplication.php +++ b/src/applications/conpherence/application/PhabricatorConpherenceApplication.php @@ -45,8 +45,10 @@ final class PhabricatorConpherenceApplication extends PhabricatorApplication { => 'ConpherenceViewController', 'columnview/' => 'ConpherenceColumnViewController', - 'new/' - => 'ConpherenceNewRoomController', + $this->getEditRoutePattern('new/') + => 'ConpherenceRoomEditController', + $this->getEditRoutePattern('edit/') + => 'ConpherenceRoomEditController', 'picture/(?P[1-9]\d*)/' => 'ConpherenceRoomPictureController', 'search/(?:query/(?P[^/]+)/)?' diff --git a/src/applications/conpherence/constants/ConpherenceUpdateActions.php b/src/applications/conpherence/constants/ConpherenceUpdateActions.php index a2b97f9c6a..afec800de3 100644 --- a/src/applications/conpherence/constants/ConpherenceUpdateActions.php +++ b/src/applications/conpherence/constants/ConpherenceUpdateActions.php @@ -2,7 +2,6 @@ final class ConpherenceUpdateActions extends ConpherenceConstants { - const METADATA = 'metadata'; const MESSAGE = 'message'; const DRAFT = 'draft'; const JOIN_ROOM = 'join_room'; diff --git a/src/applications/conpherence/controller/ConpherenceController.php b/src/applications/conpherence/controller/ConpherenceController.php index f7fd7ef1b4..90328cca04 100644 --- a/src/applications/conpherence/controller/ConpherenceController.php +++ b/src/applications/conpherence/controller/ConpherenceController.php @@ -91,7 +91,8 @@ abstract class ConpherenceController extends PhabricatorController { $header->addActionItem( id(new PHUIIconCircleView()) - ->setHref($this->getApplicationURI("update/{$id}/")) + ->setHref( + $this->getApplicationURI('edit/'.$conpherence->getID()).'/') ->setIcon('fa-pencil') ->addClass('hide-on-device') ->setColor('violet') diff --git a/src/applications/conpherence/controller/ConpherenceNewRoomController.php b/src/applications/conpherence/controller/ConpherenceNewRoomController.php deleted file mode 100644 index 6cbe86aaa2..0000000000 --- a/src/applications/conpherence/controller/ConpherenceNewRoomController.php +++ /dev/null @@ -1,117 +0,0 @@ -getUser(); - - $title = pht('New Room'); - $e_title = true; - $validation_exception = null; - - $conpherence = ConpherenceThread::initializeNewRoom($user); - $participants = array(); - if ($request->isFormPost()) { - $editor = new ConpherenceEditor(); - $xactions = array(); - - $xactions[] = id(new ConpherenceTransaction()) - ->setTransactionType(ConpherenceThreadTitleTransaction::TRANSACTIONTYPE) - ->setNewValue($request->getStr('title')); - - $participants = $request->getArr('participants'); - $participants[] = $user->getPHID(); - $participants = array_unique($participants); - $xactions[] = id(new ConpherenceTransaction()) - ->setTransactionType( - ConpherenceThreadParticipantsTransaction::TRANSACTIONTYPE) - ->setNewValue(array('+' => $participants)); - $xactions[] = id(new ConpherenceTransaction()) - ->setTransactionType(ConpherenceThreadTopicTransaction::TRANSACTIONTYPE) - ->setNewValue($request->getStr('topic')); - $xactions[] = id(new ConpherenceTransaction()) - ->setTransactionType(PhabricatorTransactions::TYPE_VIEW_POLICY) - ->setNewValue($request->getStr('viewPolicy')); - $xactions[] = id(new ConpherenceTransaction()) - ->setTransactionType(PhabricatorTransactions::TYPE_EDIT_POLICY) - ->setNewValue($request->getStr('editPolicy')); - - try { - $editor - ->setContentSourceFromRequest($request) - ->setContinueOnNoEffect(true) - ->setActor($user) - ->applyTransactions($conpherence, $xactions); - - return id(new AphrontRedirectResponse()) - ->setURI('/'.$conpherence->getMonogram()); - } catch (PhabricatorApplicationTransactionValidationException $ex) { - $validation_exception = $ex; - - $e_title = $ex->getShortMessage( - ConpherenceThreadTitleTransaction::TRANSACTIONTYPE); - - $conpherence->setViewPolicy($request->getStr('viewPolicy')); - $conpherence->setEditPolicy($request->getStr('editPolicy')); - } - } else { - if ($request->getStr('participant')) { - $participants[] = $request->getStr('participant'); - } - } - - $policies = id(new PhabricatorPolicyQuery()) - ->setViewer($user) - ->setObject($conpherence) - ->execute(); - - $submit_uri = $this->getApplicationURI('new/'); - $cancel_uri = $this->getApplicationURI('search/'); - - $dialog = $this->newDialog() - ->setWidth(AphrontDialogView::WIDTH_FORM) - ->setValidationException($validation_exception) - ->setUser($user) - ->setTitle($title) - ->addCancelButton($cancel_uri) - ->addSubmitButton(pht('Create Room')); - - $form = id(new PHUIFormLayoutView()) - ->setUser($user) - ->appendChild( - id(new AphrontFormTextControl()) - ->setError($e_title) - ->setLabel(pht('Name')) - ->setName('title') - ->setValue($request->getStr('title'))) - ->appendChild( - id(new AphrontFormTextControl()) - ->setLabel(pht('Topic')) - ->setName('topic') - ->setValue($request->getStr('topic'))) - ->appendChild( - id(new AphrontFormTokenizerControl()) - ->setName('participants') - ->setUser($user) - ->setDatasource(new PhabricatorPeopleDatasource()) - ->setValue($participants) - ->setLabel(pht('Other Participants'))) - ->appendChild( - id(new AphrontFormPolicyControl()) - ->setName('viewPolicy') - ->setPolicyObject($conpherence) - ->setCapability(PhabricatorPolicyCapability::CAN_VIEW) - ->setPolicies($policies)) - ->appendChild( - id(new AphrontFormPolicyControl()) - ->setName('editPolicy') - ->setPolicyObject($conpherence) - ->setCapability(PhabricatorPolicyCapability::CAN_EDIT) - ->setPolicies($policies)); - - $dialog->appendChild($form); - - return id(new AphrontDialogResponse())->setDialog($dialog); - } - -} diff --git a/src/applications/conpherence/controller/ConpherenceRoomEditController.php b/src/applications/conpherence/controller/ConpherenceRoomEditController.php new file mode 100644 index 0000000000..56f808056c --- /dev/null +++ b/src/applications/conpherence/controller/ConpherenceRoomEditController.php @@ -0,0 +1,11 @@ +setController($this) + ->buildResponse(); + } +} diff --git a/src/applications/conpherence/controller/ConpherenceUpdateController.php b/src/applications/conpherence/controller/ConpherenceUpdateController.php index 728d917589..a814c64452 100644 --- a/src/applications/conpherence/controller/ConpherenceUpdateController.php +++ b/src/applications/conpherence/controller/ConpherenceUpdateController.php @@ -12,7 +12,7 @@ final class ConpherenceUpdateController $need_participants = false; $needed_capabilities = array(PhabricatorPolicyCapability::CAN_VIEW); - $action = $request->getStr('action', ConpherenceUpdateActions::METADATA); + $action = $request->getStr('action'); switch ($action) { case ConpherenceUpdateActions::REMOVE_PERSON: $person_phid = $request->getStr('remove_person'); @@ -21,7 +21,6 @@ final class ConpherenceUpdateController } break; case ConpherenceUpdateActions::ADD_PERSON: - case ConpherenceUpdateActions::METADATA: $needed_capabilities[] = PhabricatorPolicyCapability::CAN_EDIT; break; case ConpherenceUpdateActions::LOAD: @@ -110,35 +109,6 @@ final class ConpherenceUpdateController $response_mode = 'go-home'; } break; - case ConpherenceUpdateActions::METADATA: - $title = $request->getStr('title'); - $topic = $request->getStr('topic'); - - // all other metadata updates are continue requests - if (!$request->isContinueRequest()) { - break; - } - - $title = $request->getStr('title'); - $topic = $request->getStr('topic'); - $xactions[] = id(new ConpherenceTransaction()) - ->setTransactionType( - ConpherenceThreadTitleTransaction::TRANSACTIONTYPE) - ->setNewValue($title); - $xactions[] = id(new ConpherenceTransaction()) - ->setTransactionType( - ConpherenceThreadTopicTransaction::TRANSACTIONTYPE) - ->setNewValue($topic); - $xactions[] = id(new ConpherenceTransaction()) - ->setTransactionType(PhabricatorTransactions::TYPE_VIEW_POLICY) - ->setNewValue($request->getStr('viewPolicy')); - $xactions[] = id(new ConpherenceTransaction()) - ->setTransactionType(PhabricatorTransactions::TYPE_EDIT_POLICY) - ->setNewValue($request->getStr('editPolicy')); - if (!$request->getExists('force_ajax')) { - $response_mode = 'redirect'; - } - break; case ConpherenceUpdateActions::LOAD: $updated = false; $response_mode = 'ajax'; @@ -208,10 +178,6 @@ final class ConpherenceUpdateController case ConpherenceUpdateActions::REMOVE_PERSON: $dialog = $this->renderRemovePersonDialog($conpherence); break; - case ConpherenceUpdateActions::METADATA: - default: - $dialog = $this->renderMetadataDialog($conpherence, $error_view); - break; } return @@ -332,62 +298,6 @@ final class ConpherenceUpdateController return $dialog; } - private function renderMetadataDialog( - ConpherenceThread $conpherence, - $error_view) { - - $request = $this->getRequest(); - $user = $request->getUser(); - - $title = pht('Update Room'); - $form = id(new PHUIFormLayoutView()) - ->appendChild($error_view) - ->appendChild( - id(new AphrontFormTextControl()) - ->setLabel(pht('Title')) - ->setName('title') - ->setValue($conpherence->getTitle())) - ->appendChild( - id(new AphrontFormTextControl()) - ->setLabel(pht('Topic')) - ->setName('topic') - ->setValue($conpherence->getTopic())); - - $policies = id(new PhabricatorPolicyQuery()) - ->setViewer($user) - ->setObject($conpherence) - ->execute(); - - $form - ->appendChild( - id(new AphrontFormPolicyControl()) - ->setName('viewPolicy') - ->setPolicyObject($conpherence) - ->setCapability(PhabricatorPolicyCapability::CAN_VIEW) - ->setPolicies($policies)) - ->appendChild( - id(new AphrontFormPolicyControl()) - ->setName('editPolicy') - ->setPolicyObject($conpherence) - ->setCapability(PhabricatorPolicyCapability::CAN_EDIT) - ->setPolicies($policies)); - - $view = id(new AphrontDialogView()) - ->setTitle($title) - ->addHiddenInput('action', 'metadata') - ->addHiddenInput( - 'latest_transaction_id', - $request->getInt('latest_transaction_id')) - ->addHiddenInput('__continue__', true) - ->appendChild($form); - - if ($request->getExists('force_ajax')) { - $view->addHiddenInput('force_ajax', true); - } - - return $view; - } - private function loadAndRenderUpdates( $action, $conpherence_id, @@ -395,7 +305,6 @@ final class ConpherenceUpdateController $need_transactions = false; switch ($action) { - case ConpherenceUpdateActions::METADATA: case ConpherenceUpdateActions::LOAD: $need_transactions = true; break; @@ -444,15 +353,6 @@ final class ConpherenceUpdateController $header = null; $people_widget = null; switch ($action) { - case ConpherenceUpdateActions::METADATA: - $header = $this->buildHeaderPaneContent($conpherence); - $header = hsprintf('%s', $header); - $nav_item = id(new ConpherenceThreadListView()) - ->setUser($user) - ->setBaseURI($this->getApplicationURI()) - ->renderThreadItem($conpherence); - $nav_item = hsprintf('%s', $nav_item); - break; case ConpherenceUpdateActions::ADD_PERSON: $people_widget = id(new ConpherenceParticipantView()) ->setUser($user) diff --git a/src/applications/conpherence/editor/ConpherenceEditEngine.php b/src/applications/conpherence/editor/ConpherenceEditEngine.php new file mode 100644 index 0000000000..91cd8fd081 --- /dev/null +++ b/src/applications/conpherence/editor/ConpherenceEditEngine.php @@ -0,0 +1,118 @@ +getViewer()); + } + + protected function newObjectQuery() { + return new ConpherenceThreadQuery(); + } + + protected function getObjectCreateTitleText($object) { + return pht('Create New Room'); + } + + protected function getObjectEditTitleText($object) { + return pht('Edit Room: %s', $object->getTitle()); + } + + protected function getObjectEditShortText($object) { + return $object->getTitle(); + } + + protected function getObjectCreateShortText() { + return pht('Create Room'); + } + + protected function getObjectName() { + return pht('Room'); + } + + protected function getObjectCreateCancelURI($object) { + return $this->getApplication()->getApplicationURI('/'); + } + + protected function getEditorURI() { + return $this->getApplication()->getApplicationURI('edit/'); + } + + protected function getObjectViewURI($object) { + return $object->getURI(); + } + + public function isEngineConfigurable() { + return false; + } + + protected function buildCustomEditFields($object) { + $viewer = $this->getViewer(); + + if ($this->getIsCreate()) { + $participant_phids = array($viewer->getPHID()); + $initial_phids = array(); + } else { + $participant_phids = $object->getParticipantPHIDs(); + $initial_phids = $participant_phids; + } + + // Only show participants on create or conduit, not edit + $conduit_only = !$this->getIsCreate(); + + return array( + id(new PhabricatorTextEditField()) + ->setKey('name') + ->setLabel(pht('Name')) + ->setDescription(pht('Room name.')) + ->setConduitTypeDescription(pht('New Room name.')) + ->setIsRequired(true) + ->setTransactionType( + ConpherenceThreadTitleTransaction::TRANSACTIONTYPE) + ->setValue($object->getTitle()), + + id(new PhabricatorTextEditField()) + ->setKey('topic') + ->setLabel(pht('Topic')) + ->setDescription(pht('Room topic.')) + ->setConduitTypeDescription(pht('New Room topic.')) + ->setTransactionType( + ConpherenceThreadTopicTransaction::TRANSACTIONTYPE) + ->setValue($object->getTopic()), + + id(new PhabricatorUsersEditField()) + ->setKey('participants') + ->setValue($participant_phids) + ->setInitialValue($initial_phids) + ->setIsConduitOnly($conduit_only) + ->setAliases(array('users', 'members', 'participants', 'userPHID')) + ->setDescription(pht('Room participants.')) + ->setUseEdgeTransactions(true) + ->setConduitTypeDescription(pht('New Room participants.')) + ->setTransactionType( + ConpherenceThreadParticipantsTransaction::TRANSACTIONTYPE) + ->setLabel(pht('Initial Participants')), + + ); + } + +} diff --git a/src/applications/conpherence/view/ConpherenceDurableColumnView.php b/src/applications/conpherence/view/ConpherenceDurableColumnView.php index e3240bc2e4..5d6a5eaaec 100644 --- a/src/applications/conpherence/view/ConpherenceDurableColumnView.php +++ b/src/applications/conpherence/view/ConpherenceDurableColumnView.php @@ -363,9 +363,9 @@ final class ConpherenceDurableColumnView extends AphrontTagView { $actions[] = array( 'name' => pht('Edit Room'), 'disabled' => !$can_edit, - 'href' => '/conpherence/update/'.$conpherence->getID().'/?nopic', + 'href' => '/conpherence/edit/'.$conpherence->getID().'/', 'icon' => 'fa-pencil', - 'key' => ConpherenceUpdateActions::METADATA, + 'key' => 'go_edit', ); $actions[] = array( 'name' => pht('View in Conpherence'), diff --git a/src/applications/conpherence/view/ConpherenceThreadListView.php b/src/applications/conpherence/view/ConpherenceThreadListView.php index af15f82a6e..42f1b605c1 100644 --- a/src/applications/conpherence/view/ConpherenceThreadListView.php +++ b/src/applications/conpherence/view/ConpherenceThreadListView.php @@ -117,7 +117,7 @@ final class ConpherenceThreadListView extends AphrontView { $new_icon = id(new PHUIIconView()) ->setIcon('fa-plus-square') ->addSigil('has-tooltip') - ->setHref('/conpherence/new/') + ->setHref('/conpherence/edit/') ->setWorkflow(true) ->setMetaData(array( 'tip' => pht('New Room'), diff --git a/webroot/rsrc/js/application/conpherence/behavior-durable-column.js b/webroot/rsrc/js/application/conpherence/behavior-durable-column.js index c6c82bc3be..a521046d8e 100644 --- a/webroot/rsrc/js/application/conpherence/behavior-durable-column.js +++ b/webroot/rsrc/js/application/conpherence/behavior-durable-column.js @@ -177,7 +177,7 @@ JX.behavior('durable-column', function(config, statics) { var params = null; switch (action) { - case 'metadata': + case 'go_edit': threadManager.runUpdateWorkflowFromLink( link, { From 608dd061510defdd5f2ab065e3034287d304acbd Mon Sep 17 00:00:00 2001 From: Chad Little Date: Sat, 29 Apr 2017 19:53:14 -0700 Subject: [PATCH 02/25] Add a lipsum generator for Conpherence Rooms Summary: Builds a basic room generator for Conpherence, picks a random name, adds 10 random users to it, sets view and edit policy to all users. Test Plan: `bin/lipsum generate conpherence` {F4928815} Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Differential Revision: https://secure.phabricator.com/D17699 --- src/__phutil_library_map__.php | 6 ++ .../ConpherenceEditConduitAPIMethod.php | 19 ++++ ...catorConpherenceRoomContextFreeGrammar.php | 97 +++++++++++++++++++ ...icatorConpherenceRoomTestDataGenerator.php | 76 +++++++++++++++ 4 files changed, 198 insertions(+) create mode 100644 src/applications/conpherence/conduit/ConpherenceEditConduitAPIMethod.php create mode 100644 src/applications/conpherence/lipsum/PhabricatorConpherenceRoomContextFreeGrammar.php create mode 100644 src/applications/conpherence/lipsum/PhabricatorConpherenceRoomTestDataGenerator.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index ca24aedf75..33618ca547 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -292,6 +292,7 @@ phutil_register_library_map(array( 'ConpherenceCreateThreadConduitAPIMethod' => 'applications/conpherence/conduit/ConpherenceCreateThreadConduitAPIMethod.php', 'ConpherenceDAO' => 'applications/conpherence/storage/ConpherenceDAO.php', 'ConpherenceDurableColumnView' => 'applications/conpherence/view/ConpherenceDurableColumnView.php', + 'ConpherenceEditConduitAPIMethod' => 'applications/conpherence/conduit/ConpherenceEditConduitAPIMethod.php', 'ConpherenceEditEngine' => 'applications/conpherence/editor/ConpherenceEditEngine.php', 'ConpherenceEditor' => 'applications/conpherence/editor/ConpherenceEditor.php', 'ConpherenceFulltextQuery' => 'applications/conpherence/query/ConpherenceFulltextQuery.php', @@ -2390,6 +2391,8 @@ phutil_register_library_map(array( 'PhabricatorConpherenceNotificationsSetting' => 'applications/settings/setting/PhabricatorConpherenceNotificationsSetting.php', 'PhabricatorConpherencePreferencesSettingsPanel' => 'applications/settings/panel/PhabricatorConpherencePreferencesSettingsPanel.php', 'PhabricatorConpherenceProfileMenuItem' => 'applications/search/menuitem/PhabricatorConpherenceProfileMenuItem.php', + 'PhabricatorConpherenceRoomContextFreeGrammar' => 'applications/conpherence/lipsum/PhabricatorConpherenceRoomContextFreeGrammar.php', + 'PhabricatorConpherenceRoomTestDataGenerator' => 'applications/conpherence/lipsum/PhabricatorConpherenceRoomTestDataGenerator.php', 'PhabricatorConpherenceSoundSetting' => 'applications/settings/setting/PhabricatorConpherenceSoundSetting.php', 'PhabricatorConpherenceThreadPHIDType' => 'applications/conpherence/phid/PhabricatorConpherenceThreadPHIDType.php', 'PhabricatorConpherenceWidgetVisibleSetting' => 'applications/settings/setting/PhabricatorConpherenceWidgetVisibleSetting.php', @@ -5075,6 +5078,7 @@ phutil_register_library_map(array( 'ConpherenceCreateThreadConduitAPIMethod' => 'ConpherenceConduitAPIMethod', 'ConpherenceDAO' => 'PhabricatorLiskDAO', 'ConpherenceDurableColumnView' => 'AphrontTagView', + 'ConpherenceEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod', 'ConpherenceEditEngine' => 'PhabricatorEditEngine', 'ConpherenceEditor' => 'PhabricatorApplicationTransactionEditor', 'ConpherenceFulltextQuery' => 'PhabricatorOffsetPagedQuery', @@ -7489,6 +7493,8 @@ phutil_register_library_map(array( 'PhabricatorConpherenceNotificationsSetting' => 'PhabricatorSelectSetting', 'PhabricatorConpherencePreferencesSettingsPanel' => 'PhabricatorEditEngineSettingsPanel', 'PhabricatorConpherenceProfileMenuItem' => 'PhabricatorProfileMenuItem', + 'PhabricatorConpherenceRoomContextFreeGrammar' => 'PhutilContextFreeGrammar', + 'PhabricatorConpherenceRoomTestDataGenerator' => 'PhabricatorTestDataGenerator', 'PhabricatorConpherenceSoundSetting' => 'PhabricatorSelectSetting', 'PhabricatorConpherenceThreadPHIDType' => 'PhabricatorPHIDType', 'PhabricatorConpherenceWidgetVisibleSetting' => 'PhabricatorInternalSetting', diff --git a/src/applications/conpherence/conduit/ConpherenceEditConduitAPIMethod.php b/src/applications/conpherence/conduit/ConpherenceEditConduitAPIMethod.php new file mode 100644 index 0000000000..9fc799c194 --- /dev/null +++ b/src/applications/conpherence/conduit/ConpherenceEditConduitAPIMethod.php @@ -0,0 +1,19 @@ + array( + '[dept]', + '[dept]', + '[dept]', + '[dept]', + '[dept]', + '[dept]', + '[dept]', + '[dept] ([city])', + '[dept] ([city])', + '[dept] - [city]', + '[dept] - [room]', + '[dept] / [room]', + '[dept] [room]', + '[city] ([dept]) - [room]', + '[dept] ([city]) - [room]', + '[dept] ([city]) [room]', + ), + 'dept' => array( + 'Eng', + 'Engineering', + 'User Interface', + 'Design', + 'Data Science', + 'Database', + 'Marketing', + 'Content', + 'Ads', + 'Operations', + 'Network Ops', + 'Ops', + 'Server Ops', + 'IT', + 'Information Technology', + 'i18n', + 'Internationalization', + 'Human Resources', + 'HR', + 'Research & Development', + 'R&D', + 'Management', + 'Directors', + 'Managers', + 'Support', + 'Customer Support', + 'Finance', + 'Sales', + 'Purchasing', + 'Education', + 'Hardware Engineering', + 'Software', + 'Supply Management', + 'Logistics', + 'Growth', + 'Content Strategy', + 'Developer Relations', + 'Accounting', + 'Production', + ), + 'city' => array( + 'Palo Alto', + 'Mtn View', + 'Cupertino', + 'Los Altos', + 'Menlo Park', + 'Santa Cruz', + 'S.F.', + 'San Francisco', + 'Seattle', + 'London', + 'New York', + 'Dublin', + 'Tokyo', + ), + 'room' => array( + 'General', + 'Announcements', + 'Staff', + 'Interns', + 'Managers', + 'Book Club', + 'Parking', + 'Sports', + 'Social', + 'Commuting', + 'For Sale', + 'Parents@', + ), + ); + } +} diff --git a/src/applications/conpherence/lipsum/PhabricatorConpherenceRoomTestDataGenerator.php b/src/applications/conpherence/lipsum/PhabricatorConpherenceRoomTestDataGenerator.php new file mode 100644 index 0000000000..8346df3313 --- /dev/null +++ b/src/applications/conpherence/lipsum/PhabricatorConpherenceRoomTestDataGenerator.php @@ -0,0 +1,76 @@ +loadRandomUser(); + + $name = $this->newRoomName(); + + $participants = array(); + $participants[] = $this->loadRandomUser(); + $participants[] = $this->loadRandomUser(); + $participants[] = $this->loadRandomUser(); + $participants[] = $this->loadRandomUser(); + $participants[] = $this->loadRandomUser(); + $participants[] = $this->loadRandomUser(); + $participants[] = $this->loadRandomUser(); + $participants[] = $this->loadRandomUser(); + $participants[] = $this->loadRandomUser(); + $participants[] = $this->loadRandomUser(); + + $rando_phids = array(); + $rando_phids[] = $author->getPHID(); + foreach ($participants as $actor) { + $rando_phids[] = $actor->getPHID(); + } + + $xactions = array(); + + $xactions[] = array( + 'type' => 'name', + 'value' => $name, + ); + + $xactions[] = array( + 'type' => 'participants.set', + 'value' => $rando_phids, + ); + + $xactions[] = array( + 'type' => 'view', + 'value' => 'users', + ); + + $xactions[] = array( + 'type' => 'edit', + 'value' => 'users', + ); + + $params = array( + 'transactions' => $xactions, + ); + + $result = id(new ConduitCall('conpherence.edit', $params)) + ->setUser($author) + ->execute(); + + return $result['object']['phid']; + } + + protected function newRoomName() { + $generator = new PhabricatorConpherenceRoomContextFreeGrammar(); + $name = $generator->generate(); + return $name; + } + + + +} From 89d0c8e388fbe0b27b6b73d9a5f201a883239d1c Mon Sep 17 00:00:00 2001 From: epriestley Date: Sun, 30 Apr 2017 12:57:24 -0700 Subject: [PATCH 03/25] Use grey dots for disabled users, even if a user is also unverified Summary: Fixes T12559. Test Plan: {F4929988} {F4929989} {F4929990} Reviewers: chad Reviewed By: chad Maniphest Tasks: T12559 Differential Revision: https://secure.phabricator.com/D17806 --- .../people/markup/PhabricatorMentionRemarkupRule.php | 4 +++- .../people/phid/PhabricatorPeopleUserPHIDType.php | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/applications/people/markup/PhabricatorMentionRemarkupRule.php b/src/applications/people/markup/PhabricatorMentionRemarkupRule.php index 1f82d78423..aa5b7f908e 100644 --- a/src/applications/people/markup/PhabricatorMentionRemarkupRule.php +++ b/src/applications/people/markup/PhabricatorMentionRemarkupRule.php @@ -150,7 +150,9 @@ final class PhabricatorMentionRemarkupRule extends PhutilRemarkupRule { $tag->addClass('phabricator-remarkup-mention-nopermission'); } - if (!$user->isResponsive()) { + if ($user->getIsDisabled()) { + $tag->setDotColor(PHUITagView::COLOR_GREY); + } else if (!$user->isResponsive()) { $tag->setDotColor(PHUITagView::COLOR_VIOLET); } else { if ($user->getAwayUntil()) { diff --git a/src/applications/people/phid/PhabricatorPeopleUserPHIDType.php b/src/applications/people/phid/PhabricatorPeopleUserPHIDType.php index b2a456cd51..f0512e91f1 100644 --- a/src/applications/people/phid/PhabricatorPeopleUserPHIDType.php +++ b/src/applications/people/phid/PhabricatorPeopleUserPHIDType.php @@ -61,7 +61,9 @@ final class PhabricatorPeopleUserPHIDType extends PhabricatorPHIDType { } $availability = null; - if (!$user->isResponsive()) { + if ($user->getIsDisabled()) { + $availability = PhabricatorObjectHandle::AVAILABILITY_DISABLED; + } else if (!$user->isResponsive()) { $availability = PhabricatorObjectHandle::AVAILABILITY_NOEMAIL; } else { $until = $user->getAwayUntil(); From b7c4f60e235d233d74a6341debf5172b5f4370d0 Mon Sep 17 00:00:00 2001 From: epriestley Date: Sun, 30 Apr 2017 12:44:59 -0700 Subject: [PATCH 04/25] Only recognize "Fixes ..." in main revision content like the Summary or Test Plan Summary: Fixes T12642. Currently, writing "Fixes T..." in a comment gets picked up as a formal "fixes". This is a bit confusing, and can also give you a "no effect" error if you "fixes ..." a task which is already "fixes"'d. We could make the duplicate action a non-error, but just prevent the text from having an effect instead, which seems cleaner. Test Plan: - Wrote "Fixes ..." in a summary, saw a "fixes" relationship established. - Wrote "Fixes ..." in a comment, got a "mention" instead. - `var_dump()`'d some stuff as a sanity check, looked reasonable. Reviewers: chad Reviewed By: chad Maniphest Tasks: T12642 Differential Revision: https://secure.phabricator.com/D17805 --- .../editor/DifferentialTransactionEditor.php | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/applications/differential/editor/DifferentialTransactionEditor.php b/src/applications/differential/editor/DifferentialTransactionEditor.php index 0086c101e2..9204a1aadb 100644 --- a/src/applications/differential/editor/DifferentialTransactionEditor.php +++ b/src/applications/differential/editor/DifferentialTransactionEditor.php @@ -1191,12 +1191,23 @@ final class DifferentialTransactionEditor array $changes, PhutilMarkupEngine $engine) { - $flat_blocks = mpull($changes, 'getNewValue'); - $huge_block = implode("\n\n", $flat_blocks); - + // For "Fixes ..." and "Depends on ...", we're only going to look at + // content blocks which are part of the revision itself (like "Summary" + // and "Test Plan"), not comments. + $content_parts = array(); + foreach ($changes as $change) { + if ($change->getTransaction()->isCommentTransaction()) { + continue; + } + $content_parts[] = $change->getNewValue(); + } + if (!$content_parts) { + return array(); + } + $content_block = implode("\n\n", $content_parts); $task_map = array(); $task_refs = id(new ManiphestCustomFieldStatusParser()) - ->parseCorpus($huge_block); + ->parseCorpus($content_block); foreach ($task_refs as $match) { foreach ($match['monograms'] as $monogram) { $task_id = (int)trim($monogram, 'tT'); @@ -1206,7 +1217,7 @@ final class DifferentialTransactionEditor $rev_map = array(); $rev_refs = id(new DifferentialCustomFieldDependsOnParser()) - ->parseCorpus($huge_block); + ->parseCorpus($content_block); foreach ($rev_refs as $match) { foreach ($match['monograms'] as $monogram) { $rev_id = (int)trim($monogram, 'dD'); From f2ca348b3a7a91a1f8bf8a061b592f9d60ec7dc9 Mon Sep 17 00:00:00 2001 From: Josh Cox Date: Wed, 5 Apr 2017 06:08:14 -0400 Subject: [PATCH 05/25] Set project's ObjectName to its PHID when it doesn't have a hashtag Summary: Fixes T12659. Previously this would lead to an error when trying to run `arc diff` on a revision that had a milestone as a reviewer (or any non-octothorpe'd Object Name) Test Plan: Followed repro steps in T12659 and didn't get the error described. Also clicked around and didn't notice any obvious regressions in projects or differential Reviewers: epriestley, #blessed_reviewers Reviewed By: epriestley, #blessed_reviewers Subscribers: Korvin, yelirekim Maniphest Tasks: T12659 Differential Revision: https://secure.phabricator.com/D17807 --- .../project/phid/PhabricatorProjectProjectPHIDType.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/applications/project/phid/PhabricatorProjectProjectPHIDType.php b/src/applications/project/phid/PhabricatorProjectProjectPHIDType.php index 7a04103a7c..3aa6088780 100644 --- a/src/applications/project/phid/PhabricatorProjectProjectPHIDType.php +++ b/src/applications/project/phid/PhabricatorProjectProjectPHIDType.php @@ -47,6 +47,10 @@ final class PhabricatorProjectProjectPHIDType extends PhabricatorPHIDType { $handle->setObjectName('#'.$slug); $handle->setURI("/tag/{$slug}/"); } else { + // We set the name to the project's PHID to avoid a parse error when a + // project has no hashtag (as is the case with milestones by default). + // See T12659 for more details + $handle->setCommandLineObjectName($project->getPHID()); $handle->setURI("/project/view/{$id}/"); } From da6d624fe8782ceabea1098749d96af14218cb7c Mon Sep 17 00:00:00 2001 From: Chad Little Date: Mon, 1 May 2017 09:17:34 -0700 Subject: [PATCH 06/25] Mark ConpherenceCreate and Update conduit calls as frozen Summary: T12656, mark these methods as frozen and use conpherence.edit instead. Test Plan: Visit conduit, check status is displayed. Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Differential Revision: https://secure.phabricator.com/D17808 --- .../ConpherenceCreateThreadConduitAPIMethod.php | 10 ++++++++++ .../ConpherenceUpdateThreadConduitAPIMethod.php | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/src/applications/conpherence/conduit/ConpherenceCreateThreadConduitAPIMethod.php b/src/applications/conpherence/conduit/ConpherenceCreateThreadConduitAPIMethod.php index 9cae87e10a..e751318c16 100644 --- a/src/applications/conpherence/conduit/ConpherenceCreateThreadConduitAPIMethod.php +++ b/src/applications/conpherence/conduit/ConpherenceCreateThreadConduitAPIMethod.php @@ -11,6 +11,16 @@ final class ConpherenceCreateThreadConduitAPIMethod return pht('Create a new conpherence thread.'); } + public function getMethodStatus() { + return self::METHOD_STATUS_FROZEN; + } + + public function getMethodStatusDescription() { + return pht( + 'This method is frozen and will eventually be deprecated. New code '. + 'should use "conpherence.edit" instead.'); + } + protected function defineParamTypes() { return array( 'title' => 'required string', diff --git a/src/applications/conpherence/conduit/ConpherenceUpdateThreadConduitAPIMethod.php b/src/applications/conpherence/conduit/ConpherenceUpdateThreadConduitAPIMethod.php index e7d927905d..71000000c1 100644 --- a/src/applications/conpherence/conduit/ConpherenceUpdateThreadConduitAPIMethod.php +++ b/src/applications/conpherence/conduit/ConpherenceUpdateThreadConduitAPIMethod.php @@ -11,6 +11,16 @@ final class ConpherenceUpdateThreadConduitAPIMethod return pht('Update an existing conpherence room.'); } + public function getMethodStatus() { + return self::METHOD_STATUS_FROZEN; + } + + public function getMethodStatusDescription() { + return pht( + 'This method is frozen and will eventually be deprecated. New code '. + 'should use "conpherence.edit" instead.'); + } + protected function defineParamTypes() { return array( 'id' => 'optional int', From 0ebe56be40863a4c6d68a212553cd82d960eeae0 Mon Sep 17 00:00:00 2001 From: epriestley Date: Mon, 1 May 2017 10:37:12 -0700 Subject: [PATCH 07/25] Fix two Calendar availability cache issues Summary: Fixes T12661. When changing the start date of an event from some time in the past to some time significantly in the future (more than 24 hours), we'd invalidate only future caches and leave users in an "away" state. Instead, just invalidate all past and future caches (this is simpler than trying to figure out a narrower window, and should not make us do too much extra work). When uninviting users from events, their caches also didn't get cleared correctly. Instead, clear them. Test Plan: - Changed an event from "Apr 1 - June 1" to "May 15 - June 1", saw availablity clear properly. - Uninvited user `@dog` from an ongoing event, saw availability clear properly. Reviewers: chad Reviewed By: chad Maniphest Tasks: T12661 Differential Revision: https://secure.phabricator.com/D17809 --- .../editor/PhabricatorCalendarEventEditor.php | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/applications/calendar/editor/PhabricatorCalendarEventEditor.php b/src/applications/calendar/editor/PhabricatorCalendarEventEditor.php index eee6b46751..4ab13fd360 100644 --- a/src/applications/calendar/editor/PhabricatorCalendarEventEditor.php +++ b/src/applications/calendar/editor/PhabricatorCalendarEventEditor.php @@ -127,6 +127,9 @@ final class PhabricatorCalendarEventEditor // Clear the availability caches for users whose availability is affected // by this edit. + $phids = mpull($object->getInvitees(), 'getInviteePHID'); + $phids = array_fuse($phids); + $invalidate_all = false; $invalidate_phids = array(); foreach ($xactions as $xaction) { @@ -146,16 +149,21 @@ final class PhabricatorCalendarEventEditor $invalidate_phids[$acting_phid] = $acting_phid; break; case PhabricatorCalendarEventInviteTransaction::TRANSACTIONTYPE: - foreach ($xaction->getNewValue() as $phid => $ignored) { + foreach ($xaction->getOldValue() as $phid) { + // Add the possibly un-invited user to the list of potentially + // affected users if they are't already present. + $phids[$phid] = $phid; + + $invalidate_phids[$phid] = $phid; + } + + foreach ($xaction->getNewValue() as $phid) { $invalidate_phids[$phid] = $phid; } break; } } - $phids = mpull($object->getInvitees(), 'getInviteePHID'); - $phids = array_fuse($phids); - if (!$invalidate_all) { $phids = array_select_keys($phids, $invalidate_phids); } @@ -168,10 +176,9 @@ final class PhabricatorCalendarEventEditor queryfx( $conn_w, 'UPDATE %T SET availabilityCacheTTL = NULL - WHERE phid IN (%Ls) AND availabilityCacheTTL >= %d', + WHERE phid IN (%Ls)', $user->getTableName(), - $phids, - $object->getStartDateTimeEpochForCache()); + $phids); } return $xactions; From dff028c4907dd1959859733ea0d947f244559e7f Mon Sep 17 00:00:00 2001 From: Chad Little Date: Mon, 1 May 2017 11:16:38 -0700 Subject: [PATCH 08/25] Update PonderQuestion for Modular Transactions Summary: Ref T12624, this moves PonderQuestion over to modular transactions. Test Plan: - Create a question - Edit a question - Comment on question - Answer question - Edit Answer - Close Question - Verify answer count in list views - Check Question History - Check Answer History Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Maniphest Tasks: T12624 Differential Revision: https://secure.phabricator.com/D17810 --- src/__phutil_library_map__.php | 14 +- .../controller/PonderAnswerSaveController.php | 2 +- .../PonderQuestionEditController.php | 11 +- .../PonderQuestionStatusController.php | 2 +- .../ponder/editor/PonderQuestionEditor.php | 120 +------- .../storage/PonderQuestionTransaction.php | 279 +----------------- .../PonderQuestionAnswerTransaction.php | 28 ++ .../PonderQuestionAnswerWikiTransaction.php | 56 ++++ .../PonderQuestionContentTransaction.php | 56 ++++ .../PonderQuestionStatusTransaction.php | 74 +++++ .../PonderQuestionTitleTransaction.php | 55 ++++ .../xaction/PonderQuestionTransactionType.php | 4 + 12 files changed, 309 insertions(+), 392 deletions(-) create mode 100644 src/applications/ponder/xaction/PonderQuestionAnswerTransaction.php create mode 100644 src/applications/ponder/xaction/PonderQuestionAnswerWikiTransaction.php create mode 100644 src/applications/ponder/xaction/PonderQuestionContentTransaction.php create mode 100644 src/applications/ponder/xaction/PonderQuestionStatusTransaction.php create mode 100644 src/applications/ponder/xaction/PonderQuestionTitleTransaction.php create mode 100644 src/applications/ponder/xaction/PonderQuestionTransactionType.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 33618ca547..2ddff09728 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -4572,7 +4572,10 @@ phutil_register_library_map(array( 'PonderFooterView' => 'applications/ponder/view/PonderFooterView.php', 'PonderModerateCapability' => 'applications/ponder/capability/PonderModerateCapability.php', 'PonderQuestion' => 'applications/ponder/storage/PonderQuestion.php', + 'PonderQuestionAnswerTransaction' => 'applications/ponder/xaction/PonderQuestionAnswerTransaction.php', + 'PonderQuestionAnswerWikiTransaction' => 'applications/ponder/xaction/PonderQuestionAnswerWikiTransaction.php', 'PonderQuestionCommentController' => 'applications/ponder/controller/PonderQuestionCommentController.php', + 'PonderQuestionContentTransaction' => 'applications/ponder/xaction/PonderQuestionContentTransaction.php', 'PonderQuestionCreateMailReceiver' => 'applications/ponder/mail/PonderQuestionCreateMailReceiver.php', 'PonderQuestionEditController' => 'applications/ponder/controller/PonderQuestionEditController.php', 'PonderQuestionEditor' => 'applications/ponder/editor/PonderQuestionEditor.php', @@ -4586,9 +4589,12 @@ phutil_register_library_map(array( 'PonderQuestionSearchEngine' => 'applications/ponder/query/PonderQuestionSearchEngine.php', 'PonderQuestionStatus' => 'applications/ponder/constants/PonderQuestionStatus.php', 'PonderQuestionStatusController' => 'applications/ponder/controller/PonderQuestionStatusController.php', + 'PonderQuestionStatusTransaction' => 'applications/ponder/xaction/PonderQuestionStatusTransaction.php', + 'PonderQuestionTitleTransaction' => 'applications/ponder/xaction/PonderQuestionTitleTransaction.php', 'PonderQuestionTransaction' => 'applications/ponder/storage/PonderQuestionTransaction.php', 'PonderQuestionTransactionComment' => 'applications/ponder/storage/PonderQuestionTransactionComment.php', 'PonderQuestionTransactionQuery' => 'applications/ponder/query/PonderQuestionTransactionQuery.php', + 'PonderQuestionTransactionType' => 'applications/ponder/xaction/PonderQuestionTransactionType.php', 'PonderQuestionViewController' => 'applications/ponder/controller/PonderQuestionViewController.php', 'PonderRemarkupRule' => 'applications/ponder/remarkup/PonderRemarkupRule.php', 'PonderSchemaSpec' => 'applications/ponder/storage/PonderSchemaSpec.php', @@ -10126,7 +10132,10 @@ phutil_register_library_map(array( 'PhabricatorSpacesInterface', 'PhabricatorFulltextInterface', ), + 'PonderQuestionAnswerTransaction' => 'PonderQuestionTransactionType', + 'PonderQuestionAnswerWikiTransaction' => 'PonderQuestionTransactionType', 'PonderQuestionCommentController' => 'PonderController', + 'PonderQuestionContentTransaction' => 'PonderQuestionTransactionType', 'PonderQuestionCreateMailReceiver' => 'PhabricatorMailReceiver', 'PonderQuestionEditController' => 'PonderController', 'PonderQuestionEditor' => 'PonderEditor', @@ -10140,9 +10149,12 @@ phutil_register_library_map(array( 'PonderQuestionSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PonderQuestionStatus' => 'PonderConstants', 'PonderQuestionStatusController' => 'PonderController', - 'PonderQuestionTransaction' => 'PhabricatorApplicationTransaction', + 'PonderQuestionStatusTransaction' => 'PonderQuestionTransactionType', + 'PonderQuestionTitleTransaction' => 'PonderQuestionTransactionType', + 'PonderQuestionTransaction' => 'PhabricatorModularTransaction', 'PonderQuestionTransactionComment' => 'PhabricatorApplicationTransactionComment', 'PonderQuestionTransactionQuery' => 'PhabricatorApplicationTransactionQuery', + 'PonderQuestionTransactionType' => 'PhabricatorModularTransactionType', 'PonderQuestionViewController' => 'PonderController', 'PonderRemarkupRule' => 'PhabricatorObjectRemarkupRule', 'PonderSchemaSpec' => 'PhabricatorConfigSchemaSpec', diff --git a/src/applications/ponder/controller/PonderAnswerSaveController.php b/src/applications/ponder/controller/PonderAnswerSaveController.php index cac17acbed..72e0e5ee04 100644 --- a/src/applications/ponder/controller/PonderAnswerSaveController.php +++ b/src/applications/ponder/controller/PonderAnswerSaveController.php @@ -38,7 +38,7 @@ final class PonderAnswerSaveController extends PonderController { $xactions = array(); $xactions[] = id(new PonderQuestionTransaction()) - ->setTransactionType(PonderQuestionTransaction::TYPE_ANSWERS) + ->setTransactionType(PonderQuestionAnswerTransaction::TRANSACTIONTYPE) ->setNewValue( array( '+' => array( diff --git a/src/applications/ponder/controller/PonderQuestionEditController.php b/src/applications/ponder/controller/PonderQuestionEditController.php index 49ca5fe846..c872933ca2 100644 --- a/src/applications/ponder/controller/PonderQuestionEditController.php +++ b/src/applications/ponder/controller/PonderQuestionEditController.php @@ -63,20 +63,23 @@ final class PonderQuestionEditController extends PonderController { $xactions = array(); $xactions[] = id(clone $template) - ->setTransactionType(PonderQuestionTransaction::TYPE_TITLE) + ->setTransactionType(PonderQuestionTitleTransaction::TRANSACTIONTYPE) ->setNewValue($v_title); $xactions[] = id(clone $template) - ->setTransactionType(PonderQuestionTransaction::TYPE_CONTENT) + ->setTransactionType( + PonderQuestionContentTransaction::TRANSACTIONTYPE) ->setNewValue($v_content); $xactions[] = id(clone $template) - ->setTransactionType(PonderQuestionTransaction::TYPE_ANSWERWIKI) + ->setTransactionType( + PonderQuestionAnswerWikiTransaction::TRANSACTIONTYPE) ->setNewValue($v_wiki); if (!$is_new) { $xactions[] = id(clone $template) - ->setTransactionType(PonderQuestionTransaction::TYPE_STATUS) + ->setTransactionType( + PonderQuestionStatusTransaction::TRANSACTIONTYPE) ->setNewValue($v_status); } diff --git a/src/applications/ponder/controller/PonderQuestionStatusController.php b/src/applications/ponder/controller/PonderQuestionStatusController.php index a4671d5915..ab791b740f 100644 --- a/src/applications/ponder/controller/PonderQuestionStatusController.php +++ b/src/applications/ponder/controller/PonderQuestionStatusController.php @@ -28,7 +28,7 @@ final class PonderQuestionStatusController $xactions = array(); $xactions[] = id(new PonderQuestionTransaction()) - ->setTransactionType(PonderQuestionTransaction::TYPE_STATUS) + ->setTransactionType(PonderQuestionStatusTransaction::TRANSACTIONTYPE) ->setNewValue($v_status); $editor = id(new PonderQuestionEditor()) diff --git a/src/applications/ponder/editor/PonderQuestionEditor.php b/src/applications/ponder/editor/PonderQuestionEditor.php index 73d9ed0ce0..9b34031f13 100644 --- a/src/applications/ponder/editor/PonderQuestionEditor.php +++ b/src/applications/ponder/editor/PonderQuestionEditor.php @@ -32,7 +32,7 @@ final class PonderQuestionEditor foreach ($xactions as $xaction) { switch ($xaction->getTransactionType()) { - case PonderQuestionTransaction::TYPE_ANSWERS: + case PonderQuestionAnswerTransaction::TRANSACTIONTYPE: return true; } } @@ -46,7 +46,7 @@ final class PonderQuestionEditor foreach ($xactions as $xaction) { switch ($xaction->getTransactionType()) { - case PonderQuestionTransaction::TYPE_ANSWERS: + case PonderQuestionAnswerTransaction::TRANSACTIONTYPE: $new_value = $xaction->getNewValue(); $new = idx($new_value, '+', array()); foreach ($new as $new_answer) { @@ -70,117 +70,9 @@ final class PonderQuestionEditor $types[] = PhabricatorTransactions::TYPE_EDIT_POLICY; $types[] = PhabricatorTransactions::TYPE_SPACE; - $types[] = PonderQuestionTransaction::TYPE_TITLE; - $types[] = PonderQuestionTransaction::TYPE_CONTENT; - $types[] = PonderQuestionTransaction::TYPE_ANSWERS; - $types[] = PonderQuestionTransaction::TYPE_STATUS; - $types[] = PonderQuestionTransaction::TYPE_ANSWERWIKI; - return $types; } - protected function getCustomTransactionOldValue( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case PonderQuestionTransaction::TYPE_TITLE: - return $object->getTitle(); - case PonderQuestionTransaction::TYPE_CONTENT: - return $object->getContent(); - case PonderQuestionTransaction::TYPE_ANSWERS: - return mpull($object->getAnswers(), 'getPHID'); - case PonderQuestionTransaction::TYPE_STATUS: - return $object->getStatus(); - case PonderQuestionTransaction::TYPE_ANSWERWIKI: - return $object->getAnswerWiki(); - } - } - - protected function getCustomTransactionNewValue( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case PonderQuestionTransaction::TYPE_TITLE: - case PonderQuestionTransaction::TYPE_CONTENT: - case PonderQuestionTransaction::TYPE_STATUS: - case PonderQuestionTransaction::TYPE_ANSWERWIKI: - return $xaction->getNewValue(); - case PonderQuestionTransaction::TYPE_ANSWERS: - $raw_new_value = $xaction->getNewValue(); - $new_value = array(); - foreach ($raw_new_value as $key => $answers) { - $phids = array(); - foreach ($answers as $answer) { - $obj = idx($answer, 'answer'); - if (!$answer) { - continue; - } - $phids[] = $obj->getPHID(); - } - $new_value[$key] = $phids; - } - $xaction->setNewValue($new_value); - return $this->getPHIDTransactionNewValue($xaction); - } - } - - protected function applyCustomInternalTransaction( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case PonderQuestionTransaction::TYPE_TITLE: - $object->setTitle($xaction->getNewValue()); - break; - case PonderQuestionTransaction::TYPE_CONTENT: - $object->setContent($xaction->getNewValue()); - break; - case PonderQuestionTransaction::TYPE_STATUS: - $object->setStatus($xaction->getNewValue()); - break; - case PonderQuestionTransaction::TYPE_ANSWERWIKI: - $object->setAnswerWiki($xaction->getNewValue()); - break; - case PonderQuestionTransaction::TYPE_ANSWERS: - $old = $xaction->getOldValue(); - $new = $xaction->getNewValue(); - - $add = array_diff_key($new, $old); - $rem = array_diff_key($old, $new); - - $count = $object->getAnswerCount(); - $count += count($add); - $count -= count($rem); - - $object->setAnswerCount($count); - break; - } - } - - protected function applyCustomExternalTransaction( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - return; - } - - protected function mergeTransactions( - PhabricatorApplicationTransaction $u, - PhabricatorApplicationTransaction $v) { - - $type = $u->getTransactionType(); - switch ($type) { - case PonderQuestionTransaction::TYPE_TITLE: - case PonderQuestionTransaction::TYPE_CONTENT: - case PonderQuestionTransaction::TYPE_STATUS: - case PonderQuestionTransaction::TYPE_ANSWERWIKI: - return $v; - } - - return parent::mergeTransactions($u, $v); - } - protected function supportsSearch() { return true; } @@ -190,7 +82,7 @@ final class PonderQuestionEditor PhabricatorApplicationTransaction $xaction) { switch ($xaction->getTransactionType()) { - case PonderQuestionTransaction::TYPE_ANSWERS: + case PonderQuestionAnswerTransaction::TRANSACTIONTYPE: return false; } @@ -202,7 +94,7 @@ final class PonderQuestionEditor array $xactions) { foreach ($xactions as $xaction) { switch ($xaction->getTransactionType()) { - case PonderQuestionTransaction::TYPE_ANSWERS: + case PonderQuestionAnswerTransaction::TRANSACTIONTYPE: return false; } } @@ -221,7 +113,7 @@ final class PonderQuestionEditor array $xactions) { foreach ($xactions as $xaction) { switch ($xaction->getTransactionType()) { - case PonderQuestionTransaction::TYPE_ANSWERS: + case PonderQuestionAnswerTransaction::TRANSACTIONTYPE: return false; } } @@ -269,7 +161,7 @@ final class PonderQuestionEditor $old = $xaction->getOldValue(); $new = $xaction->getNewValue(); // If the user just asked the question, add the question text. - if ($type == PonderQuestionTransaction::TYPE_CONTENT) { + if ($type == PonderQuestionContentTransaction::TRANSACTIONTYPE) { if ($old === null) { $body->addRawSection($new); } diff --git a/src/applications/ponder/storage/PonderQuestionTransaction.php b/src/applications/ponder/storage/PonderQuestionTransaction.php index 7abfd247f5..73a0899ca8 100644 --- a/src/applications/ponder/storage/PonderQuestionTransaction.php +++ b/src/applications/ponder/storage/PonderQuestionTransaction.php @@ -1,13 +1,7 @@ getTransactionType()) { - case self::TYPE_ANSWERS: - $phids[] = $this->getNewAnswerPHID(); - $phids[] = $this->getObjectPHID(); - break; - } - - return $phids; - } - - public function getRemarkupBlocks() { - $blocks = parent::getRemarkupBlocks(); - switch ($this->getTransactionType()) { - case self::TYPE_CONTENT: - $blocks[] = $this->getNewValue(); - break; - } - return $blocks; - } - - public function getTitle() { - $author_phid = $this->getAuthorPHID(); - $object_phid = $this->getObjectPHID(); - - $old = $this->getOldValue(); - $new = $this->getNewValue(); - - switch ($this->getTransactionType()) { - case self::TYPE_TITLE: - if ($old === null) { - return pht( - '%s asked this question.', - $this->renderHandleLink($author_phid)); - } else { - return pht( - '%s edited the question title from "%s" to "%s".', - $this->renderHandleLink($author_phid), - $old, - $new); - } - case self::TYPE_CONTENT: - return pht( - '%s edited the question description.', - $this->renderHandleLink($author_phid)); - case self::TYPE_ANSWERWIKI: - return pht( - '%s edited the question answer wiki.', - $this->renderHandleLink($author_phid)); - case self::TYPE_ANSWERS: - $answer_handle = $this->getHandle($this->getNewAnswerPHID()); - $question_handle = $this->getHandle($object_phid); - - return pht( - '%s answered %s', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - case self::TYPE_STATUS: - switch ($new) { - case PonderQuestionStatus::STATUS_OPEN: - return pht( - '%s reopened this question.', - $this->renderHandleLink($author_phid)); - case PonderQuestionStatus::STATUS_CLOSED_RESOLVED: - return pht( - '%s closed this question as resolved.', - $this->renderHandleLink($author_phid)); - case PonderQuestionStatus::STATUS_CLOSED_OBSOLETE: - return pht( - '%s closed this question as obsolete.', - $this->renderHandleLink($author_phid)); - case PonderQuestionStatus::STATUS_CLOSED_INVALID: - return pht( - '%s closed this question as invalid.', - $this->renderHandleLink($author_phid)); - } - } - - return parent::getTitle(); + public function getBaseTransactionClass() { + return 'PonderQuestionTransactionType'; } public function getMailTags() { @@ -120,13 +35,13 @@ final class PonderQuestionTransaction case PhabricatorTransactions::TYPE_COMMENT: $tags[] = self::MAILTAG_COMMENT; break; - case self::TYPE_TITLE: - case self::TYPE_CONTENT: - case self::TYPE_STATUS: - case self::TYPE_ANSWERWIKI: + case PonderQuestionTitleTransaction::TRANSACTIONTYPE: + case PonderQuestionContentTransaction::TRANSACTIONTYPE: + case PonderQuestionStatusTransaction::TRANSACTIONTYPE: + case PonderQuestionAnswerWikiTransaction::TRANSACTIONTYPE: $tags[] = self::MAILTAG_DETAILS; break; - case self::TYPE_ANSWERS: + case PonderQuestionAnswerTransaction::TRANSACTIONTYPE: $tags[] = self::MAILTAG_ANSWERS; break; default: @@ -136,182 +51,4 @@ final class PonderQuestionTransaction return $tags; } - public function getIcon() { - $old = $this->getOldValue(); - $new = $this->getNewValue(); - - switch ($this->getTransactionType()) { - case self::TYPE_TITLE: - case self::TYPE_CONTENT: - case self::TYPE_ANSWERWIKI: - return 'fa-pencil'; - case self::TYPE_STATUS: - return PonderQuestionStatus::getQuestionStatusIcon($new); - case self::TYPE_ANSWERS: - return 'fa-plus'; - } - - return parent::getIcon(); - } - - public function getColor() { - $old = $this->getOldValue(); - $new = $this->getNewValue(); - - switch ($this->getTransactionType()) { - case self::TYPE_TITLE: - case self::TYPE_CONTENT: - case self::TYPE_ANSWERWIKI: - return PhabricatorTransactions::COLOR_BLUE; - case self::TYPE_ANSWERS: - return PhabricatorTransactions::COLOR_GREEN; - case self::TYPE_STATUS: - return PonderQuestionStatus::getQuestionStatusTagColor($new); - } - } - - public function hasChangeDetails() { - switch ($this->getTransactionType()) { - case self::TYPE_CONTENT: - case self::TYPE_ANSWERWIKI: - return true; - } - return parent::hasChangeDetails(); - } - - public function renderChangeDetails(PhabricatorUser $viewer) { - return $this->renderTextCorpusChangeDetails( - $viewer, - $this->getOldValue(), - $this->getNewValue()); - } - - public function getActionStrength() { - $old = $this->getOldValue(); - $new = $this->getNewValue(); - - switch ($this->getTransactionType()) { - case self::TYPE_TITLE: - if ($old === null) { - return 3; - } - break; - case self::TYPE_ANSWERS: - return 2; - } - - return parent::getActionStrength(); - } - - public function getActionName() { - $old = $this->getOldValue(); - $new = $this->getNewValue(); - - switch ($this->getTransactionType()) { - case self::TYPE_TITLE: - if ($old === null) { - return pht('Asked'); - } - break; - case self::TYPE_ANSWERS: - return pht('Answered'); - } - - return parent::getActionName(); - } - - public function getTitleForFeed() { - $author_phid = $this->getAuthorPHID(); - $object_phid = $this->getObjectPHID(); - - $old = $this->getOldValue(); - $new = $this->getNewValue(); - - switch ($this->getTransactionType()) { - case self::TYPE_TITLE: - if ($old === null) { - return pht( - '%s asked a question: %s', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - } else { - return pht( - '%s edited the title of %s (was "%s")', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid), - $old); - } - case self::TYPE_CONTENT: - return pht( - '%s edited the description of %s', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - case self::TYPE_ANSWERWIKI: - return pht( - '%s edited the answer wiki for %s', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - case self::TYPE_ANSWERS: - $answer_handle = $this->getHandle($this->getNewAnswerPHID()); - $question_handle = $this->getHandle($object_phid); - return pht( - '%s answered %s', - $this->renderHandleLink($author_phid), - $answer_handle->renderLink($question_handle->getFullName())); - case self::TYPE_STATUS: - switch ($new) { - case PonderQuestionStatus::STATUS_OPEN: - return pht( - '%s reopened %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - case PonderQuestionStatus::STATUS_CLOSED_RESOLVED: - return pht( - '%s closed %s as resolved.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - case PonderQuestionStatus::STATUS_CLOSED_INVALID: - return pht( - '%s closed %s as invalid.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - case PonderQuestionStatus::STATUS_CLOSED_OBSOLETE: - return pht( - '%s closed %s as obsolete.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - } - } - - return parent::getTitleForFeed(); - } - - public function getRemarkupBodyForFeed(PhabricatorFeedStory $story) { - $text = null; - switch ($this->getTransactionType()) { - case self::TYPE_CONTENT: - $text = $this->getNewValue(); - break; - } - return $text; - } - - /** - * Currently the application only supports adding answers one at a time. - * This data is stored as a list of phids. Use this function to get the - * new phid. - */ - private function getNewAnswerPHID() { - $new = $this->getNewValue(); - $old = $this->getOldValue(); - $add = array_diff($new, $old); - - if (count($add) != 1) { - throw new Exception( - pht('There should be only one answer added at a time.')); - } - - return reset($add); - } - } diff --git a/src/applications/ponder/xaction/PonderQuestionAnswerTransaction.php b/src/applications/ponder/xaction/PonderQuestionAnswerTransaction.php new file mode 100644 index 0000000000..a51eada7b4 --- /dev/null +++ b/src/applications/ponder/xaction/PonderQuestionAnswerTransaction.php @@ -0,0 +1,28 @@ +getAnswers(); + } + + public function applyInternalEffects($object, $value) { + $count = $object->getAnswerCount(); + $count++; + $object->setAnswerCount($count); + } + + public function getTitle() { + return pht( + '%s added an answer.', + $this->renderAuthor()); + } + + public function getIcon() { + return 'fa-plus'; + } + +} diff --git a/src/applications/ponder/xaction/PonderQuestionAnswerWikiTransaction.php b/src/applications/ponder/xaction/PonderQuestionAnswerWikiTransaction.php new file mode 100644 index 0000000000..b6b5b150fc --- /dev/null +++ b/src/applications/ponder/xaction/PonderQuestionAnswerWikiTransaction.php @@ -0,0 +1,56 @@ +getAnswerWiki(); + } + + public function applyInternalEffects($object, $value) { + $object->setAnswerWiki($value); + } + + public function getTitle() { + return pht( + '%s updated the answer wiki.', + $this->renderAuthor()); + } + + public function getTitleForFeed() { + return pht( + '%s updated the answer wiki for %s.', + $this->renderAuthor(), + $this->renderObject()); + } + + public function hasChangeDetailView() { + return true; + } + + public function getMailDiffSectionHeader() { + return pht('CHANGES TO ANSWER WIKI'); + } + + public function newChangeDetailView() { + $viewer = $this->getViewer(); + + return id(new PhabricatorApplicationTransactionTextDiffDetailView()) + ->setViewer($viewer) + ->setOldText($this->getOldValue()) + ->setNewText($this->getNewValue()); + } + + public function newRemarkupChanges() { + $changes = array(); + + $changes[] = $this->newRemarkupChange() + ->setOldValue($this->getOldValue()) + ->setNewValue($this->getNewValue()); + + return $changes; + } + +} diff --git a/src/applications/ponder/xaction/PonderQuestionContentTransaction.php b/src/applications/ponder/xaction/PonderQuestionContentTransaction.php new file mode 100644 index 0000000000..d958170475 --- /dev/null +++ b/src/applications/ponder/xaction/PonderQuestionContentTransaction.php @@ -0,0 +1,56 @@ +getContent(); + } + + public function applyInternalEffects($object, $value) { + $object->setContent($value); + } + + public function getTitle() { + return pht( + '%s updated the question details.', + $this->renderAuthor()); + } + + public function getTitleForFeed() { + return pht( + '%s updated the question details for %s.', + $this->renderAuthor(), + $this->renderObject()); + } + + public function hasChangeDetailView() { + return true; + } + + public function getMailDiffSectionHeader() { + return pht('CHANGES TO QUESTION DETAILS'); + } + + public function newChangeDetailView() { + $viewer = $this->getViewer(); + + return id(new PhabricatorApplicationTransactionTextDiffDetailView()) + ->setViewer($viewer) + ->setOldText($this->getOldValue()) + ->setNewText($this->getNewValue()); + } + + public function newRemarkupChanges() { + $changes = array(); + + $changes[] = $this->newRemarkupChange() + ->setOldValue($this->getOldValue()) + ->setNewValue($this->getNewValue()); + + return $changes; + } + +} diff --git a/src/applications/ponder/xaction/PonderQuestionStatusTransaction.php b/src/applications/ponder/xaction/PonderQuestionStatusTransaction.php new file mode 100644 index 0000000000..85080b12b7 --- /dev/null +++ b/src/applications/ponder/xaction/PonderQuestionStatusTransaction.php @@ -0,0 +1,74 @@ +getStatus(); + } + + public function applyInternalEffects($object, $value) { + $object->setStatus($value); + } + + public function getTitle() { + $new = $this->getNewValue(); + switch ($new) { + case PonderQuestionStatus::STATUS_OPEN: + return pht( + '%s reopened this question.', + $this->renderAuthor()); + case PonderQuestionStatus::STATUS_CLOSED_RESOLVED: + return pht( + '%s closed this question as resolved.', + $this->renderAuthor()); + case PonderQuestionStatus::STATUS_CLOSED_OBSOLETE: + return pht( + '%s closed this question as obsolete.', + $this->renderAuthor()); + case PonderQuestionStatus::STATUS_CLOSED_INVALID: + return pht( + '%s closed this question as invalid.', + $this->renderAuthor()); + } + } + + public function getTitleForFeed() { + $new = $this->getNewValue(); + switch ($new) { + case PonderQuestionStatus::STATUS_OPEN: + return pht( + '%s reopened %s.', + $this->renderAuthor(), + $this->renderObject()); + case PonderQuestionStatus::STATUS_CLOSED_RESOLVED: + return pht( + '%s closed %s as resolved.', + $this->renderAuthor(), + $this->renderObject()); + case PonderQuestionStatus::STATUS_CLOSED_INVALID: + return pht( + '%s closed %s as invalid.', + $this->renderAuthor(), + $this->renderObject()); + case PonderQuestionStatus::STATUS_CLOSED_OBSOLETE: + return pht( + '%s closed %s as obsolete.', + $this->renderAuthor(), + $this->renderObject()); + } + } + + public function getIcon() { + $new = $this->getNewValue(); + return PonderQuestionStatus::getQuestionStatusIcon($new); + } + + public function getColor() { + $new = $this->getNewValue(); + return PonderQuestionStatus::getQuestionStatusTagColor($new); + } + +} diff --git a/src/applications/ponder/xaction/PonderQuestionTitleTransaction.php b/src/applications/ponder/xaction/PonderQuestionTitleTransaction.php new file mode 100644 index 0000000000..e96af9d78f --- /dev/null +++ b/src/applications/ponder/xaction/PonderQuestionTitleTransaction.php @@ -0,0 +1,55 @@ +getTitle(); + } + + public function applyInternalEffects($object, $value) { + $object->setTitle($value); + } + + public function getTitle() { + return pht( + '%s updated the question from %s to %s.', + $this->renderAuthor(), + $this->renderOldValue(), + $this->renderNewValue()); + } + + public function getTitleForFeed() { + return pht( + '%s updated %s from %s to %s.', + $this->renderAuthor(), + $this->renderObject(), + $this->renderOldValue(), + $this->renderNewValue()); + } + + public function validateTransactions($object, array $xactions) { + $errors = array(); + + if ($this->isEmptyTextTransaction($object->getTitle(), $xactions)) { + $errors[] = $this->newRequiredError( + pht('Questions must have a title.')); + } + + $max_length = $object->getColumnMaximumByteLength('title'); + foreach ($xactions as $xaction) { + $new_value = $xaction->getNewValue(); + $new_length = strlen($new_value); + if ($new_length > $max_length) { + $errors[] = $this->newInvalidError( + pht('The title can be no longer than %s characters.', + new PhutilNumber($max_length))); + } + } + + return $errors; + } + +} diff --git a/src/applications/ponder/xaction/PonderQuestionTransactionType.php b/src/applications/ponder/xaction/PonderQuestionTransactionType.php new file mode 100644 index 0000000000..6b68122464 --- /dev/null +++ b/src/applications/ponder/xaction/PonderQuestionTransactionType.php @@ -0,0 +1,4 @@ + Date: Mon, 1 May 2017 12:34:43 -0700 Subject: [PATCH 09/25] Convert PonderAnswer to modular transactions Summary: Fixes T12624. Converts PonderAnswer over to modular transactions. Test Plan: - Add an answer - Edit an answer - Hide an answer - Comment on an answer Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Maniphest Tasks: T12624 Differential Revision: https://secure.phabricator.com/D17811 --- src/__phutil_library_map__.php | 10 +- .../controller/PonderAnswerEditController.php | 4 +- .../controller/PonderAnswerSaveController.php | 4 +- .../ponder/editor/PonderAnswerEditor.php | 67 -------- .../storage/PonderAnswerTransaction.php | 143 +----------------- .../PonderAnswerContentTransaction.php | 56 +++++++ .../PonderAnswerQuestionIDTransaction.php | 16 ++ .../xaction/PonderAnswerStatusTransaction.php | 62 ++++++++ .../xaction/PonderAnswerTransactionType.php | 4 + 9 files changed, 154 insertions(+), 212 deletions(-) create mode 100644 src/applications/ponder/xaction/PonderAnswerContentTransaction.php create mode 100644 src/applications/ponder/xaction/PonderAnswerQuestionIDTransaction.php create mode 100644 src/applications/ponder/xaction/PonderAnswerStatusTransaction.php create mode 100644 src/applications/ponder/xaction/PonderAnswerTransactionType.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 2ddff09728..1dc20b5019 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -4551,18 +4551,22 @@ phutil_register_library_map(array( 'PonderAddAnswerView' => 'applications/ponder/view/PonderAddAnswerView.php', 'PonderAnswer' => 'applications/ponder/storage/PonderAnswer.php', 'PonderAnswerCommentController' => 'applications/ponder/controller/PonderAnswerCommentController.php', + 'PonderAnswerContentTransaction' => 'applications/ponder/xaction/PonderAnswerContentTransaction.php', 'PonderAnswerEditController' => 'applications/ponder/controller/PonderAnswerEditController.php', 'PonderAnswerEditor' => 'applications/ponder/editor/PonderAnswerEditor.php', 'PonderAnswerHistoryController' => 'applications/ponder/controller/PonderAnswerHistoryController.php', 'PonderAnswerMailReceiver' => 'applications/ponder/mail/PonderAnswerMailReceiver.php', 'PonderAnswerPHIDType' => 'applications/ponder/phid/PonderAnswerPHIDType.php', 'PonderAnswerQuery' => 'applications/ponder/query/PonderAnswerQuery.php', + 'PonderAnswerQuestionIDTransaction' => 'applications/ponder/xaction/PonderAnswerQuestionIDTransaction.php', 'PonderAnswerReplyHandler' => 'applications/ponder/mail/PonderAnswerReplyHandler.php', 'PonderAnswerSaveController' => 'applications/ponder/controller/PonderAnswerSaveController.php', 'PonderAnswerStatus' => 'applications/ponder/constants/PonderAnswerStatus.php', + 'PonderAnswerStatusTransaction' => 'applications/ponder/xaction/PonderAnswerStatusTransaction.php', 'PonderAnswerTransaction' => 'applications/ponder/storage/PonderAnswerTransaction.php', 'PonderAnswerTransactionComment' => 'applications/ponder/storage/PonderAnswerTransactionComment.php', 'PonderAnswerTransactionQuery' => 'applications/ponder/query/PonderAnswerTransactionQuery.php', + 'PonderAnswerTransactionType' => 'applications/ponder/xaction/PonderAnswerTransactionType.php', 'PonderAnswerView' => 'applications/ponder/view/PonderAnswerView.php', 'PonderConstants' => 'applications/ponder/constants/PonderConstants.php', 'PonderController' => 'applications/ponder/controller/PonderController.php', @@ -10099,18 +10103,22 @@ phutil_register_library_map(array( 'PhabricatorDestructibleInterface', ), 'PonderAnswerCommentController' => 'PonderController', + 'PonderAnswerContentTransaction' => 'PonderAnswerTransactionType', 'PonderAnswerEditController' => 'PonderController', 'PonderAnswerEditor' => 'PonderEditor', 'PonderAnswerHistoryController' => 'PonderController', 'PonderAnswerMailReceiver' => 'PhabricatorObjectMailReceiver', 'PonderAnswerPHIDType' => 'PhabricatorPHIDType', 'PonderAnswerQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', + 'PonderAnswerQuestionIDTransaction' => 'PonderAnswerTransactionType', 'PonderAnswerReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler', 'PonderAnswerSaveController' => 'PonderController', 'PonderAnswerStatus' => 'PonderConstants', - 'PonderAnswerTransaction' => 'PhabricatorApplicationTransaction', + 'PonderAnswerStatusTransaction' => 'PonderAnswerTransactionType', + 'PonderAnswerTransaction' => 'PhabricatorModularTransaction', 'PonderAnswerTransactionComment' => 'PhabricatorApplicationTransactionComment', 'PonderAnswerTransactionQuery' => 'PhabricatorApplicationTransactionQuery', + 'PonderAnswerTransactionType' => 'PhabricatorModularTransactionType', 'PonderAnswerView' => 'AphrontTagView', 'PonderConstants' => 'Phobject', 'PonderController' => 'PhabricatorController', diff --git a/src/applications/ponder/controller/PonderAnswerEditController.php b/src/applications/ponder/controller/PonderAnswerEditController.php index 3362e15834..9c48c7c669 100644 --- a/src/applications/ponder/controller/PonderAnswerEditController.php +++ b/src/applications/ponder/controller/PonderAnswerEditController.php @@ -42,11 +42,11 @@ final class PonderAnswerEditController extends PonderController { if (!$errors) { $xactions = array(); $xactions[] = id(new PonderAnswerTransaction()) - ->setTransactionType(PonderAnswerTransaction::TYPE_CONTENT) + ->setTransactionType(PonderAnswerContentTransaction::TRANSACTIONTYPE) ->setNewValue($v_content); $xactions[] = id(new PonderAnswerTransaction()) - ->setTransactionType(PonderAnswerTransaction::TYPE_STATUS) + ->setTransactionType(PonderAnswerStatusTransaction::TRANSACTIONTYPE) ->setNewValue($v_status); $editor = id(new PonderAnswerEditor()) diff --git a/src/applications/ponder/controller/PonderAnswerSaveController.php b/src/applications/ponder/controller/PonderAnswerSaveController.php index 72e0e5ee04..53e0f06ea6 100644 --- a/src/applications/ponder/controller/PonderAnswerSaveController.php +++ b/src/applications/ponder/controller/PonderAnswerSaveController.php @@ -58,11 +58,11 @@ final class PonderAnswerSaveController extends PonderController { $xactions = array(); $xactions[] = id(clone $template) - ->setTransactionType(PonderAnswerTransaction::TYPE_QUESTION_ID) + ->setTransactionType(PonderAnswerQuestionIDTransaction::TRANSACTIONTYPE) ->setNewValue($question->getID()); $xactions[] = id(clone $template) - ->setTransactionType(PonderAnswerTransaction::TYPE_CONTENT) + ->setTransactionType(PonderAnswerContentTransaction::TRANSACTIONTYPE) ->setNewValue($content); $editor = id(new PonderAnswerEditor()) diff --git a/src/applications/ponder/editor/PonderAnswerEditor.php b/src/applications/ponder/editor/PonderAnswerEditor.php index 10a90a1945..5bde437e3e 100644 --- a/src/applications/ponder/editor/PonderAnswerEditor.php +++ b/src/applications/ponder/editor/PonderAnswerEditor.php @@ -8,78 +8,11 @@ final class PonderAnswerEditor extends PonderEditor { public function getTransactionTypes() { $types = parent::getTransactionTypes(); - $types[] = PhabricatorTransactions::TYPE_COMMENT; - $types[] = PhabricatorTransactions::TYPE_EDGE; - - $types[] = PonderAnswerTransaction::TYPE_CONTENT; - $types[] = PonderAnswerTransaction::TYPE_STATUS; - $types[] = PonderAnswerTransaction::TYPE_QUESTION_ID; return $types; } - protected function getCustomTransactionOldValue( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case PonderAnswerTransaction::TYPE_CONTENT: - case PonderAnswerTransaction::TYPE_STATUS: - return $object->getContent(); - case PonderAnswerTransaction::TYPE_QUESTION_ID: - return $object->getQuestionID(); - } - } - - protected function getCustomTransactionNewValue( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case PonderAnswerTransaction::TYPE_CONTENT: - case PonderAnswerTransaction::TYPE_STATUS: - case PonderAnswerTransaction::TYPE_QUESTION_ID: - return $xaction->getNewValue(); - } - } - - protected function applyCustomInternalTransaction( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case PonderAnswerTransaction::TYPE_CONTENT: - $object->setContent($xaction->getNewValue()); - break; - case PonderAnswerTransaction::TYPE_STATUS: - $object->setStatus($xaction->getNewValue()); - break; - case PonderAnswerTransaction::TYPE_QUESTION_ID: - $object->setQuestionID($xaction->getNewValue()); - break; - } - } - - protected function applyCustomExternalTransaction( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - return; - } - - protected function mergeTransactions( - PhabricatorApplicationTransaction $u, - PhabricatorApplicationTransaction $v) { - - $type = $u->getTransactionType(); - switch ($type) { - case PonderAnswerTransaction::TYPE_CONTENT: - return $v; - } - - return parent::mergeTransactions($u, $v); - } - protected function shouldSendMail( PhabricatorLiskDAO $object, array $xactions) { diff --git a/src/applications/ponder/storage/PonderAnswerTransaction.php b/src/applications/ponder/storage/PonderAnswerTransaction.php index 924817b34e..784b8a36e7 100644 --- a/src/applications/ponder/storage/PonderAnswerTransaction.php +++ b/src/applications/ponder/storage/PonderAnswerTransaction.php @@ -1,11 +1,7 @@ getTransactionType()) { - case self::TYPE_CONTENT: - case self::TYPE_STATUS: - $phids[] = $this->getObjectPHID(); - break; - } - - return $phids; - } - - public function getRemarkupBlocks() { - $blocks = parent::getRemarkupBlocks(); - switch ($this->getTransactionType()) { - case self::TYPE_CONTENT: - $blocks[] = $this->getNewValue(); - break; - } - return $blocks; - } - - public function shouldHide() { - switch ($this->getTransactionType()) { - case self::TYPE_QUESTION_ID: - return true; - } - return parent::shouldHide(); - } - - public function getTitle() { - $author_phid = $this->getAuthorPHID(); - $object_phid = $this->getObjectPHID(); - - $old = $this->getOldValue(); - $new = $this->getNewValue(); - - switch ($this->getTransactionType()) { - case self::TYPE_CONTENT: - if ($old === '') { - return pht( - '%s added %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - } else { - return pht( - '%s edited %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - } - break; - case self::TYPE_STATUS: - if ($new == PonderAnswerStatus::ANSWER_STATUS_VISIBLE) { - return pht( - '%s marked %s as visible.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - } else if ($new == PonderAnswerStatus::ANSWER_STATUS_HIDDEN) { - return pht( - '%s marked %s as hidden.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - } - break; - } - - return parent::getTitle(); - } - - public function getTitleForFeed() { - $author_phid = $this->getAuthorPHID(); - $object_phid = $this->getObjectPHID(); - - $old = $this->getOldValue(); - $new = $this->getNewValue(); - - switch ($this->getTransactionType()) { - case self::TYPE_CONTENT: - if ($old === '') { - return pht( - '%s added %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - } else { - return pht( - '%s updated %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - } - break; - case self::TYPE_STATUS: - if ($new == PonderAnswerStatus::ANSWER_STATUS_VISIBLE) { - return pht( - '%s marked %s as visible.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - } else if ($new == PonderAnswerStatus::ANSWER_STATUS_HIDDEN) { - return pht( - '%s marked %s as hidden.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - } - break; - } - - return parent::getTitleForFeed(); - } - - public function getRemarkupBodyForFeed(PhabricatorFeedStory $story) { - $text = null; - switch ($this->getTransactionType()) { - case self::TYPE_CONTENT: - $text = $this->getNewValue(); - break; - } - return $text; - } - - - public function hasChangeDetails() { - $old = $this->getOldValue(); - - switch ($this->getTransactionType()) { - case self::TYPE_CONTENT: - return $old !== null; - } - return parent::hasChangeDetails(); - } - - public function renderChangeDetails(PhabricatorUser $viewer) { - return $this->renderTextCorpusChangeDetails( - $viewer, - $this->getOldValue(), - $this->getNewValue()); + public function getBaseTransactionClass() { + return 'PonderAnswerTransactionType'; } } diff --git a/src/applications/ponder/xaction/PonderAnswerContentTransaction.php b/src/applications/ponder/xaction/PonderAnswerContentTransaction.php new file mode 100644 index 0000000000..5d5c6ad157 --- /dev/null +++ b/src/applications/ponder/xaction/PonderAnswerContentTransaction.php @@ -0,0 +1,56 @@ +getContent(); + } + + public function applyInternalEffects($object, $value) { + $object->setContent($value); + } + + public function getTitle() { + return pht( + '%s updated the answer details.', + $this->renderAuthor()); + } + + public function getTitleForFeed() { + return pht( + '%s updated the answer details for %s.', + $this->renderAuthor(), + $this->renderObject()); + } + + public function hasChangeDetailView() { + return true; + } + + public function getMailDiffSectionHeader() { + return pht('CHANGES TO ANSWER DETAILS'); + } + + public function newChangeDetailView() { + $viewer = $this->getViewer(); + + return id(new PhabricatorApplicationTransactionTextDiffDetailView()) + ->setViewer($viewer) + ->setOldText($this->getOldValue()) + ->setNewText($this->getNewValue()); + } + + public function newRemarkupChanges() { + $changes = array(); + + $changes[] = $this->newRemarkupChange() + ->setOldValue($this->getOldValue()) + ->setNewValue($this->getNewValue()); + + return $changes; + } + +} diff --git a/src/applications/ponder/xaction/PonderAnswerQuestionIDTransaction.php b/src/applications/ponder/xaction/PonderAnswerQuestionIDTransaction.php new file mode 100644 index 0000000000..a66608479c --- /dev/null +++ b/src/applications/ponder/xaction/PonderAnswerQuestionIDTransaction.php @@ -0,0 +1,16 @@ +getQuestionID(); + } + + public function applyInternalEffects($object, $value) { + $object->setQuestionID($value); + } + +} diff --git a/src/applications/ponder/xaction/PonderAnswerStatusTransaction.php b/src/applications/ponder/xaction/PonderAnswerStatusTransaction.php new file mode 100644 index 0000000000..46a359aa5e --- /dev/null +++ b/src/applications/ponder/xaction/PonderAnswerStatusTransaction.php @@ -0,0 +1,62 @@ +getStatus(); + } + + public function applyInternalEffects($object, $value) { + $object->setStatus($value); + } + + public function getTitle() { + $new = $this->getNewValue(); + if ($new == PonderAnswerStatus::ANSWER_STATUS_VISIBLE) { + return pht( + '%s marked this answer as visible.', + $this->renderAuthor()); + } else if ($new == PonderAnswerStatus::ANSWER_STATUS_HIDDEN) { + return pht( + '%s marked this answer as hidden.', + $this->renderAuthor()); + } + } + + public function getTitleForFeed() { + $new = $this->getNewValue(); + if ($new == PonderAnswerStatus::ANSWER_STATUS_VISIBLE) { + return pht( + '%s marked %s as visible.', + $this->renderAuthor(), + $this->renderObject()); + } else if ($new == PonderAnswerStatus::ANSWER_STATUS_HIDDEN) { + return pht( + '%s marked %s as hidden.', + $this->renderAuthor(), + $this->renderObject()); + } + } + + public function getIcon() { + $new = $this->getNewValue(); + if ($new == PonderAnswerStatus::ANSWER_STATUS_VISIBLE) { + return 'fa-ban'; + } else if ($new == PonderAnswerStatus::ANSWER_STATUS_HIDDEN) { + return 'fa-check'; + } + } + + public function getColor() { + $new = $this->getNewValue(); + if ($new == PonderAnswerStatus::ANSWER_STATUS_VISIBLE) { + return 'green'; + } else if ($new == PonderAnswerStatus::ANSWER_STATUS_HIDDEN) { + return 'indigo'; + } + } + +} diff --git a/src/applications/ponder/xaction/PonderAnswerTransactionType.php b/src/applications/ponder/xaction/PonderAnswerTransactionType.php new file mode 100644 index 0000000000..84268f33b2 --- /dev/null +++ b/src/applications/ponder/xaction/PonderAnswerTransactionType.php @@ -0,0 +1,4 @@ + Date: Mon, 1 May 2017 15:19:00 -0700 Subject: [PATCH 10/25] Update Macro for Modular Transactions Summary: Overall, seems to work ok. Test Plan: - Add a Macro - Edit Macro - Use Macro - Disable Macro - Re-enable Macro - Attach Audio - Set Audio to loop - Annoy cats {F4932069} Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Differential Revision: https://secure.phabricator.com/D17813 --- src/__phutil_library_map__.php | 14 +- .../PhabricatorMacroAudioController.php | 5 +- .../PhabricatorMacroDisableController.php | 3 +- .../PhabricatorMacroEditController.php | 6 +- .../PhabricatorMacroViewController.php | 2 +- .../macro/editor/PhabricatorMacroEditor.php | 90 +----- .../storage/PhabricatorMacroTransaction.php | 289 +----------------- ...abricatorMacroAudioBehaviorTransaction.php | 69 +++++ .../PhabricatorMacroAudioTransaction.php | 56 ++++ .../PhabricatorMacroDisabledTransaction.php | 50 +++ .../PhabricatorMacroFileTransaction.php | 33 ++ .../PhabricatorMacroNameTransaction.php | 55 ++++ .../PhabricatorMacroTransactionType.php | 4 + 13 files changed, 295 insertions(+), 381 deletions(-) create mode 100644 src/applications/macro/xaction/PhabricatorMacroAudioBehaviorTransaction.php create mode 100644 src/applications/macro/xaction/PhabricatorMacroAudioTransaction.php create mode 100644 src/applications/macro/xaction/PhabricatorMacroDisabledTransaction.php create mode 100644 src/applications/macro/xaction/PhabricatorMacroFileTransaction.php create mode 100644 src/applications/macro/xaction/PhabricatorMacroNameTransaction.php create mode 100644 src/applications/macro/xaction/PhabricatorMacroTransactionType.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 1dc20b5019..86dd5a00d8 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -2972,26 +2972,32 @@ phutil_register_library_map(array( 'PhabricatorLogoutController' => 'applications/auth/controller/PhabricatorLogoutController.php', 'PhabricatorLunarPhasePolicyRule' => 'applications/policy/rule/PhabricatorLunarPhasePolicyRule.php', 'PhabricatorMacroApplication' => 'applications/macro/application/PhabricatorMacroApplication.php', + 'PhabricatorMacroAudioBehaviorTransaction' => 'applications/macro/xaction/PhabricatorMacroAudioBehaviorTransaction.php', 'PhabricatorMacroAudioController' => 'applications/macro/controller/PhabricatorMacroAudioController.php', + 'PhabricatorMacroAudioTransaction' => 'applications/macro/xaction/PhabricatorMacroAudioTransaction.php', 'PhabricatorMacroCommentController' => 'applications/macro/controller/PhabricatorMacroCommentController.php', 'PhabricatorMacroConfigOptions' => 'applications/macro/config/PhabricatorMacroConfigOptions.php', 'PhabricatorMacroController' => 'applications/macro/controller/PhabricatorMacroController.php', 'PhabricatorMacroDatasource' => 'applications/macro/typeahead/PhabricatorMacroDatasource.php', 'PhabricatorMacroDisableController' => 'applications/macro/controller/PhabricatorMacroDisableController.php', + 'PhabricatorMacroDisabledTransaction' => 'applications/macro/xaction/PhabricatorMacroDisabledTransaction.php', 'PhabricatorMacroEditController' => 'applications/macro/controller/PhabricatorMacroEditController.php', 'PhabricatorMacroEditor' => 'applications/macro/editor/PhabricatorMacroEditor.php', + 'PhabricatorMacroFileTransaction' => 'applications/macro/xaction/PhabricatorMacroFileTransaction.php', 'PhabricatorMacroListController' => 'applications/macro/controller/PhabricatorMacroListController.php', 'PhabricatorMacroMacroPHIDType' => 'applications/macro/phid/PhabricatorMacroMacroPHIDType.php', 'PhabricatorMacroMailReceiver' => 'applications/macro/mail/PhabricatorMacroMailReceiver.php', 'PhabricatorMacroManageCapability' => 'applications/macro/capability/PhabricatorMacroManageCapability.php', 'PhabricatorMacroMemeController' => 'applications/macro/controller/PhabricatorMacroMemeController.php', 'PhabricatorMacroMemeDialogController' => 'applications/macro/controller/PhabricatorMacroMemeDialogController.php', + 'PhabricatorMacroNameTransaction' => 'applications/macro/xaction/PhabricatorMacroNameTransaction.php', 'PhabricatorMacroQuery' => 'applications/macro/query/PhabricatorMacroQuery.php', 'PhabricatorMacroReplyHandler' => 'applications/macro/mail/PhabricatorMacroReplyHandler.php', 'PhabricatorMacroSearchEngine' => 'applications/macro/query/PhabricatorMacroSearchEngine.php', 'PhabricatorMacroTransaction' => 'applications/macro/storage/PhabricatorMacroTransaction.php', 'PhabricatorMacroTransactionComment' => 'applications/macro/storage/PhabricatorMacroTransactionComment.php', 'PhabricatorMacroTransactionQuery' => 'applications/macro/query/PhabricatorMacroTransactionQuery.php', + 'PhabricatorMacroTransactionType' => 'applications/macro/xaction/PhabricatorMacroTransactionType.php', 'PhabricatorMacroViewController' => 'applications/macro/controller/PhabricatorMacroViewController.php', 'PhabricatorMailEmailHeraldField' => 'applications/metamta/herald/PhabricatorMailEmailHeraldField.php', 'PhabricatorMailEmailHeraldFieldGroup' => 'applications/metamta/herald/PhabricatorMailEmailHeraldFieldGroup.php', @@ -8162,26 +8168,32 @@ phutil_register_library_map(array( 'PhabricatorLogoutController' => 'PhabricatorAuthController', 'PhabricatorLunarPhasePolicyRule' => 'PhabricatorPolicyRule', 'PhabricatorMacroApplication' => 'PhabricatorApplication', + 'PhabricatorMacroAudioBehaviorTransaction' => 'PhabricatorMacroTransactionType', 'PhabricatorMacroAudioController' => 'PhabricatorMacroController', + 'PhabricatorMacroAudioTransaction' => 'PhabricatorMacroTransactionType', 'PhabricatorMacroCommentController' => 'PhabricatorMacroController', 'PhabricatorMacroConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorMacroController' => 'PhabricatorController', 'PhabricatorMacroDatasource' => 'PhabricatorTypeaheadDatasource', 'PhabricatorMacroDisableController' => 'PhabricatorMacroController', + 'PhabricatorMacroDisabledTransaction' => 'PhabricatorMacroTransactionType', 'PhabricatorMacroEditController' => 'PhabricatorMacroController', 'PhabricatorMacroEditor' => 'PhabricatorApplicationTransactionEditor', + 'PhabricatorMacroFileTransaction' => 'PhabricatorMacroTransactionType', 'PhabricatorMacroListController' => 'PhabricatorMacroController', 'PhabricatorMacroMacroPHIDType' => 'PhabricatorPHIDType', 'PhabricatorMacroMailReceiver' => 'PhabricatorObjectMailReceiver', 'PhabricatorMacroManageCapability' => 'PhabricatorPolicyCapability', 'PhabricatorMacroMemeController' => 'PhabricatorMacroController', 'PhabricatorMacroMemeDialogController' => 'PhabricatorMacroController', + 'PhabricatorMacroNameTransaction' => 'PhabricatorMacroTransactionType', 'PhabricatorMacroQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorMacroReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler', 'PhabricatorMacroSearchEngine' => 'PhabricatorApplicationSearchEngine', - 'PhabricatorMacroTransaction' => 'PhabricatorApplicationTransaction', + 'PhabricatorMacroTransaction' => 'PhabricatorModularTransaction', 'PhabricatorMacroTransactionComment' => 'PhabricatorApplicationTransactionComment', 'PhabricatorMacroTransactionQuery' => 'PhabricatorApplicationTransactionQuery', + 'PhabricatorMacroTransactionType' => 'PhabricatorModularTransactionType', 'PhabricatorMacroViewController' => 'PhabricatorMacroController', 'PhabricatorMailEmailHeraldField' => 'HeraldField', 'PhabricatorMailEmailHeraldFieldGroup' => 'HeraldFieldGroup', diff --git a/src/applications/macro/controller/PhabricatorMacroAudioController.php b/src/applications/macro/controller/PhabricatorMacroAudioController.php index 7e2b924637..382c82ae3a 100644 --- a/src/applications/macro/controller/PhabricatorMacroAudioController.php +++ b/src/applications/macro/controller/PhabricatorMacroAudioController.php @@ -34,7 +34,7 @@ final class PhabricatorMacroAudioController extends PhabricatorMacroController { if ($request->getBool('behaviorForm')) { $xactions[] = id(new PhabricatorMacroTransaction()) ->setTransactionType( - PhabricatorMacroTransaction::TYPE_AUDIO_BEHAVIOR) + PhabricatorMacroAudioBehaviorTransaction::TRANSACTIONTYPE) ->setNewValue($request->getStr('audioBehavior')); } else { $file = null; @@ -54,7 +54,8 @@ final class PhabricatorMacroAudioController extends PhabricatorMacroController { $e_file = pht('Invalid'); } else { $xactions[] = id(new PhabricatorMacroTransaction()) - ->setTransactionType(PhabricatorMacroTransaction::TYPE_AUDIO) + ->setTransactionType( + PhabricatorMacroAudioTransaction::TRANSACTIONTYPE) ->setNewValue($file->getPHID()); } } else { diff --git a/src/applications/macro/controller/PhabricatorMacroDisableController.php b/src/applications/macro/controller/PhabricatorMacroDisableController.php index a9868647f0..6c74e44442 100644 --- a/src/applications/macro/controller/PhabricatorMacroDisableController.php +++ b/src/applications/macro/controller/PhabricatorMacroDisableController.php @@ -22,7 +22,8 @@ final class PhabricatorMacroDisableController if ($request->isDialogFormPost() || $macro->getIsDisabled()) { $xaction = id(new PhabricatorMacroTransaction()) - ->setTransactionType(PhabricatorMacroTransaction::TYPE_DISABLED) + ->setTransactionType( + PhabricatorMacroDisabledTransaction::TRANSACTIONTYPE) ->setNewValue($macro->getIsDisabled() ? 0 : 1); $editor = id(new PhabricatorMacroEditor()) diff --git a/src/applications/macro/controller/PhabricatorMacroEditController.php b/src/applications/macro/controller/PhabricatorMacroEditController.php index 110296c172..fc84e057ae 100644 --- a/src/applications/macro/controller/PhabricatorMacroEditController.php +++ b/src/applications/macro/controller/PhabricatorMacroEditController.php @@ -135,13 +135,15 @@ final class PhabricatorMacroEditController extends PhabricatorMacroController { if ($new_name !== null) { $xactions[] = id(new PhabricatorMacroTransaction()) - ->setTransactionType(PhabricatorMacroTransaction::TYPE_NAME) + ->setTransactionType( + PhabricatorMacroNameTransaction::TRANSACTIONTYPE) ->setNewValue($new_name); } if ($file) { $xactions[] = id(new PhabricatorMacroTransaction()) - ->setTransactionType(PhabricatorMacroTransaction::TYPE_FILE) + ->setTransactionType( + PhabricatorMacroFileTransaction::TRANSACTIONTYPE) ->setNewValue($file->getPHID()); } diff --git a/src/applications/macro/controller/PhabricatorMacroViewController.php b/src/applications/macro/controller/PhabricatorMacroViewController.php index 386029c7ce..032d2228a9 100644 --- a/src/applications/macro/controller/PhabricatorMacroViewController.php +++ b/src/applications/macro/controller/PhabricatorMacroViewController.php @@ -45,7 +45,7 @@ final class PhabricatorMacroViewController if (!$macro->getIsDisabled()) { $header->setStatus('fa-check', 'bluegrey', pht('Active')); } else { - $header->setStatus('fa-ban', 'red', pht('Archived')); + $header->setStatus('fa-ban', 'indigo', pht('Archived')); } $is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business'); diff --git a/src/applications/macro/editor/PhabricatorMacroEditor.php b/src/applications/macro/editor/PhabricatorMacroEditor.php index 1bb139a4de..797fa702a9 100644 --- a/src/applications/macro/editor/PhabricatorMacroEditor.php +++ b/src/applications/macro/editor/PhabricatorMacroEditor.php @@ -13,79 +13,18 @@ final class PhabricatorMacroEditor public function getTransactionTypes() { $types = parent::getTransactionTypes(); - $types[] = PhabricatorTransactions::TYPE_COMMENT; - $types[] = PhabricatorMacroTransaction::TYPE_NAME; - $types[] = PhabricatorMacroTransaction::TYPE_DISABLED; - $types[] = PhabricatorMacroTransaction::TYPE_FILE; - $types[] = PhabricatorMacroTransaction::TYPE_AUDIO; - $types[] = PhabricatorMacroTransaction::TYPE_AUDIO_BEHAVIOR; return $types; } - protected function getCustomTransactionOldValue( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case PhabricatorMacroTransaction::TYPE_NAME: - return $object->getName(); - case PhabricatorMacroTransaction::TYPE_DISABLED: - return $object->getIsDisabled(); - case PhabricatorMacroTransaction::TYPE_FILE: - return $object->getFilePHID(); - case PhabricatorMacroTransaction::TYPE_AUDIO: - return $object->getAudioPHID(); - case PhabricatorMacroTransaction::TYPE_AUDIO_BEHAVIOR: - return $object->getAudioBehavior(); - } - } - - protected function getCustomTransactionNewValue( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case PhabricatorMacroTransaction::TYPE_NAME: - case PhabricatorMacroTransaction::TYPE_DISABLED: - case PhabricatorMacroTransaction::TYPE_FILE: - case PhabricatorMacroTransaction::TYPE_AUDIO: - case PhabricatorMacroTransaction::TYPE_AUDIO_BEHAVIOR: - return $xaction->getNewValue(); - } - } - - protected function applyCustomInternalTransaction( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case PhabricatorMacroTransaction::TYPE_NAME: - $object->setName($xaction->getNewValue()); - break; - case PhabricatorMacroTransaction::TYPE_DISABLED: - $object->setIsDisabled($xaction->getNewValue()); - break; - case PhabricatorMacroTransaction::TYPE_FILE: - $object->setFilePHID($xaction->getNewValue()); - break; - case PhabricatorMacroTransaction::TYPE_AUDIO: - $object->setAudioPHID($xaction->getNewValue()); - break; - case PhabricatorMacroTransaction::TYPE_AUDIO_BEHAVIOR: - $object->setAudioBehavior($xaction->getNewValue()); - break; - } - } - protected function applyCustomExternalTransaction( PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction) { switch ($xaction->getTransactionType()) { - case PhabricatorMacroTransaction::TYPE_FILE: - case PhabricatorMacroTransaction::TYPE_AUDIO: + case PhabricatorMacroFileTransaction::TRANSACTIONTYPE: + case PhabricatorMacroAudioTransaction::TRANSACTIONTYPE: // When changing a macro's image or audio, attach the underlying files // to the macro (and detach the old files). $old = $xaction->getOldValue(); @@ -117,34 +56,9 @@ final class PhabricatorMacroEditor } } - protected function mergeTransactions( - PhabricatorApplicationTransaction $u, - PhabricatorApplicationTransaction $v) { - - $type = $u->getTransactionType(); - switch ($type) { - case PhabricatorMacroTransaction::TYPE_NAME: - case PhabricatorMacroTransaction::TYPE_DISABLED: - case PhabricatorMacroTransaction::TYPE_FILE: - case PhabricatorMacroTransaction::TYPE_AUDIO: - case PhabricatorMacroTransaction::TYPE_AUDIO_BEHAVIOR: - return $v; - } - - return parent::mergeTransactions($u, $v); - } - protected function shouldSendMail( PhabricatorLiskDAO $object, array $xactions) { - foreach ($xactions as $xaction) { - switch ($xaction->getTransactionType()) { - case PhabricatorMacroTransaction::TYPE_NAME; - return ($xaction->getOldValue() !== null); - default: - break; - } - } return true; } diff --git a/src/applications/macro/storage/PhabricatorMacroTransaction.php b/src/applications/macro/storage/PhabricatorMacroTransaction.php index 46eb932476..3a15b4c15d 100644 --- a/src/applications/macro/storage/PhabricatorMacroTransaction.php +++ b/src/applications/macro/storage/PhabricatorMacroTransaction.php @@ -1,14 +1,7 @@ getOldValue(); - $new = $this->getNewValue(); - - switch ($this->getTransactionType()) { - case self::TYPE_FILE: - case self::TYPE_AUDIO: - if ($old !== null) { - $phids[] = $old; - } - $phids[] = $new; - break; - } - - return $phids; - } - - public function shouldHide() { - $old = $this->getOldValue(); - $new = $this->getNewValue(); - - switch ($this->getTransactionType()) { - case self::TYPE_NAME: - return ($old === null); - } - - return parent::shouldHide(); - } - - public function getTitle() { - $author_phid = $this->getAuthorPHID(); - - $old = $this->getOldValue(); - $new = $this->getNewValue(); - - switch ($this->getTransactionType()) { - case self::TYPE_NAME: - return pht( - '%s renamed this macro from "%s" to "%s".', - $this->renderHandleLink($author_phid), - $old, - $new); - break; - case self::TYPE_DISABLED: - if ($new) { - return pht( - '%s disabled this macro.', - $this->renderHandleLink($author_phid)); - } else { - return pht( - '%s restored this macro.', - $this->renderHandleLink($author_phid)); - } - break; - - case self::TYPE_AUDIO: - if (!$old) { - return pht( - '%s attached audio: %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($new)); - } else { - return pht( - '%s changed the audio for this macro from %s to %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($old), - $this->renderHandleLink($new)); - } - - case self::TYPE_AUDIO_BEHAVIOR: - switch ($new) { - case PhabricatorFileImageMacro::AUDIO_BEHAVIOR_ONCE: - return pht( - '%s set the audio to play once.', - $this->renderHandleLink($author_phid)); - case PhabricatorFileImageMacro::AUDIO_BEHAVIOR_LOOP: - return pht( - '%s set the audio to loop.', - $this->renderHandleLink($author_phid)); - default: - return pht( - '%s disabled the audio for this macro.', - $this->renderHandleLink($author_phid)); - } - - case self::TYPE_FILE: - if ($old === null) { - return pht( - '%s created this macro.', - $this->renderHandleLink($author_phid)); - } else { - return pht( - '%s changed the image for this macro from %s to %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($old), - $this->renderHandleLink($new)); - } - break; - } - - return parent::getTitle(); - } - - public function getTitleForFeed() { - $author_phid = $this->getAuthorPHID(); - $object_phid = $this->getObjectPHID(); - - $old = $this->getOldValue(); - $new = $this->getNewValue(); - - switch ($this->getTransactionType()) { - case self::TYPE_NAME: - return pht( - '%s renamed %s from "%s" to "%s".', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid), - $old, - $new); - case self::TYPE_DISABLED: - if ($new) { - return pht( - '%s disabled %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - } else { - return pht( - '%s restored %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - } - case self::TYPE_FILE: - if ($old === null) { - return pht( - '%s created %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - } else { - return pht( - '%s updated the image for %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - } - - case self::TYPE_AUDIO: - if (!$old) { - return pht( - '%s attached audio to %s: %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid), - $this->renderHandleLink($new)); - } else { - return pht( - '%s changed the audio for %s from %s to %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid), - $this->renderHandleLink($old), - $this->renderHandleLink($new)); - } - - case self::TYPE_AUDIO_BEHAVIOR: - switch ($new) { - case PhabricatorFileImageMacro::AUDIO_BEHAVIOR_ONCE: - return pht( - '%s set the audio for %s to play once.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - case PhabricatorFileImageMacro::AUDIO_BEHAVIOR_LOOP: - return pht( - '%s set the audio for %s to loop.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - default: - return pht( - '%s disabled the audio for %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - } - - } - - return parent::getTitleForFeed(); - } - - public function getActionName() { - $old = $this->getOldValue(); - $new = $this->getNewValue(); - - switch ($this->getTransactionType()) { - case self::TYPE_NAME: - if ($old === null) { - return pht('Created'); - } else { - return pht('Renamed'); - } - case self::TYPE_DISABLED: - if ($new) { - return pht('Disabled'); - } else { - return pht('Restored'); - } - case self::TYPE_FILE: - if ($old === null) { - return pht('Created'); - } else { - return pht('Edited Image'); - } - - case self::TYPE_AUDIO: - return pht('Audio'); - - case self::TYPE_AUDIO_BEHAVIOR: - return pht('Audio Behavior'); - - } - - return parent::getActionName(); - } - - public function getActionStrength() { - switch ($this->getTransactionType()) { - case self::TYPE_DISABLED: - return 2.0; - case self::TYPE_FILE: - return 1.5; - } - return parent::getActionStrength(); - } - - public function getIcon() { - $old = $this->getOldValue(); - $new = $this->getNewValue(); - - switch ($this->getTransactionType()) { - case self::TYPE_NAME: - return 'fa-pencil'; - case self::TYPE_FILE: - if ($old === null) { - return 'fa-plus'; - } else { - return 'fa-pencil'; - } - case self::TYPE_DISABLED: - if ($new) { - return 'fa-times'; - } else { - return 'fa-undo'; - } - case self::TYPE_AUDIO: - return 'fa-headphones'; - } - - return parent::getIcon(); - } - - public function getColor() { - $old = $this->getOldValue(); - $new = $this->getNewValue(); - - switch ($this->getTransactionType()) { - case self::TYPE_NAME: - return PhabricatorTransactions::COLOR_BLUE; - case self::TYPE_FILE: - if ($old === null) { - return PhabricatorTransactions::COLOR_GREEN; - } else { - return PhabricatorTransactions::COLOR_BLUE; - } - case self::TYPE_DISABLED: - if ($new) { - return PhabricatorTransactions::COLOR_RED; - } else { - return PhabricatorTransactions::COLOR_SKY; - } - } - - return parent::getColor(); + public function getBaseTransactionClass() { + return 'PhabricatorMacroTransactionType'; } diff --git a/src/applications/macro/xaction/PhabricatorMacroAudioBehaviorTransaction.php b/src/applications/macro/xaction/PhabricatorMacroAudioBehaviorTransaction.php new file mode 100644 index 0000000000..e27e9081ed --- /dev/null +++ b/src/applications/macro/xaction/PhabricatorMacroAudioBehaviorTransaction.php @@ -0,0 +1,69 @@ +getAudioBehavior(); + } + + public function applyInternalEffects($object, $value) { + $object->setAudioBehavior($value); + } + + public function getTitle() { + $new = $this->getNewValue(); + $old = $this->getOldValue(); + switch ($new) { + case PhabricatorFileImageMacro::AUDIO_BEHAVIOR_ONCE: + return pht( + '%s set the audio to play once.', + $this->renderAuthor()); + case PhabricatorFileImageMacro::AUDIO_BEHAVIOR_LOOP: + return pht( + '%s set the audio to loop.', + $this->renderAuthor()); + default: + return pht( + '%s disabled the audio for this macro.', + $this->renderAuthor()); + } + } + + public function getTitleForFeed() { + $new = $this->getNewValue(); + $old = $this->getOldValue(); + switch ($new) { + case PhabricatorFileImageMacro::AUDIO_BEHAVIOR_ONCE: + return pht( + '%s set the audio for %s to play once.', + $this->renderAuthor(), + $this->renderObject()); + case PhabricatorFileImageMacro::AUDIO_BEHAVIOR_LOOP: + return pht( + '%s set the audio for %s to loop.', + $this->renderAuthor(), + $this->renderObject()); + default: + return pht( + '%s disabled the audio for %s.', + $this->renderAuthor(), + $this->renderObject()); + } + } + + public function getIcon() { + $new = $this->getNewValue(); + switch ($new) { + case PhabricatorFileImageMacro::AUDIO_BEHAVIOR_ONCE: + return 'fa-play-circle'; + case PhabricatorFileImageMacro::AUDIO_BEHAVIOR_LOOP: + return 'fa-repeat'; + default: + return 'fa-pause-circle'; + } + } + +} diff --git a/src/applications/macro/xaction/PhabricatorMacroAudioTransaction.php b/src/applications/macro/xaction/PhabricatorMacroAudioTransaction.php new file mode 100644 index 0000000000..aacf9f4016 --- /dev/null +++ b/src/applications/macro/xaction/PhabricatorMacroAudioTransaction.php @@ -0,0 +1,56 @@ +getAudioPHID(); + } + + public function applyInternalEffects($object, $value) { + $object->setAudioPHID($value); + } + + public function getTitle() { + $new = $this->getNewValue(); + $old = $this->getOldValue(); + if (!$old) { + return pht( + '%s attached audio: %s.', + $this->renderAuthor(), + $this->renderHandle($new)); + } else { + return pht( + '%s changed the audio for this macro from %s to %s.', + $this->renderAuthor(), + $this->renderHandle($old), + $this->renderHandle($new)); + } + } + + public function getTitleForFeed() { + $new = $this->getNewValue(); + $old = $this->getOldValue(); + if (!$old) { + return pht( + '%s attached audio to %s: %s.', + $this->renderAuthor(), + $this->renderObject(), + $this->renderHandle($new)); + } else { + return pht( + '%s changed the audio for %s from %s to %s.', + $this->renderAuthor(), + $this->renderObject(), + $this->renderHandle($old), + $this->renderHandle($new)); + } + } + + public function getIcon() { + return 'fa-music'; + } + +} diff --git a/src/applications/macro/xaction/PhabricatorMacroDisabledTransaction.php b/src/applications/macro/xaction/PhabricatorMacroDisabledTransaction.php new file mode 100644 index 0000000000..334dc9ef6f --- /dev/null +++ b/src/applications/macro/xaction/PhabricatorMacroDisabledTransaction.php @@ -0,0 +1,50 @@ +getIsDisabled(); + } + + public function applyInternalEffects($object, $value) { + $object->setIsDisabled($value); + } + + public function getTitle() { + if ($this->getNewValue()) { + return pht( + '%s disabled this macro.', + $this->renderAuthor()); + } else { + return pht( + '%s restored this macro.', + $this->renderAuthor()); + } + } + + public function getTitleForFeed() { + if ($this->getNewValue()) { + return pht( + '%s disabled %s.', + $this->renderAuthor(), + $this->renderObject()); + } else { + return pht( + '%s restored %s.', + $this->renderAuthor(), + $this->renderObject()); + } + } + + public function getIcon() { + if ($this->getNewValue()) { + return 'fa-ban'; + } else { + return 'fa-check'; + } + } + +} diff --git a/src/applications/macro/xaction/PhabricatorMacroFileTransaction.php b/src/applications/macro/xaction/PhabricatorMacroFileTransaction.php new file mode 100644 index 0000000000..40e51fe1df --- /dev/null +++ b/src/applications/macro/xaction/PhabricatorMacroFileTransaction.php @@ -0,0 +1,33 @@ +getFilePHID(); + } + + public function applyInternalEffects($object, $value) { + $object->setFilePHID($value); + } + + public function getTitle() { + return pht( + '%s changed the image for this macro.', + $this->renderAuthor()); + } + + public function getTitleForFeed() { + return pht( + '%s changed the image for macro %s.', + $this->renderAuthor(), + $this->renderObject()); + } + + public function getIcon() { + return 'fa-file-image-o'; + } + +} diff --git a/src/applications/macro/xaction/PhabricatorMacroNameTransaction.php b/src/applications/macro/xaction/PhabricatorMacroNameTransaction.php new file mode 100644 index 0000000000..ebd81530f5 --- /dev/null +++ b/src/applications/macro/xaction/PhabricatorMacroNameTransaction.php @@ -0,0 +1,55 @@ +getName(); + } + + public function applyInternalEffects($object, $value) { + $object->setName($value); + } + + public function getTitle() { + return pht( + '%s renamed this macro from %s to %s.', + $this->renderAuthor(), + $this->renderOldValue(), + $this->renderNewValue()); + } + + public function getTitleForFeed() { + return pht( + '%s renamed %s macro %s to %s.', + $this->renderAuthor(), + $this->renderObject(), + $this->renderOldValue(), + $this->renderNewValue()); + } + + public function validateTransactions($object, array $xactions) { + $errors = array(); + + if ($this->isEmptyTextTransaction($object->getName(), $xactions)) { + $errors[] = $this->newRequiredError( + pht('Macros must have a name.')); + } + + $max_length = $object->getColumnMaximumByteLength('name'); + foreach ($xactions as $xaction) { + $new_value = $xaction->getNewValue(); + $new_length = strlen($new_value); + if ($new_length > $max_length) { + $errors[] = $this->newInvalidError( + pht('The name can be no longer than %s characters.', + new PhutilNumber($max_length))); + } + } + + return $errors; + } + +} diff --git a/src/applications/macro/xaction/PhabricatorMacroTransactionType.php b/src/applications/macro/xaction/PhabricatorMacroTransactionType.php new file mode 100644 index 0000000000..6a8e98c05b --- /dev/null +++ b/src/applications/macro/xaction/PhabricatorMacroTransactionType.php @@ -0,0 +1,4 @@ + Date: Tue, 2 May 2017 15:11:54 -0700 Subject: [PATCH 11/25] Modernize PhameBlog with modular transactions Summary: Moves PhameBlog over to the wonderful world of modular transactions and the riches that lay beyond... Test Plan: - Create Blog - Edit Blog - Set Header - Delete Header - Add picture - Archive blog - Set incorrect domain values - Be irresponsible with subtitle length - Activate blog - Change description Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Differential Revision: https://secure.phabricator.com/D17815 --- src/__phutil_library_map__.php | 22 +- .../blog/PhameBlogArchiveController.php | 2 +- .../blog/PhameBlogHeaderPictureController.php | 2 +- .../PhameBlogProfilePictureController.php | 3 +- .../phame/editor/PhameBlogEditEngine.php | 14 +- .../phame/editor/PhameBlogEditor.php | 245 +------------ src/applications/phame/storage/PhameBlog.php | 44 +-- .../phame/storage/PhameBlogTransaction.php | 327 +----------------- .../PhameBlogDescriptionTransaction.php | 60 ++++ .../PhameBlogFullDomainTransaction.php | 95 +++++ .../PhameBlogHeaderImageTransaction.php | 34 ++ .../xaction/PhameBlogNameTransaction.php | 59 ++++ .../PhameBlogParentDomainTransaction.php | 82 +++++ .../PhameBlogParentSiteTransaction.php | 66 ++++ .../PhameBlogProfileImageTransaction.php | 34 ++ .../xaction/PhameBlogStatusTransaction.php | 55 +++ .../xaction/PhameBlogSubtitleTransaction.php | 63 ++++ .../xaction/PhameBlogTransactionType.php | 4 + 18 files changed, 611 insertions(+), 600 deletions(-) create mode 100644 src/applications/phame/xaction/PhameBlogDescriptionTransaction.php create mode 100644 src/applications/phame/xaction/PhameBlogFullDomainTransaction.php create mode 100644 src/applications/phame/xaction/PhameBlogHeaderImageTransaction.php create mode 100644 src/applications/phame/xaction/PhameBlogNameTransaction.php create mode 100644 src/applications/phame/xaction/PhameBlogParentDomainTransaction.php create mode 100644 src/applications/phame/xaction/PhameBlogParentSiteTransaction.php create mode 100644 src/applications/phame/xaction/PhameBlogProfileImageTransaction.php create mode 100644 src/applications/phame/xaction/PhameBlogStatusTransaction.php create mode 100644 src/applications/phame/xaction/PhameBlogSubtitleTransaction.php create mode 100644 src/applications/phame/xaction/PhameBlogTransactionType.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 86dd5a00d8..0c71c8eab1 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -4232,24 +4232,34 @@ phutil_register_library_map(array( 'PhameBlogController' => 'applications/phame/controller/blog/PhameBlogController.php', 'PhameBlogCreateCapability' => 'applications/phame/capability/PhameBlogCreateCapability.php', 'PhameBlogDatasource' => 'applications/phame/typeahead/PhameBlogDatasource.php', + 'PhameBlogDescriptionTransaction' => 'applications/phame/xaction/PhameBlogDescriptionTransaction.php', 'PhameBlogEditConduitAPIMethod' => 'applications/phame/conduit/PhameBlogEditConduitAPIMethod.php', 'PhameBlogEditController' => 'applications/phame/controller/blog/PhameBlogEditController.php', 'PhameBlogEditEngine' => 'applications/phame/editor/PhameBlogEditEngine.php', 'PhameBlogEditor' => 'applications/phame/editor/PhameBlogEditor.php', 'PhameBlogFeedController' => 'applications/phame/controller/blog/PhameBlogFeedController.php', + 'PhameBlogFullDomainTransaction' => 'applications/phame/xaction/PhameBlogFullDomainTransaction.php', 'PhameBlogFulltextEngine' => 'applications/phame/search/PhameBlogFulltextEngine.php', + 'PhameBlogHeaderImageTransaction' => 'applications/phame/xaction/PhameBlogHeaderImageTransaction.php', 'PhameBlogHeaderPictureController' => 'applications/phame/controller/blog/PhameBlogHeaderPictureController.php', 'PhameBlogListController' => 'applications/phame/controller/blog/PhameBlogListController.php', 'PhameBlogListView' => 'applications/phame/view/PhameBlogListView.php', 'PhameBlogManageController' => 'applications/phame/controller/blog/PhameBlogManageController.php', + 'PhameBlogNameTransaction' => 'applications/phame/xaction/PhameBlogNameTransaction.php', + 'PhameBlogParentDomainTransaction' => 'applications/phame/xaction/PhameBlogParentDomainTransaction.php', + 'PhameBlogParentSiteTransaction' => 'applications/phame/xaction/PhameBlogParentSiteTransaction.php', + 'PhameBlogProfileImageTransaction' => 'applications/phame/xaction/PhameBlogProfileImageTransaction.php', 'PhameBlogProfilePictureController' => 'applications/phame/controller/blog/PhameBlogProfilePictureController.php', 'PhameBlogQuery' => 'applications/phame/query/PhameBlogQuery.php', 'PhameBlogReplyHandler' => 'applications/phame/mail/PhameBlogReplyHandler.php', 'PhameBlogSearchConduitAPIMethod' => 'applications/phame/conduit/PhameBlogSearchConduitAPIMethod.php', 'PhameBlogSearchEngine' => 'applications/phame/query/PhameBlogSearchEngine.php', 'PhameBlogSite' => 'applications/phame/site/PhameBlogSite.php', + 'PhameBlogStatusTransaction' => 'applications/phame/xaction/PhameBlogStatusTransaction.php', + 'PhameBlogSubtitleTransaction' => 'applications/phame/xaction/PhameBlogSubtitleTransaction.php', 'PhameBlogTransaction' => 'applications/phame/storage/PhameBlogTransaction.php', 'PhameBlogTransactionQuery' => 'applications/phame/query/PhameBlogTransactionQuery.php', + 'PhameBlogTransactionType' => 'applications/phame/xaction/PhameBlogTransactionType.php', 'PhameBlogViewController' => 'applications/phame/controller/blog/PhameBlogViewController.php', 'PhameConstants' => 'applications/phame/constants/PhameConstants.php', 'PhameController' => 'applications/phame/controller/PhameController.php', @@ -9690,24 +9700,34 @@ phutil_register_library_map(array( 'PhameBlogController' => 'PhameController', 'PhameBlogCreateCapability' => 'PhabricatorPolicyCapability', 'PhameBlogDatasource' => 'PhabricatorTypeaheadDatasource', + 'PhameBlogDescriptionTransaction' => 'PhameBlogTransactionType', 'PhameBlogEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod', 'PhameBlogEditController' => 'PhameBlogController', 'PhameBlogEditEngine' => 'PhabricatorEditEngine', 'PhameBlogEditor' => 'PhabricatorApplicationTransactionEditor', 'PhameBlogFeedController' => 'PhameBlogController', + 'PhameBlogFullDomainTransaction' => 'PhameBlogTransactionType', 'PhameBlogFulltextEngine' => 'PhabricatorFulltextEngine', + 'PhameBlogHeaderImageTransaction' => 'PhameBlogTransactionType', 'PhameBlogHeaderPictureController' => 'PhameBlogController', 'PhameBlogListController' => 'PhameBlogController', 'PhameBlogListView' => 'AphrontTagView', 'PhameBlogManageController' => 'PhameBlogController', + 'PhameBlogNameTransaction' => 'PhameBlogTransactionType', + 'PhameBlogParentDomainTransaction' => 'PhameBlogTransactionType', + 'PhameBlogParentSiteTransaction' => 'PhameBlogTransactionType', + 'PhameBlogProfileImageTransaction' => 'PhameBlogTransactionType', 'PhameBlogProfilePictureController' => 'PhameBlogController', 'PhameBlogQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhameBlogReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler', 'PhameBlogSearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod', 'PhameBlogSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhameBlogSite' => 'PhameSite', - 'PhameBlogTransaction' => 'PhabricatorApplicationTransaction', + 'PhameBlogStatusTransaction' => 'PhameBlogTransactionType', + 'PhameBlogSubtitleTransaction' => 'PhameBlogTransactionType', + 'PhameBlogTransaction' => 'PhabricatorModularTransaction', 'PhameBlogTransactionQuery' => 'PhabricatorApplicationTransactionQuery', + 'PhameBlogTransactionType' => 'PhabricatorModularTransactionType', 'PhameBlogViewController' => 'PhameLiveController', 'PhameConstants' => 'Phobject', 'PhameController' => 'PhabricatorController', diff --git a/src/applications/phame/controller/blog/PhameBlogArchiveController.php b/src/applications/phame/controller/blog/PhameBlogArchiveController.php index 4c8d4a4a63..8b63bad9ff 100644 --- a/src/applications/phame/controller/blog/PhameBlogArchiveController.php +++ b/src/applications/phame/controller/blog/PhameBlogArchiveController.php @@ -32,7 +32,7 @@ final class PhameBlogArchiveController $xactions = array(); $xactions[] = id(new PhameBlogTransaction()) - ->setTransactionType(PhameBlogTransaction::TYPE_STATUS) + ->setTransactionType(PhameBlogStatusTransaction::TRANSACTIONTYPE) ->setNewValue($new_status); id(new PhameBlogEditor()) diff --git a/src/applications/phame/controller/blog/PhameBlogHeaderPictureController.php b/src/applications/phame/controller/blog/PhameBlogHeaderPictureController.php index ab026fecbf..0106b9571d 100644 --- a/src/applications/phame/controller/blog/PhameBlogHeaderPictureController.php +++ b/src/applications/phame/controller/blog/PhameBlogHeaderPictureController.php @@ -61,7 +61,7 @@ final class PhameBlogHeaderPictureController $xactions = array(); $xactions[] = id(new PhameBlogTransaction()) - ->setTransactionType(PhameBlogTransaction::TYPE_HEADERIMAGE) + ->setTransactionType(PhameBlogHeaderImageTransaction::TRANSACTIONTYPE) ->setNewValue($new_value); $editor = id(new PhameBlogEditor()) diff --git a/src/applications/phame/controller/blog/PhameBlogProfilePictureController.php b/src/applications/phame/controller/blog/PhameBlogProfilePictureController.php index 3368046414..04b41dbb79 100644 --- a/src/applications/phame/controller/blog/PhameBlogProfilePictureController.php +++ b/src/applications/phame/controller/blog/PhameBlogProfilePictureController.php @@ -76,7 +76,8 @@ final class PhameBlogProfilePictureController $xactions = array(); $xactions[] = id(new PhameBlogTransaction()) - ->setTransactionType(PhameBlogTransaction::TYPE_PROFILEIMAGE) + ->setTransactionType( + PhameBlogProfileImageTransaction::TRANSACTIONTYPE) ->setNewValue($new_value); $editor = id(new PhameBlogEditor()) diff --git a/src/applications/phame/editor/PhameBlogEditEngine.php b/src/applications/phame/editor/PhameBlogEditEngine.php index 7d6511d55c..6d6c0a9f77 100644 --- a/src/applications/phame/editor/PhameBlogEditEngine.php +++ b/src/applications/phame/editor/PhameBlogEditEngine.php @@ -75,7 +75,7 @@ final class PhameBlogEditEngine ->setDescription(pht('Blog name.')) ->setConduitDescription(pht('Retitle the blog.')) ->setConduitTypeDescription(pht('New blog title.')) - ->setTransactionType(PhameBlogTransaction::TYPE_NAME) + ->setTransactionType(PhameBlogNameTransaction::TRANSACTIONTYPE) ->setValue($object->getName()), id(new PhabricatorTextEditField()) ->setKey('subtitle') @@ -83,7 +83,7 @@ final class PhameBlogEditEngine ->setDescription(pht('Blog subtitle.')) ->setConduitDescription(pht('Change the blog subtitle.')) ->setConduitTypeDescription(pht('New blog subtitle.')) - ->setTransactionType(PhameBlogTransaction::TYPE_SUBTITLE) + ->setTransactionType(PhameBlogSubtitleTransaction::TRANSACTIONTYPE) ->setValue($object->getSubtitle()), id(new PhabricatorRemarkupEditField()) ->setKey('description') @@ -91,7 +91,7 @@ final class PhameBlogEditEngine ->setDescription(pht('Blog description.')) ->setConduitDescription(pht('Change the blog description.')) ->setConduitTypeDescription(pht('New blog description.')) - ->setTransactionType(PhameBlogTransaction::TYPE_DESCRIPTION) + ->setTransactionType(PhameBlogDescriptionTransaction::TRANSACTIONTYPE) ->setValue($object->getDescription()), id(new PhabricatorTextEditField()) ->setKey('domainFullURI') @@ -104,7 +104,7 @@ final class PhameBlogEditEngine ->setConduitDescription(pht('Change the blog full domain URI.')) ->setConduitTypeDescription(pht('New blog full domain URI.')) ->setValue($object->getDomainFullURI()) - ->setTransactionType(PhameBlogTransaction::TYPE_FULLDOMAIN), + ->setTransactionType(PhameBlogFullDomainTransaction::TRANSACTIONTYPE), id(new PhabricatorTextEditField()) ->setKey('parentSite') ->setLabel(pht('Parent Site Name')) @@ -112,7 +112,7 @@ final class PhameBlogEditEngine ->setConduitDescription(pht('Change the blog parent site name.')) ->setConduitTypeDescription(pht('New blog parent site name.')) ->setValue($object->getParentSite()) - ->setTransactionType(PhameBlogTransaction::TYPE_PARENTSITE), + ->setTransactionType(PhameBlogParentSiteTransaction::TRANSACTIONTYPE), id(new PhabricatorTextEditField()) ->setKey('parentDomain') ->setLabel(pht('Parent Site URI')) @@ -120,11 +120,11 @@ final class PhameBlogEditEngine ->setConduitDescription(pht('Change the blog parent domain.')) ->setConduitTypeDescription(pht('New blog parent domain.')) ->setValue($object->getParentDomain()) - ->setTransactionType(PhameBlogTransaction::TYPE_PARENTDOMAIN), + ->setTransactionType(PhameBlogParentDomainTransaction::TRANSACTIONTYPE), id(new PhabricatorSelectEditField()) ->setKey('status') ->setLabel(pht('Status')) - ->setTransactionType(PhameBlogTransaction::TYPE_STATUS) + ->setTransactionType(PhameBlogStatusTransaction::TRANSACTIONTYPE) ->setIsConduitOnly(true) ->setOptions(PhameBlog::getStatusNameMap()) ->setDescription(pht('Active or archived status.')) diff --git a/src/applications/phame/editor/PhameBlogEditor.php b/src/applications/phame/editor/PhameBlogEditor.php index 14f63f51ac..f30a74065e 100644 --- a/src/applications/phame/editor/PhameBlogEditor.php +++ b/src/applications/phame/editor/PhameBlogEditor.php @@ -11,251 +11,22 @@ final class PhameBlogEditor return pht('Phame Blogs'); } + public function getCreateObjectTitle($author, $object) { + return pht('%s created this blog.', $author); + } + + public function getCreateObjectTitleForFeed($author, $object) { + return pht('%s created %s.', $author, $object); + } + public function getTransactionTypes() { $types = parent::getTransactionTypes(); - - $types[] = PhameBlogTransaction::TYPE_NAME; - $types[] = PhameBlogTransaction::TYPE_SUBTITLE; - $types[] = PhameBlogTransaction::TYPE_DESCRIPTION; - $types[] = PhameBlogTransaction::TYPE_FULLDOMAIN; - $types[] = PhameBlogTransaction::TYPE_PARENTSITE; - $types[] = PhameBlogTransaction::TYPE_PARENTDOMAIN; - $types[] = PhameBlogTransaction::TYPE_STATUS; - $types[] = PhameBlogTransaction::TYPE_HEADERIMAGE; - $types[] = PhameBlogTransaction::TYPE_PROFILEIMAGE; - $types[] = PhabricatorTransactions::TYPE_VIEW_POLICY; $types[] = PhabricatorTransactions::TYPE_EDIT_POLICY; return $types; } - protected function getCustomTransactionOldValue( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case PhameBlogTransaction::TYPE_NAME: - return $object->getName(); - case PhameBlogTransaction::TYPE_SUBTITLE: - return $object->getSubtitle(); - case PhameBlogTransaction::TYPE_DESCRIPTION: - return $object->getDescription(); - case PhameBlogTransaction::TYPE_FULLDOMAIN: - return $object->getDomainFullURI(); - case PhameBlogTransaction::TYPE_PARENTSITE: - return $object->getParentSite(); - case PhameBlogTransaction::TYPE_PARENTDOMAIN: - return $object->getParentDomain(); - case PhameBlogTransaction::TYPE_PROFILEIMAGE: - return $object->getProfileImagePHID(); - case PhameBlogTransaction::TYPE_HEADERIMAGE: - return $object->getHeaderImagePHID(); - case PhameBlogTransaction::TYPE_STATUS: - return $object->getStatus(); - } - } - - protected function getCustomTransactionNewValue( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case PhameBlogTransaction::TYPE_NAME: - case PhameBlogTransaction::TYPE_SUBTITLE: - case PhameBlogTransaction::TYPE_DESCRIPTION: - case PhameBlogTransaction::TYPE_STATUS: - case PhameBlogTransaction::TYPE_PARENTSITE: - case PhameBlogTransaction::TYPE_PARENTDOMAIN: - case PhameBlogTransaction::TYPE_PROFILEIMAGE: - case PhameBlogTransaction::TYPE_HEADERIMAGE: - return $xaction->getNewValue(); - case PhameBlogTransaction::TYPE_FULLDOMAIN: - $domain = $xaction->getNewValue(); - if (!strlen($xaction->getNewValue())) { - return null; - } - return $domain; - } - } - - protected function applyCustomInternalTransaction( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case PhameBlogTransaction::TYPE_NAME: - return $object->setName($xaction->getNewValue()); - case PhameBlogTransaction::TYPE_SUBTITLE: - return $object->setSubtitle($xaction->getNewValue()); - case PhameBlogTransaction::TYPE_DESCRIPTION: - return $object->setDescription($xaction->getNewValue()); - case PhameBlogTransaction::TYPE_FULLDOMAIN: - $new_value = $xaction->getNewValue(); - if (strlen($new_value)) { - $uri = new PhutilURI($new_value); - $domain = $uri->getDomain(); - $object->setDomain($domain); - } else { - $object->setDomain(null); - } - $object->setDomainFullURI($new_value); - return; - case PhameBlogTransaction::TYPE_PROFILEIMAGE: - return $object->setProfileImagePHID($xaction->getNewValue()); - case PhameBlogTransaction::TYPE_HEADERIMAGE: - return $object->setHeaderImagePHID($xaction->getNewValue()); - case PhameBlogTransaction::TYPE_STATUS: - return $object->setStatus($xaction->getNewValue()); - case PhameBlogTransaction::TYPE_PARENTSITE: - return $object->setParentSite($xaction->getNewValue()); - case PhameBlogTransaction::TYPE_PARENTDOMAIN: - return $object->setParentDomain($xaction->getNewValue()); - } - - return parent::applyCustomInternalTransaction($object, $xaction); - } - - protected function applyCustomExternalTransaction( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case PhameBlogTransaction::TYPE_NAME: - case PhameBlogTransaction::TYPE_SUBTITLE: - case PhameBlogTransaction::TYPE_DESCRIPTION: - case PhameBlogTransaction::TYPE_FULLDOMAIN: - case PhameBlogTransaction::TYPE_PARENTSITE: - case PhameBlogTransaction::TYPE_PARENTDOMAIN: - case PhameBlogTransaction::TYPE_HEADERIMAGE: - case PhameBlogTransaction::TYPE_PROFILEIMAGE: - case PhameBlogTransaction::TYPE_STATUS: - return; - } - - return parent::applyCustomExternalTransaction($object, $xaction); - } - - protected function validateTransaction( - PhabricatorLiskDAO $object, - $type, - array $xactions) { - - $errors = parent::validateTransaction($object, $type, $xactions); - - - switch ($type) { - case PhameBlogTransaction::TYPE_NAME: - $missing = $this->validateIsEmptyTextField( - $object->getName(), - $xactions); - - if ($missing) { - $error = new PhabricatorApplicationTransactionValidationError( - $type, - pht('Required'), - pht('Name is required.'), - nonempty(last($xactions), null)); - - $error->setIsMissingFieldError(true); - $errors[] = $error; - } - - foreach ($xactions as $xaction) { - $new = $xaction->getNewValue(); - if (phutil_utf8_strlen($new) > 64) { - $errors[] = new PhabricatorApplicationTransactionValidationError( - $type, - pht('Invalid'), - pht( - 'The selected blog title is too long. The maximum length '. - 'of a blog title is 64 characters.'), - $xaction); - } - } - break; - case PhameBlogTransaction::TYPE_SUBTITLE: - foreach ($xactions as $xaction) { - $new = $xaction->getNewValue(); - if (phutil_utf8_strlen($new) > 64) { - $errors[] = new PhabricatorApplicationTransactionValidationError( - $type, - pht('Invalid'), - pht( - 'The selected blog subtitle is too long. The maximum length '. - 'of a blog subtitle is 64 characters.'), - $xaction); - } - } - break; - case PhameBlogTransaction::TYPE_PARENTDOMAIN: - if (!$xactions) { - continue; - } - $parent_domain = last($xactions)->getNewValue(); - if (empty($parent_domain)) { - continue; - } - try { - PhabricatorEnv::requireValidRemoteURIForLink($parent_domain); - } catch (Exception $ex) { - $error = new PhabricatorApplicationTransactionValidationError( - $type, - pht('Invalid URI'), - pht('Parent Domain must be set to a valid Remote URI.'), - nonempty(last($xactions), null)); - $errors[] = $error; - } - break; - case PhameBlogTransaction::TYPE_FULLDOMAIN: - if (!$xactions) { - continue; - } - $custom_domain = last($xactions)->getNewValue(); - if (empty($custom_domain)) { - continue; - } - list($error_label, $error_text) = - $object->validateCustomDomain($custom_domain); - if ($error_label) { - $error = new PhabricatorApplicationTransactionValidationError( - $type, - $error_label, - $error_text, - nonempty(last($xactions), null)); - $errors[] = $error; - } - if ($object->getViewPolicy() != PhabricatorPolicies::POLICY_PUBLIC) { - $error_text = pht( - 'For custom domains to work, the blog must have a view policy of '. - 'public.'); - $error = new PhabricatorApplicationTransactionValidationError( - PhabricatorTransactions::TYPE_VIEW_POLICY, - pht('Invalid Policy'), - $error_text, - nonempty(last($xactions), null)); - $errors[] = $error; - } - $domain = new PhutilURI($custom_domain); - $domain = $domain->getDomain(); - $duplicate_blog = id(new PhameBlogQuery()) - ->setViewer(PhabricatorUser::getOmnipotentUser()) - ->withDomain($domain) - ->executeOne(); - if ($duplicate_blog && $duplicate_blog->getID() != $object->getID()) { - $error = new PhabricatorApplicationTransactionValidationError( - $type, - pht('Not Unique'), - pht('Domain must be unique; another blog already has this domain.'), - nonempty(last($xactions), null)); - $errors[] = $error; - } - - break; - } - return $errors; - } - protected function shouldSendMail( PhabricatorLiskDAO $object, array $xactions) { diff --git a/src/applications/phame/storage/PhameBlog.php b/src/applications/phame/storage/PhameBlog.php index bd4954d0ab..b72fc4bcfe 100644 --- a/src/applications/phame/storage/PhameBlog.php +++ b/src/applications/phame/storage/PhameBlog.php @@ -127,53 +127,41 @@ final class PhameBlog extends PhameDAO $supported_protocols = array('http', 'https'); if (!in_array($protocol, $supported_protocols)) { - return array( - $label, - pht( + return pht( 'The custom domain should include a valid protocol in the URI '. '(for example, "%s"). Valid protocols are "http" or "https".', - $example_domain), - ); + $example_domain); } if (strlen($path) && $path != '/') { - return array( - $label, - pht( + return pht( 'The custom domain should not specify a path (hosting a Phame '. 'blog at a path is currently not supported). Instead, just provide '. 'the bare domain name (for example, "%s").', - $example_domain), - ); + $example_domain); } if (strpos($domain, '.') === false) { - return array( - $label, - pht( + return pht( 'The custom domain should contain at least one dot (.) because '. 'some browsers fail to set cookies on domains without a dot. '. 'Instead, use a normal looking domain name like "%s".', - $example_domain), - ); + $example_domain); } if (!PhabricatorEnv::getEnvConfig('policy.allow-public')) { $href = PhabricatorEnv::getProductionURI( '/config/edit/policy.allow-public/'); - return array( - pht('Fix Configuration'), - pht( - 'For custom domains to work, this Phabricator instance must be '. - 'configured to allow the public access policy. Configure this '. - 'setting %s, or ask an administrator to configure this setting. '. - 'The domain can be specified later once this setting has been '. - 'changed.', - phutil_tag( - 'a', - array('href' => $href), - pht('here'))), - ); + return pht( + 'For custom domains to work, this Phabricator instance must be '. + 'configured to allow the public access policy. Configure this '. + 'setting %s, or ask an administrator to configure this setting. '. + 'The domain can be specified later once this setting has been '. + 'changed.', + phutil_tag( + 'a', + array('href' => $href), + pht('here'))); } return null; diff --git a/src/applications/phame/storage/PhameBlogTransaction.php b/src/applications/phame/storage/PhameBlogTransaction.php index f08c7be688..c5702a2b18 100644 --- a/src/applications/phame/storage/PhameBlogTransaction.php +++ b/src/applications/phame/storage/PhameBlogTransaction.php @@ -1,17 +1,7 @@ getOldValue(); - switch ($this->getTransactionType()) { - case self::TYPE_DESCRIPTION: - if ($old === null) { - return true; - } - } - return parent::shouldHide(); - } - - public function getRequiredHandlePHIDs() { - $old = $this->getOldValue(); - $new = $this->getNewValue(); - - $req_phids = array(); - switch ($this->getTransactionType()) { - case self::TYPE_PROFILEIMAGE: - case self::TYPE_HEADERIMAGE: - $req_phids[] = $old; - $req_phids[] = $new; - break; - } - - return array_merge($req_phids, parent::getRequiredHandlePHIDs()); - } - - public function getIcon() { - $old = $this->getOldValue(); - $new = $this->getNewValue(); - switch ($this->getTransactionType()) { - case self::TYPE_NAME: - if ($old === null) { - return 'fa-plus'; - } else { - return 'fa-pencil'; - } - break; - case self::TYPE_DESCRIPTION: - case self::TYPE_FULLDOMAIN: - return 'fa-pencil'; - case self::TYPE_HEADERIMAGE: - return 'fa-image'; - case self::TYPE_PROFILEIMAGE: - return 'fa-star'; - case self::TYPE_STATUS: - if ($new == PhameBlog::STATUS_ARCHIVED) { - return 'fa-ban'; - } else { - return 'fa-check'; - } - break; - } - return parent::getIcon(); - } - - public function getColor() { - - $old = $this->getOldValue(); - $new = $this->getNewValue(); - - switch ($this->getTransactionType()) { - case self::TYPE_STATUS: - if ($new == PhameBlog::STATUS_ARCHIVED) { - return 'violet'; - } else { - return 'green'; - } - } - return parent::getColor(); + public function getBaseTransactionClass() { + return 'PhameBlogTransactionType'; } public function getMailTags() { @@ -121,247 +43,4 @@ final class PhameBlogTransaction return $tags; } - public function getTitle() { - $author_phid = $this->getAuthorPHID(); - $object_phid = $this->getObjectPHID(); - - $old = $this->getOldValue(); - $new = $this->getNewValue(); - - $type = $this->getTransactionType(); - switch ($type) { - case PhabricatorTransactions::TYPE_CREATE: - return pht( - '%s created this blog.', - $this->renderHandleLink($author_phid)); - case self::TYPE_NAME: - if ($old === null) { - return pht( - '%s created this blog.', - $this->renderHandleLink($author_phid)); - } else { - return pht( - '%s updated the blog\'s name to "%s".', - $this->renderHandleLink($author_phid), - $new); - } - break; - case self::TYPE_SUBTITLE: - if ($old === null) { - return pht( - '%s set this blog\'s subtitle to "%s".', - $this->renderHandleLink($author_phid), - $new); - } else { - return pht( - '%s updated the blog\'s subtitle to "%s".', - $this->renderHandleLink($author_phid), - $new); - } - break; - case self::TYPE_DESCRIPTION: - return pht( - '%s updated the blog\'s description.', - $this->renderHandleLink($author_phid)); - break; - case self::TYPE_FULLDOMAIN: - return pht( - '%s updated the blog\'s full domain to "%s".', - $this->renderHandleLink($author_phid), - $new); - break; - case self::TYPE_PARENTSITE: - if ($old === null) { - return pht( - '%s set this blog\'s parent site to "%s".', - $this->renderHandleLink($author_phid), - $new); - } else { - return pht( - '%s updated the blog\'s parent site to "%s".', - $this->renderHandleLink($author_phid), - $new); - } - break; - case self::TYPE_PARENTDOMAIN: - if ($old === null) { - return pht( - '%s set this blog\'s parent domain to "%s".', - $this->renderHandleLink($author_phid), - $new); - } else { - return pht( - '%s updated the blog\'s parent domain to "%s".', - $this->renderHandleLink($author_phid), - $new); - } - break; - case self::TYPE_HEADERIMAGE: - if (!$old) { - return pht( - "%s set this blog's header image to %s.", - $this->renderHandleLink($author_phid), - $this->renderHandleLink($new)); - } else if (!$new) { - return pht( - "%s removed this blog's header image.", - $this->renderHandleLink($author_phid)); - } else { - return pht( - "%s updated this blog's header image from %s to %s.", - $this->renderHandleLink($author_phid), - $this->renderHandleLink($old), - $this->renderHandleLink($new)); - } - break; - case self::TYPE_PROFILEIMAGE: - if (!$old) { - return pht( - "%s set this blog's profile image to %s.", - $this->renderHandleLink($author_phid), - $this->renderHandleLink($new)); - } else if (!$new) { - return pht( - "%s removed this blog's profile image.", - $this->renderHandleLink($author_phid)); - } else { - return pht( - "%s updated this blog's profile image from %s to %s.", - $this->renderHandleLink($author_phid), - $this->renderHandleLink($old), - $this->renderHandleLink($new)); - } - break; - case self::TYPE_STATUS: - switch ($new) { - case PhameBlog::STATUS_ACTIVE: - return pht( - '%s published this blog.', - $this->renderHandleLink($author_phid)); - case PhameBlog::STATUS_ARCHIVED: - return pht( - '%s archived this blog.', - $this->renderHandleLink($author_phid)); - } - - } - - return parent::getTitle(); - } - - public function getTitleForFeed() { - $author_phid = $this->getAuthorPHID(); - $object_phid = $this->getObjectPHID(); - - $old = $this->getOldValue(); - $new = $this->getNewValue(); - - $type = $this->getTransactionType(); - switch ($type) { - case self::TYPE_NAME: - if ($old === null) { - return pht( - '%s created %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - } else { - return pht( - '%s updated the name for %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - } - break; - case self::TYPE_SUBTITLE: - if ($old === null) { - return pht( - '%s set the subtitle for %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - } else { - return pht( - '%s updated the subtitle for %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - } - break; - case self::TYPE_DESCRIPTION: - return pht( - '%s updated the description for %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - break; - case self::TYPE_FULLDOMAIN: - return pht( - '%s updated the full domain for %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - break; - case self::TYPE_PARENTSITE: - return pht( - '%s updated the parent site for %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - break; - case self::TYPE_PARENTDOMAIN: - return pht( - '%s updated the parent domain for %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - break; - case self::TYPE_HEADERIMAGE: - return pht( - '%s updated the header image for %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - break; - case self::TYPE_PROFILEIMAGE: - return pht( - '%s updated the profile image for %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - break; - case self::TYPE_STATUS: - switch ($new) { - case PhameBlog::STATUS_ACTIVE: - return pht( - '%s published the blog %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - case PhameBlog::STATUS_ARCHIVED: - return pht( - '%s archived the blog %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - } - break; - - } - - return parent::getTitleForFeed(); - } - - public function hasChangeDetails() { - switch ($this->getTransactionType()) { - case self::TYPE_DESCRIPTION: - return ($this->getOldValue() !== null); - } - - return parent::hasChangeDetails(); - } - - public function renderChangeDetails(PhabricatorUser $viewer) { - switch ($this->getTransactionType()) { - case self::TYPE_DESCRIPTION: - $old = $this->getOldValue(); - $new = $this->getNewValue(); - - return $this->renderTextCorpusChangeDetails( - $viewer, - $old, - $new); - } - - return parent::renderChangeDetails($viewer); - } - } diff --git a/src/applications/phame/xaction/PhameBlogDescriptionTransaction.php b/src/applications/phame/xaction/PhameBlogDescriptionTransaction.php new file mode 100644 index 0000000000..2bc12f3998 --- /dev/null +++ b/src/applications/phame/xaction/PhameBlogDescriptionTransaction.php @@ -0,0 +1,60 @@ +getDescription(); + } + + public function applyInternalEffects($object, $value) { + $object->setDescription($value); + } + + public function getTitle() { + return pht( + '%s updated the description.', + $this->renderAuthor()); + } + + public function getTitleForFeed() { + return pht( + '%s updated the description for %s.', + $this->renderAuthor(), + $this->renderObject()); + } + + public function hasChangeDetailView() { + return true; + } + + public function getMailDiffSectionHeader() { + return pht('CHANGES TO BLOG DESCRIPTION'); + } + + public function newChangeDetailView() { + $viewer = $this->getViewer(); + + return id(new PhabricatorApplicationTransactionTextDiffDetailView()) + ->setViewer($viewer) + ->setOldText($this->getOldValue()) + ->setNewText($this->getNewValue()); + } + + public function newRemarkupChanges() { + $changes = array(); + + $changes[] = $this->newRemarkupChange() + ->setOldValue($this->getOldValue()) + ->setNewValue($this->getNewValue()); + + return $changes; + } + + public function getIcon() { + return 'fa-file-text-o'; + } + +} diff --git a/src/applications/phame/xaction/PhameBlogFullDomainTransaction.php b/src/applications/phame/xaction/PhameBlogFullDomainTransaction.php new file mode 100644 index 0000000000..5287f9cc06 --- /dev/null +++ b/src/applications/phame/xaction/PhameBlogFullDomainTransaction.php @@ -0,0 +1,95 @@ +getDomainFullURI(); + } + + public function applyInternalEffects($object, $value) { + if (strlen($value)) { + $uri = new PhutilURI($value); + $domain = $uri->getDomain(); + $object->setDomain($domain); + } else { + $object->setDomain(null); + } + $object->setDomainFullURI($value); + } + + public function getTitle() { + $old = $this->getOldValue(); + if (!strlen($old)) { + return pht( + '%s set this blog\'s full domain to %s.', + $this->renderAuthor(), + $this->renderNewValue()); + } else { + return pht( + '%s updated the blog\'s full domain from %s to %s.', + $this->renderAuthor(), + $this->renderOldValue(), + $this->renderNewValue()); + } + } + + public function getTitleForFeed() { + $old = $this->getOldValue(); + if (!strlen($old)) { + return pht( + '%s set %s blog\'s full domain to %s.', + $this->renderAuthor(), + $this->renderObject(), + $this->renderNewValue()); + } else { + return pht( + '%s updated %s blog\'s full domain from %s to %s.', + $this->renderAuthor(), + $this->renderObject(), + $this->renderOldValue(), + $this->renderNewValue()); + } + } + + public function validateTransactions($object, array $xactions) { + $errors = array(); + + if (!$xactions) { + return $errors; + } + + $custom_domain = last($xactions)->getNewValue(); + if (empty($custom_domain)) { + return $errors; + } + + $error_text = $object->validateCustomDomain($custom_domain); + if ($error_text) { + $errors[] = $this->newInvalidError($error_text); + } + + if ($object->getViewPolicy() != PhabricatorPolicies::POLICY_PUBLIC) { + $errors[] = $this->newInvalidError( + pht('For custom domains to work, the blog must have a view policy of '. + 'public. This blog is currently set to "%s".', + $object->getViewPolicy())); + } + + $domain = new PhutilURI($custom_domain); + $domain = $domain->getDomain(); + $duplicate_blog = id(new PhameBlogQuery()) + ->setViewer(PhabricatorUser::getOmnipotentUser()) + ->withDomain($domain) + ->executeOne(); + if ($duplicate_blog && $duplicate_blog->getID() != $object->getID()) { + $errors[] = $this->newInvalidError( + pht('Domain must be unique; another blog already has this domain.')); + } + + return $errors; + } + +} diff --git a/src/applications/phame/xaction/PhameBlogHeaderImageTransaction.php b/src/applications/phame/xaction/PhameBlogHeaderImageTransaction.php new file mode 100644 index 0000000000..b328b9aca5 --- /dev/null +++ b/src/applications/phame/xaction/PhameBlogHeaderImageTransaction.php @@ -0,0 +1,34 @@ +getHeaderImagePHID(); + } + + public function applyInternalEffects($object, $value) { + $object->setHeaderImagePHID($value); + } + + public function getTitle() { + return pht( + '%s changed the header image for this blog.', + $this->renderAuthor()); + } + + public function getTitleForFeed() { + return pht( + '%s changed the header image for blog %s.', + $this->renderAuthor(), + $this->renderObject()); + } + + public function getIcon() { + return 'fa-camera'; + } + +} diff --git a/src/applications/phame/xaction/PhameBlogNameTransaction.php b/src/applications/phame/xaction/PhameBlogNameTransaction.php new file mode 100644 index 0000000000..dbca5304a8 --- /dev/null +++ b/src/applications/phame/xaction/PhameBlogNameTransaction.php @@ -0,0 +1,59 @@ +getName(); + } + + public function applyInternalEffects($object, $value) { + $object->setName($value); + } + + public function getTitle() { + return pht( + '%s renamed this blog from %s to %s.', + $this->renderAuthor(), + $this->renderOldValue(), + $this->renderNewValue()); + } + + public function getTitleForFeed() { + return pht( + '%s renamed %s blog froms %s to %s.', + $this->renderAuthor(), + $this->renderObject(), + $this->renderOldValue(), + $this->renderNewValue()); + } + + public function validateTransactions($object, array $xactions) { + $errors = array(); + + if ($this->isEmptyTextTransaction($object->getName(), $xactions)) { + $errors[] = $this->newRequiredError( + pht('Blogs must have a name.')); + } + + $max_length = $object->getColumnMaximumByteLength('name'); + foreach ($xactions as $xaction) { + $new_value = $xaction->getNewValue(); + $new_length = strlen($new_value); + if ($new_length > $max_length) { + $errors[] = $this->newInvalidError( + pht('The name can be no longer than %s characters.', + new PhutilNumber($max_length))); + } + } + + return $errors; + } + + public function getIcon() { + return 'fa-rss'; + } + +} diff --git a/src/applications/phame/xaction/PhameBlogParentDomainTransaction.php b/src/applications/phame/xaction/PhameBlogParentDomainTransaction.php new file mode 100644 index 0000000000..227c8ce8c3 --- /dev/null +++ b/src/applications/phame/xaction/PhameBlogParentDomainTransaction.php @@ -0,0 +1,82 @@ +getParentDomain(); + } + + public function applyInternalEffects($object, $value) { + $object->setParentDomain($value); + } + + public function getTitle() { + $old = $this->getOldValue(); + if (!strlen($old)) { + return pht( + '%s set this blog\'s parent domain to %s.', + $this->renderAuthor(), + $this->renderNewValue()); + } else { + return pht( + '%s updated the blog\'s parent domain from %s to %s.', + $this->renderAuthor(), + $this->renderOldValue(), + $this->renderNewValue()); + } + } + + public function getTitleForFeed() { + $old = $this->getOldValue(); + if (!strlen($old)) { + return pht( + '%s set %s blog\'s parent domain to %s.', + $this->renderAuthor(), + $this->renderObject(), + $this->renderNewValue()); + } else { + return pht( + '%s updated %s blog\'s parent domain from %s to %s.', + $this->renderAuthor(), + $this->renderObject(), + $this->renderOldValue(), + $this->renderNewValue()); + } + } + + public function validateTransactions($object, array $xactions) { + $errors = array(); + + if (!$xactions) { + return $errors; + } + + $parent_domain = last($xactions)->getNewValue(); + if (empty($parent_domain)) { + return $errors; + } + + try { + PhabricatorEnv::requireValidRemoteURIForLink($parent_domain); + } catch (Exception $ex) { + $errors[] = $this->newInvalidError( + pht('Parent Domain must be set to a valid Remote URI.')); + } + + $max_length = $object->getColumnMaximumByteLength('parentDomain'); + foreach ($xactions as $xaction) { + $new_value = $xaction->getNewValue(); + $new_length = strlen($new_value); + if ($new_length > $max_length) { + $errors[] = $this->newInvalidError( + pht('The parent domain can be no longer than %s characters.', + new PhutilNumber($max_length))); + } + } + + return $errors; + } +} diff --git a/src/applications/phame/xaction/PhameBlogParentSiteTransaction.php b/src/applications/phame/xaction/PhameBlogParentSiteTransaction.php new file mode 100644 index 0000000000..1b62b98488 --- /dev/null +++ b/src/applications/phame/xaction/PhameBlogParentSiteTransaction.php @@ -0,0 +1,66 @@ +getParentSite(); + } + + public function applyInternalEffects($object, $value) { + $object->setParentSite($value); + } + + public function getTitle() { + $old = $this->getOldValue(); + if (!strlen($old)) { + return pht( + '%s set this blog\'s parent site to %s.', + $this->renderAuthor(), + $this->renderNewValue()); + } else { + return pht( + '%s updated the blog\'s parent site from %s to %s.', + $this->renderAuthor(), + $this->renderOldValue(), + $this->renderNewValue()); + } + } + + public function getTitleForFeed() { + $old = $this->getOldValue(); + if (!strlen($old)) { + return pht( + '%s set %s blog\'s parent site to %s.', + $this->renderAuthor(), + $this->renderObject(), + $this->renderNewValue()); + } else { + return pht( + '%s updated %s blog\'s parent site from %s to %s.', + $this->renderAuthor(), + $this->renderObject(), + $this->renderOldValue(), + $this->renderNewValue()); + } + } + + public function validateTransactions($object, array $xactions) { + $errors = array(); + + $max_length = $object->getColumnMaximumByteLength('parentSite'); + foreach ($xactions as $xaction) { + $new_value = $xaction->getNewValue(); + $new_length = strlen($new_value); + if ($new_length > $max_length) { + $errors[] = $this->newInvalidError( + pht('The parent site can be no longer than %s characters.', + new PhutilNumber($max_length))); + } + } + + return $errors; + } +} diff --git a/src/applications/phame/xaction/PhameBlogProfileImageTransaction.php b/src/applications/phame/xaction/PhameBlogProfileImageTransaction.php new file mode 100644 index 0000000000..77acf680fd --- /dev/null +++ b/src/applications/phame/xaction/PhameBlogProfileImageTransaction.php @@ -0,0 +1,34 @@ +getProfileImagePHID(); + } + + public function applyInternalEffects($object, $value) { + $object->setProfileImagePHID($value); + } + + public function getTitle() { + return pht( + '%s changed the profile image for this blog.', + $this->renderAuthor()); + } + + public function getTitleForFeed() { + return pht( + '%s changed the profile image for blog %s.', + $this->renderAuthor(), + $this->renderObject()); + } + + public function getIcon() { + return 'fa-file-image-o'; + } + +} diff --git a/src/applications/phame/xaction/PhameBlogStatusTransaction.php b/src/applications/phame/xaction/PhameBlogStatusTransaction.php new file mode 100644 index 0000000000..21345ea249 --- /dev/null +++ b/src/applications/phame/xaction/PhameBlogStatusTransaction.php @@ -0,0 +1,55 @@ +getStatus(); + } + + public function applyInternalEffects($object, $value) { + $object->setStatus($value); + } + + public function getTitle() { + $new = $this->getNewValue(); + switch ($new) { + case PhameBlog::STATUS_ACTIVE: + return pht( + '%s published this blog.', + $this->renderAuthor()); + case PhameBlog::STATUS_ARCHIVED: + return pht( + '%s archived this blog.', + $this->renderAuthor()); + } + } + + public function getTitleForFeed() { + $new = $this->getNewValue(); + switch ($new) { + case PhameBlog::STATUS_ACTIVE: + return pht( + '%s published the blog %s.', + $this->renderAuthor(), + $this->renderObject()); + case PhameBlog::STATUS_ARCHIVED: + return pht( + '%s archived the blog %s.', + $this->renderAuthor(), + $this->renderObject()); + } + } + + public function getIcon() { + $new = $this->getNewValue(); + if ($new == PhameBlog::STATUS_ARCHIVED) { + return 'fa-ban'; + } else { + return 'fa-check'; + } + } + +} diff --git a/src/applications/phame/xaction/PhameBlogSubtitleTransaction.php b/src/applications/phame/xaction/PhameBlogSubtitleTransaction.php new file mode 100644 index 0000000000..87788a31f7 --- /dev/null +++ b/src/applications/phame/xaction/PhameBlogSubtitleTransaction.php @@ -0,0 +1,63 @@ +getSubtitle(); + } + + public function applyInternalEffects($object, $value) { + $object->setSubtitle($value); + } + + public function getTitle() { + $old = $this->getOldValue(); + if ($old === null) { + return pht( + '%s set this blog\'s subtitle to "%s".', + $this->renderAuthor(), + $this->renderNewValue()); + } else { + return pht( + '%s updated the blog\'s subtitle to "%s".', + $this->renderAuthor(), + $this->renderNewValue()); + } + } + + public function getTitleForFeed() { + $old = $this->getOldValue(); + if ($old === null) { + return pht( + '%s set the subtitle for %s.', + $this->renderAuthor(), + $this->renderObject()); + } else { + return pht( + '%s updated the subtitle for %s.', + $this->renderAuthor(), + $this->renderObject()); + } + } + + public function validateTransactions($object, array $xactions) { + $errors = array(); + + $max_length = $object->getColumnMaximumByteLength('subtitle'); + foreach ($xactions as $xaction) { + $new_value = $xaction->getNewValue(); + $new_length = strlen($new_value); + if ($new_length > $max_length) { + $errors[] = $this->newInvalidError( + pht('The subtitle can be no longer than %s characters.', + new PhutilNumber($max_length))); + } + } + + return $errors; + } + +} diff --git a/src/applications/phame/xaction/PhameBlogTransactionType.php b/src/applications/phame/xaction/PhameBlogTransactionType.php new file mode 100644 index 0000000000..cf83633b9f --- /dev/null +++ b/src/applications/phame/xaction/PhameBlogTransactionType.php @@ -0,0 +1,4 @@ + Date: Wed, 3 May 2017 11:11:14 -0700 Subject: [PATCH 12/25] Update Macro for EditEngine Summary: Updates Macro to use EditEngine. Also removes "URL" field for adding a Macro, which I think it's worth pursuing. Test Plan: - Create a Macro - Forget to name it - Try a PDF - Use a Macro - Edit a macro (not working) Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Differential Revision: https://secure.phabricator.com/D17821 --- src/__phutil_library_map__.php | 4 +- .../PhabricatorMacroApplication.php | 3 +- .../PhabricatorMacroEditController.php | 302 +----------------- .../editor/PhabricatorMacroEditEngine.php | 88 +++++ .../macro/editor/PhabricatorMacroEditor.php | 9 +- .../storage/PhabricatorFileImageMacro.php | 20 +- .../PhabricatorMacroFileTransaction.php | 35 ++ .../PhabricatorMacroNameTransaction.php | 25 ++ 8 files changed, 181 insertions(+), 305 deletions(-) create mode 100644 src/applications/macro/editor/PhabricatorMacroEditEngine.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 0c71c8eab1..7716a29ce7 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -2982,6 +2982,7 @@ phutil_register_library_map(array( 'PhabricatorMacroDisableController' => 'applications/macro/controller/PhabricatorMacroDisableController.php', 'PhabricatorMacroDisabledTransaction' => 'applications/macro/xaction/PhabricatorMacroDisabledTransaction.php', 'PhabricatorMacroEditController' => 'applications/macro/controller/PhabricatorMacroEditController.php', + 'PhabricatorMacroEditEngine' => 'applications/macro/editor/PhabricatorMacroEditEngine.php', 'PhabricatorMacroEditor' => 'applications/macro/editor/PhabricatorMacroEditor.php', 'PhabricatorMacroFileTransaction' => 'applications/macro/xaction/PhabricatorMacroFileTransaction.php', 'PhabricatorMacroListController' => 'applications/macro/controller/PhabricatorMacroListController.php', @@ -8187,7 +8188,8 @@ phutil_register_library_map(array( 'PhabricatorMacroDatasource' => 'PhabricatorTypeaheadDatasource', 'PhabricatorMacroDisableController' => 'PhabricatorMacroController', 'PhabricatorMacroDisabledTransaction' => 'PhabricatorMacroTransactionType', - 'PhabricatorMacroEditController' => 'PhabricatorMacroController', + 'PhabricatorMacroEditController' => 'PhameBlogController', + 'PhabricatorMacroEditEngine' => 'PhabricatorEditEngine', 'PhabricatorMacroEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorMacroFileTransaction' => 'PhabricatorMacroTransactionType', 'PhabricatorMacroListController' => 'PhabricatorMacroController', diff --git a/src/applications/macro/application/PhabricatorMacroApplication.php b/src/applications/macro/application/PhabricatorMacroApplication.php index 3519a3f520..d0e6bbab04 100644 --- a/src/applications/macro/application/PhabricatorMacroApplication.php +++ b/src/applications/macro/application/PhabricatorMacroApplication.php @@ -33,7 +33,8 @@ final class PhabricatorMacroApplication extends PhabricatorApplication { 'create/' => 'PhabricatorMacroEditController', 'view/(?P[1-9]\d*)/' => 'PhabricatorMacroViewController', 'comment/(?P[1-9]\d*)/' => 'PhabricatorMacroCommentController', - 'edit/(?P[1-9]\d*)/' => 'PhabricatorMacroEditController', + $this->getEditRoutePattern('edit/') + => 'PhabricatorMacroEditController', 'audio/(?P[1-9]\d*)/' => 'PhabricatorMacroAudioController', 'disable/(?P[1-9]\d*)/' => 'PhabricatorMacroDisableController', 'meme/' => 'PhabricatorMacroMemeController', diff --git a/src/applications/macro/controller/PhabricatorMacroEditController.php b/src/applications/macro/controller/PhabricatorMacroEditController.php index fc84e057ae..d4b7d5aeec 100644 --- a/src/applications/macro/controller/PhabricatorMacroEditController.php +++ b/src/applications/macro/controller/PhabricatorMacroEditController.php @@ -1,304 +1,10 @@ getViewer(); - $id = $request->getURIData('id'); - - $this->requireApplicationCapability( - PhabricatorMacroManageCapability::CAPABILITY); - - if ($id) { - $macro = id(new PhabricatorMacroQuery()) - ->setViewer($viewer) - ->withIDs(array($id)) - ->needFiles(true) - ->executeOne(); - if (!$macro) { - return new Aphront404Response(); - } - } else { - $macro = new PhabricatorFileImageMacro(); - $macro->setAuthorPHID($viewer->getPHID()); - } - - $errors = array(); - $e_name = true; - $e_file = null; - $file = null; - - if ($request->isFormPost()) { - $original = clone $macro; - - $new_name = null; - if ($request->getBool('name_form') || !$macro->getID()) { - $new_name = $request->getStr('name'); - - $macro->setName($new_name); - - if (!strlen($macro->getName())) { - $errors[] = pht('Macro name is required.'); - $e_name = pht('Required'); - } else if (!preg_match('/^[a-z0-9:_-]{3,}\z/', $macro->getName())) { - $errors[] = pht( - 'Macro must be at least three characters long and contain only '. - 'lowercase letters, digits, hyphens, colons and underscores.'); - $e_name = pht('Invalid'); - } else { - $e_name = null; - } - } - - $uri = $request->getStr('url'); - - $engine = new PhabricatorDestructionEngine(); - - $file = null; - if ($request->getFileExists('file')) { - $file = PhabricatorFile::newFromPHPUpload( - $_FILES['file'], - array( - 'name' => $request->getStr('name'), - 'authorPHID' => $viewer->getPHID(), - 'isExplicitUpload' => true, - 'canCDN' => true, - )); - } else if ($uri) { - try { - // Rate limit outbound fetches to make this mechanism less useful for - // scanning networks and ports. - PhabricatorSystemActionEngine::willTakeAction( - array($viewer->getPHID()), - new PhabricatorFilesOutboundRequestAction(), - 1); - - $file = PhabricatorFile::newFromFileDownload( - $uri, - array( - 'name' => $request->getStr('name'), - 'viewPolicy' => PhabricatorPolicies::POLICY_NOONE, - 'isExplicitUpload' => true, - 'canCDN' => true, - )); - - if (!$file->isViewableInBrowser()) { - $mime_type = $file->getMimeType(); - $engine->destroyObject($file); - $file = null; - throw new Exception( - pht( - 'The URI "%s" does not correspond to a valid image file, got '. - 'a file with MIME type "%s". You must specify the URI of a '. - 'valid image file.', - $uri, - $mime_type)); - } else { - $file - ->setAuthorPHID($viewer->getPHID()) - ->save(); - } - } catch (HTTPFutureHTTPResponseStatus $status) { - $errors[] = pht( - 'The URI "%s" could not be loaded, got %s error.', - $uri, - $status->getStatusCode()); - } catch (Exception $ex) { - $errors[] = $ex->getMessage(); - } - } else if ($request->getStr('phid')) { - $file = id(new PhabricatorFileQuery()) - ->setViewer($viewer) - ->withPHIDs(array($request->getStr('phid'))) - ->executeOne(); - } - - if ($file) { - if (!$file->isViewableInBrowser()) { - $errors[] = pht('You must upload an image.'); - $e_file = pht('Invalid'); - } else { - $macro->setFilePHID($file->getPHID()); - $macro->attachFile($file); - $e_file = null; - } - } - - if (!$macro->getID() && !$file) { - $errors[] = pht('You must upload an image to create a macro.'); - $e_file = pht('Required'); - } - - if (!$errors) { - try { - $xactions = array(); - - if ($new_name !== null) { - $xactions[] = id(new PhabricatorMacroTransaction()) - ->setTransactionType( - PhabricatorMacroNameTransaction::TRANSACTIONTYPE) - ->setNewValue($new_name); - } - - if ($file) { - $xactions[] = id(new PhabricatorMacroTransaction()) - ->setTransactionType( - PhabricatorMacroFileTransaction::TRANSACTIONTYPE) - ->setNewValue($file->getPHID()); - } - - $editor = id(new PhabricatorMacroEditor()) - ->setActor($viewer) - ->setContinueOnNoEffect(true) - ->setContentSourceFromRequest($request); - - $xactions = $editor->applyTransactions($original, $xactions); - - $view_uri = $this->getApplicationURI('/view/'.$original->getID().'/'); - return id(new AphrontRedirectResponse())->setURI($view_uri); - } catch (AphrontDuplicateKeyQueryException $ex) { - throw $ex; - $errors[] = pht('Macro name is not unique!'); - $e_name = pht('Duplicate'); - } - } - } - - $current_file = null; - if ($macro->getFilePHID()) { - $current_file = $macro->getFile(); - } - - $form = new AphrontFormView(); - $form->addHiddenInput('name_form', 1); - $form->setUser($request->getUser()); - - $form - ->setEncType('multipart/form-data') - ->appendChild( - id(new AphrontFormTextControl()) - ->setLabel(pht('Name')) - ->setName('name') - ->setValue($macro->getName()) - ->setCaption( - pht('This word or phrase will be replaced with the image.')) - ->setError($e_name)); - - if (!$macro->getID()) { - if ($current_file) { - $current_file_view = id(new PhabricatorFileLinkView()) - ->setViewer($viewer) - ->setFilePHID($current_file->getPHID()) - ->setFileName($current_file->getName()) - ->setFileViewable(true) - ->setFileViewURI($current_file->getBestURI()) - ->render(); - $form->addHiddenInput('phid', $current_file->getPHID()); - $form->appendChild( - id(new AphrontFormMarkupControl()) - ->setLabel(pht('Selected File')) - ->setValue($current_file_view)); - - $other_label = pht('Change File'); - } else { - $other_label = pht('File'); - } - - $form->appendChild( - id(new AphrontFormTextControl()) - ->setLabel(pht('URL')) - ->setName('url') - ->setValue($request->getStr('url')) - ->setError($request->getFileExists('file') ? false : $e_file)); - - $form->appendChild( - id(new AphrontFormFileControl()) - ->setLabel($other_label) - ->setName('file') - ->setError($request->getStr('url') ? false : $e_file)); - } - - - $view_uri = $this->getApplicationURI('/view/'.$macro->getID().'/'); - - if ($macro->getID()) { - $cancel_uri = $view_uri; - } else { - $cancel_uri = $this->getApplicationURI(); - } - - $form - ->appendChild( - id(new AphrontFormSubmitControl()) - ->setValue(pht('Save Image Macro')) - ->addCancelButton($cancel_uri)); - - $crumbs = $this->buildApplicationCrumbs(); - - if ($macro->getID()) { - $title = pht('Edit Macro: %s', $macro->getName()); - $crumb = pht('Edit Macro'); - $header_icon = 'fa-pencil'; - - $crumbs->addTextCrumb(pht('Macro: %s', $macro->getName()), $view_uri); - } else { - $title = pht('Create Image Macro'); - $crumb = pht('Create Macro'); - $header_icon = 'fa-plus-square'; - } - - $crumbs->addTextCrumb($crumb, $request->getRequestURI()); - $crumbs->setBorder(true); - - $upload = null; - if ($macro->getID()) { - $upload_form = id(new AphrontFormView()) - ->setEncType('multipart/form-data') - ->setUser($request->getUser()); - - $upload_form->appendChild( - id(new AphrontFormTextControl()) - ->setLabel(pht('URL')) - ->setName('url') - ->setValue($request->getStr('url'))); - - $upload_form - ->appendChild( - id(new AphrontFormFileControl()) - ->setLabel(pht('File')) - ->setName('file')) - ->appendChild( - id(new AphrontFormSubmitControl()) - ->setValue(pht('Upload File'))); - - $upload = id(new PHUIObjectBoxView()) - ->setHeaderText(pht('Upload New File')) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) - ->setForm($upload_form); - } - - $form_box = id(new PHUIObjectBoxView()) - ->setHeaderText(pht('Macro')) - ->setFormErrors($errors) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) - ->setForm($form); - - $header = id(new PHUIHeaderView()) - ->setHeader($title) - ->setHeaderIcon($header_icon); - - $view = id(new PHUITwoColumnView()) - ->setHeader($header) - ->setFooter(array( - $form_box, - $upload, - )); - - return $this->newPage() - ->setTitle($title) - ->setCrumbs($crumbs) - ->appendChild($view); - + return id(new PhabricatorMacroEditEngine()) + ->setController($this) + ->buildResponse(); } - } diff --git a/src/applications/macro/editor/PhabricatorMacroEditEngine.php b/src/applications/macro/editor/PhabricatorMacroEditEngine.php new file mode 100644 index 0000000000..3f472ff0ce --- /dev/null +++ b/src/applications/macro/editor/PhabricatorMacroEditEngine.php @@ -0,0 +1,88 @@ +getViewer(); + return PhabricatorFileImageMacro::initializeNewFileImageMacro($viewer); + } + + protected function newObjectQuery() { + return new PhabricatorMacroQuery(); + } + + protected function getObjectCreateTitleText($object) { + return pht('Create New Macro'); + } + + protected function getObjectEditTitleText($object) { + return pht('Edit %s', $object->getName()); + } + + protected function getObjectEditShortText($object) { + return $object->getName(); + } + + protected function getObjectCreateShortText() { + return pht('Create Macro'); + } + + protected function getObjectName() { + return pht('Macro'); + } + + protected function getObjectViewURI($object) { + return $object->getViewURI(); + } + + protected function getEditorURI() { + return $this->getApplication()->getApplicationURI('edit/'); + } + + protected function getCreateNewObjectPolicy() { + return $this->getApplication()->getPolicy( + PhabricatorMacroManageCapability::CAPABILITY); + } + + protected function buildCustomEditFields($object) { + + return array( + id(new PhabricatorTextEditField()) + ->setKey('name') + ->setLabel(pht('Name')) + ->setDescription(pht('Macro name.')) + ->setConduitDescription(pht('Rename the macro.')) + ->setConduitTypeDescription(pht('New macro name.')) + ->setTransactionType(PhabricatorMacroNameTransaction::TRANSACTIONTYPE) + ->setValue($object->getName()), + id(new PhabricatorFileEditField()) + ->setKey('filePHID') + ->setLabel(pht('Image File')) + ->setDescription(pht('Image file to import.')) + ->setTransactionType(PhabricatorMacroFileTransaction::TRANSACTIONTYPE) + ->setConduitDescription(pht('File PHID to import.')) + ->setConduitTypeDescription(pht('File PHID.')), + ); + + } + +} diff --git a/src/applications/macro/editor/PhabricatorMacroEditor.php b/src/applications/macro/editor/PhabricatorMacroEditor.php index 797fa702a9..d9067c5367 100644 --- a/src/applications/macro/editor/PhabricatorMacroEditor.php +++ b/src/applications/macro/editor/PhabricatorMacroEditor.php @@ -11,11 +11,12 @@ final class PhabricatorMacroEditor return pht('Macros'); } - public function getTransactionTypes() { - $types = parent::getTransactionTypes(); - $types[] = PhabricatorTransactions::TYPE_COMMENT; + public function getCreateObjectTitle($author, $object) { + return pht('%s created this macro.', $author); + } - return $types; + public function getCreateObjectTitleForFeed($author, $object) { + return pht('%s created %s.', $author, $object); } protected function applyCustomExternalTransaction( diff --git a/src/applications/macro/storage/PhabricatorFileImageMacro.php b/src/applications/macro/storage/PhabricatorFileImageMacro.php index bc23e639d7..0cd6726f5f 100644 --- a/src/applications/macro/storage/PhabricatorFileImageMacro.php +++ b/src/applications/macro/storage/PhabricatorFileImageMacro.php @@ -41,6 +41,12 @@ final class PhabricatorFileImageMacro extends PhabricatorFileDAO return $this->assertAttached($this->audio); } + public static function initializeNewFileImageMacro(PhabricatorUser $actor) { + $macro = id(new self()) + ->setAuthorPHID($actor->getPHID()); + return $macro; + } + protected function getConfiguration() { return array( self::CONFIG_AUX_PHID => true, @@ -80,6 +86,10 @@ final class PhabricatorFileImageMacro extends PhabricatorFileDAO return parent::save(); } + public function getViewURI() { + return '/macro/view/'.$this->getID().'/'; + } + /* -( PhabricatorApplicationTransactionInterface )------------------------- */ @@ -128,11 +138,19 @@ final class PhabricatorFileImageMacro extends PhabricatorFileDAO public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, ); } public function getPolicy($capability) { - return PhabricatorPolicies::getMostOpenPolicy(); + switch ($capability) { + case PhabricatorPolicyCapability::CAN_VIEW: + return PhabricatorPolicies::getMostOpenPolicy(); + case PhabricatorPolicyCapability::CAN_EDIT: + $app = PhabricatorApplication::getByClass( + 'PhabricatorMacroApplication'); + return $app->getPolicy(PhabricatorMacroManageCapability::CAPABILITY); + } } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { diff --git a/src/applications/macro/xaction/PhabricatorMacroFileTransaction.php b/src/applications/macro/xaction/PhabricatorMacroFileTransaction.php index 40e51fe1df..77c9f24dd9 100644 --- a/src/applications/macro/xaction/PhabricatorMacroFileTransaction.php +++ b/src/applications/macro/xaction/PhabricatorMacroFileTransaction.php @@ -26,6 +26,41 @@ final class PhabricatorMacroFileTransaction $this->renderObject()); } + public function validateTransactions($object, array $xactions) { + $errors = array(); + $viewer = $this->getActor(); + + foreach ($xactions as $xaction) { + $file_phid = $xaction->getNewValue(); + + if ($this->isEmptyTextTransaction($file_phid, $xactions)) { + $errors[] = $this->newRequiredError( + pht('Image macros must have a file.')); + } + + $file = id(new PhabricatorFileQuery()) + ->setViewer($viewer) + ->withPHIDs(array($file_phid)) + ->executeOne(); + + if (!$file) { + $errors[] = $this->newInvalidError( + pht('"%s" is not a valid file PHID.', + $file_phid)); + } else { + if (!$file->isViewableInBrowser()) { + $mime_type = $file->getMimeType(); + $errors[] = $this->newInvalidError( + pht('File mime type of "%s" is not a valid viewable image.', + $mime_type)); + } + } + + } + + return $errors; + } + public function getIcon() { return 'fa-file-image-o'; } diff --git a/src/applications/macro/xaction/PhabricatorMacroNameTransaction.php b/src/applications/macro/xaction/PhabricatorMacroNameTransaction.php index ebd81530f5..5b7b6f4417 100644 --- a/src/applications/macro/xaction/PhabricatorMacroNameTransaction.php +++ b/src/applications/macro/xaction/PhabricatorMacroNameTransaction.php @@ -32,6 +32,7 @@ final class PhabricatorMacroNameTransaction public function validateTransactions($object, array $xactions) { $errors = array(); + $viewer = $this->getActor(); if ($this->isEmptyTextTransaction($object->getName(), $xactions)) { $errors[] = $this->newRequiredError( @@ -40,13 +41,37 @@ final class PhabricatorMacroNameTransaction $max_length = $object->getColumnMaximumByteLength('name'); foreach ($xactions as $xaction) { + $old_value = $this->generateOldValue($object); $new_value = $xaction->getNewValue(); + $new_length = strlen($new_value); if ($new_length > $max_length) { $errors[] = $this->newInvalidError( pht('The name can be no longer than %s characters.', new PhutilNumber($max_length))); } + + if (!preg_match('/^[a-z0-9:_-]{3,}\z/', $new_value)) { + $errors[] = $this->newInvalidError( + pht('Macro name "%s" be at least three characters long and contain '. + 'only lowercase letters, digits, hyphens, colons and '. + 'underscores.', + $new_value)); + } + + // Check name is unique when updating / creating + if ($old_value != $new_value) { + $macro = id(new PhabricatorMacroQuery()) + ->setViewer($viewer) + ->withNames(array($new_value)) + ->executeOne(); + + if ($macro) { + $errors[] = $this->newInvalidError( + pht('Macro "%s" already exists.', $new_value)); + } + } + } return $errors; From 4aec809b69e2b314cf5b620f098a694895b326fa Mon Sep 17 00:00:00 2001 From: Chad Little Date: Wed, 3 May 2017 09:26:20 -0700 Subject: [PATCH 13/25] Update PhamePost for modular transactions Summary: Updates PhamePost for modular transactions. Test Plan: - Create a post - Edit a post - Add a header image - Delete header image - Award Token - Leave comment - Unpublish post - Check History page - Move post - Archive post {F4936456} Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Differential Revision: https://secure.phabricator.com/D17818 --- src/__phutil_library_map__.php | 16 +- .../post/PhamePostArchiveController.php | 2 +- .../post/PhamePostHeaderPictureController.php | 2 +- .../post/PhamePostMoveController.php | 2 +- .../post/PhamePostPublishController.php | 2 +- .../phame/editor/PhamePostEditEngine.php | 10 +- .../phame/editor/PhamePostEditor.php | 172 +---------- .../phame/storage/PhamePostTransaction.php | 270 +----------------- .../xaction/PhameBlogNameTransaction.php | 2 +- .../xaction/PhameBlogStatusTransaction.php | 10 +- .../xaction/PhamePostBlogTransaction.php | 64 +++++ .../xaction/PhamePostBodyTransaction.php | 60 ++++ .../PhamePostHeaderImageTransaction.php | 33 +++ .../xaction/PhamePostSubtitleTransaction.php | 63 ++++ .../xaction/PhamePostTitleTransaction.php | 55 ++++ .../xaction/PhamePostTransactionType.php | 4 + .../PhamePostVisibilityTransaction.php | 70 +++++ 17 files changed, 392 insertions(+), 445 deletions(-) create mode 100644 src/applications/phame/xaction/PhamePostBlogTransaction.php create mode 100644 src/applications/phame/xaction/PhamePostBodyTransaction.php create mode 100644 src/applications/phame/xaction/PhamePostHeaderImageTransaction.php create mode 100644 src/applications/phame/xaction/PhamePostSubtitleTransaction.php create mode 100644 src/applications/phame/xaction/PhamePostTitleTransaction.php create mode 100644 src/applications/phame/xaction/PhamePostTransactionType.php create mode 100644 src/applications/phame/xaction/PhamePostVisibilityTransaction.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 7716a29ce7..70c5ea2cf1 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -4272,12 +4272,15 @@ phutil_register_library_map(array( 'PhameNextPostView' => 'applications/phame/view/PhameNextPostView.php', 'PhamePost' => 'applications/phame/storage/PhamePost.php', 'PhamePostArchiveController' => 'applications/phame/controller/post/PhamePostArchiveController.php', + 'PhamePostBlogTransaction' => 'applications/phame/xaction/PhamePostBlogTransaction.php', + 'PhamePostBodyTransaction' => 'applications/phame/xaction/PhamePostBodyTransaction.php', 'PhamePostController' => 'applications/phame/controller/post/PhamePostController.php', 'PhamePostEditConduitAPIMethod' => 'applications/phame/conduit/PhamePostEditConduitAPIMethod.php', 'PhamePostEditController' => 'applications/phame/controller/post/PhamePostEditController.php', 'PhamePostEditEngine' => 'applications/phame/editor/PhamePostEditEngine.php', 'PhamePostEditor' => 'applications/phame/editor/PhamePostEditor.php', 'PhamePostFulltextEngine' => 'applications/phame/search/PhamePostFulltextEngine.php', + 'PhamePostHeaderImageTransaction' => 'applications/phame/xaction/PhamePostHeaderImageTransaction.php', 'PhamePostHeaderPictureController' => 'applications/phame/controller/post/PhamePostHeaderPictureController.php', 'PhamePostHistoryController' => 'applications/phame/controller/post/PhamePostHistoryController.php', 'PhamePostListController' => 'applications/phame/controller/post/PhamePostListController.php', @@ -4290,10 +4293,14 @@ phutil_register_library_map(array( 'PhamePostReplyHandler' => 'applications/phame/mail/PhamePostReplyHandler.php', 'PhamePostSearchConduitAPIMethod' => 'applications/phame/conduit/PhamePostSearchConduitAPIMethod.php', 'PhamePostSearchEngine' => 'applications/phame/query/PhamePostSearchEngine.php', + 'PhamePostSubtitleTransaction' => 'applications/phame/xaction/PhamePostSubtitleTransaction.php', + 'PhamePostTitleTransaction' => 'applications/phame/xaction/PhamePostTitleTransaction.php', 'PhamePostTransaction' => 'applications/phame/storage/PhamePostTransaction.php', 'PhamePostTransactionComment' => 'applications/phame/storage/PhamePostTransactionComment.php', 'PhamePostTransactionQuery' => 'applications/phame/query/PhamePostTransactionQuery.php', + 'PhamePostTransactionType' => 'applications/phame/xaction/PhamePostTransactionType.php', 'PhamePostViewController' => 'applications/phame/controller/post/PhamePostViewController.php', + 'PhamePostVisibilityTransaction' => 'applications/phame/xaction/PhamePostVisibilityTransaction.php', 'PhameSchemaSpec' => 'applications/phame/storage/PhameSchemaSpec.php', 'PhameSite' => 'applications/phame/site/PhameSite.php', 'PhluxController' => 'applications/phlux/controller/PhluxController.php', @@ -9753,12 +9760,15 @@ phutil_register_library_map(array( 'PhabricatorFulltextInterface', ), 'PhamePostArchiveController' => 'PhamePostController', + 'PhamePostBlogTransaction' => 'PhamePostTransactionType', + 'PhamePostBodyTransaction' => 'PhamePostTransactionType', 'PhamePostController' => 'PhameController', 'PhamePostEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod', 'PhamePostEditController' => 'PhamePostController', 'PhamePostEditEngine' => 'PhabricatorEditEngine', 'PhamePostEditor' => 'PhabricatorApplicationTransactionEditor', 'PhamePostFulltextEngine' => 'PhabricatorFulltextEngine', + 'PhamePostHeaderImageTransaction' => 'PhamePostTransactionType', 'PhamePostHeaderPictureController' => 'PhamePostController', 'PhamePostHistoryController' => 'PhamePostController', 'PhamePostListController' => 'PhamePostController', @@ -9771,10 +9781,14 @@ phutil_register_library_map(array( 'PhamePostReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler', 'PhamePostSearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod', 'PhamePostSearchEngine' => 'PhabricatorApplicationSearchEngine', - 'PhamePostTransaction' => 'PhabricatorApplicationTransaction', + 'PhamePostSubtitleTransaction' => 'PhamePostTransactionType', + 'PhamePostTitleTransaction' => 'PhamePostTransactionType', + 'PhamePostTransaction' => 'PhabricatorModularTransaction', 'PhamePostTransactionComment' => 'PhabricatorApplicationTransactionComment', 'PhamePostTransactionQuery' => 'PhabricatorApplicationTransactionQuery', + 'PhamePostTransactionType' => 'PhabricatorModularTransactionType', 'PhamePostViewController' => 'PhameLiveController', + 'PhamePostVisibilityTransaction' => 'PhamePostTransactionType', 'PhameSchemaSpec' => 'PhabricatorConfigSchemaSpec', 'PhameSite' => 'PhabricatorSite', 'PhluxController' => 'PhabricatorController', diff --git a/src/applications/phame/controller/post/PhamePostArchiveController.php b/src/applications/phame/controller/post/PhamePostArchiveController.php index 5a3b32944a..b8647121ef 100644 --- a/src/applications/phame/controller/post/PhamePostArchiveController.php +++ b/src/applications/phame/controller/post/PhamePostArchiveController.php @@ -26,7 +26,7 @@ final class PhamePostArchiveController extends PhamePostController { $new_value = PhameConstants::VISIBILITY_ARCHIVED; $xactions[] = id(new PhamePostTransaction()) - ->setTransactionType(PhamePostTransaction::TYPE_VISIBILITY) + ->setTransactionType(PhamePostVisibilityTransaction::TRANSACTIONTYPE) ->setNewValue($new_value); id(new PhamePostEditor()) diff --git a/src/applications/phame/controller/post/PhamePostHeaderPictureController.php b/src/applications/phame/controller/post/PhamePostHeaderPictureController.php index 2e60c9ba71..60075cc077 100644 --- a/src/applications/phame/controller/post/PhamePostHeaderPictureController.php +++ b/src/applications/phame/controller/post/PhamePostHeaderPictureController.php @@ -61,7 +61,7 @@ final class PhamePostHeaderPictureController $xactions = array(); $xactions[] = id(new PhamePostTransaction()) - ->setTransactionType(PhamePostTransaction::TYPE_HEADERIMAGE) + ->setTransactionType(PhamePostHeaderImageTransaction::TRANSACTIONTYPE) ->setNewValue($new_value); $editor = id(new PhamePostEditor()) diff --git a/src/applications/phame/controller/post/PhamePostMoveController.php b/src/applications/phame/controller/post/PhamePostMoveController.php index 3e09a9ba2d..d088b260b5 100644 --- a/src/applications/phame/controller/post/PhamePostMoveController.php +++ b/src/applications/phame/controller/post/PhamePostMoveController.php @@ -28,7 +28,7 @@ final class PhamePostMoveController extends PhamePostController { $xactions = array(); $xactions[] = id(new PhamePostTransaction()) - ->setTransactionType(PhamePostTransaction::TYPE_BLOG) + ->setTransactionType(PhamePostBlogTransaction::TRANSACTIONTYPE) ->setNewValue($v_blog); $editor = id(new PhamePostEditor()) diff --git a/src/applications/phame/controller/post/PhamePostPublishController.php b/src/applications/phame/controller/post/PhamePostPublishController.php index 567099f0d4..70989082bd 100644 --- a/src/applications/phame/controller/post/PhamePostPublishController.php +++ b/src/applications/phame/controller/post/PhamePostPublishController.php @@ -34,7 +34,7 @@ final class PhamePostPublishController extends PhamePostController { } $xactions[] = id(new PhamePostTransaction()) - ->setTransactionType(PhamePostTransaction::TYPE_VISIBILITY) + ->setTransactionType(PhamePostVisibilityTransaction::TRANSACTIONTYPE) ->setNewValue($new_value); id(new PhamePostEditor()) diff --git a/src/applications/phame/editor/PhamePostEditEngine.php b/src/applications/phame/editor/PhamePostEditEngine.php index e80c1f6d0d..af1b1091d1 100644 --- a/src/applications/phame/editor/PhamePostEditEngine.php +++ b/src/applications/phame/editor/PhamePostEditEngine.php @@ -84,7 +84,7 @@ final class PhamePostEditEngine pht('Choose a blog to create a post on (or move a post to).')) ->setConduitTypeDescription(pht('PHID of the blog.')) ->setAliases(array('blogPHID')) - ->setTransactionType(PhamePostTransaction::TYPE_BLOG) + ->setTransactionType(PhamePostBlogTransaction::TRANSACTIONTYPE) ->setHandleParameterType(new AphrontPHIDListHTTPParameterType()) ->setSingleValue($blog_phid) ->setIsReorderable(false) @@ -97,7 +97,7 @@ final class PhamePostEditEngine ->setDescription(pht('Post title.')) ->setConduitDescription(pht('Retitle the post.')) ->setConduitTypeDescription(pht('New post title.')) - ->setTransactionType(PhamePostTransaction::TYPE_TITLE) + ->setTransactionType(PhamePostTitleTransaction::TRANSACTIONTYPE) ->setValue($object->getTitle()), id(new PhabricatorTextEditField()) ->setKey('subtitle') @@ -105,7 +105,7 @@ final class PhamePostEditEngine ->setDescription(pht('Post subtitle.')) ->setConduitDescription(pht('Change the post subtitle.')) ->setConduitTypeDescription(pht('New post subtitle.')) - ->setTransactionType(PhamePostTransaction::TYPE_SUBTITLE) + ->setTransactionType(PhamePostSubtitleTransaction::TRANSACTIONTYPE) ->setValue($object->getSubtitle()), id(new PhabricatorSelectEditField()) ->setKey('visibility') @@ -113,7 +113,7 @@ final class PhamePostEditEngine ->setDescription(pht('Post visibility.')) ->setConduitDescription(pht('Change post visibility.')) ->setConduitTypeDescription(pht('New post visibility constant.')) - ->setTransactionType(PhamePostTransaction::TYPE_VISIBILITY) + ->setTransactionType(PhamePostVisibilityTransaction::TRANSACTIONTYPE) ->setValue($object->getVisibility()) ->setOptions(PhameConstants::getPhamePostStatusMap()), id(new PhabricatorRemarkupEditField()) @@ -122,7 +122,7 @@ final class PhamePostEditEngine ->setDescription(pht('Post body.')) ->setConduitDescription(pht('Change post body.')) ->setConduitTypeDescription(pht('New post body.')) - ->setTransactionType(PhamePostTransaction::TYPE_BODY) + ->setTransactionType(PhamePostBodyTransaction::TRANSACTIONTYPE) ->setValue($object->getBody()) ->setPreviewPanel( id(new PHUIRemarkupPreviewPanel()) diff --git a/src/applications/phame/editor/PhamePostEditor.php b/src/applications/phame/editor/PhamePostEditor.php index 929613fe80..8f0e2b5099 100644 --- a/src/applications/phame/editor/PhamePostEditor.php +++ b/src/applications/phame/editor/PhamePostEditor.php @@ -11,177 +11,21 @@ final class PhamePostEditor return pht('Phame Posts'); } + public function getCreateObjectTitle($author, $object) { + return pht('%s created this post.', $author); + } + + public function getCreateObjectTitleForFeed($author, $object) { + return pht('%s created %s.', $author, $object); + } + public function getTransactionTypes() { $types = parent::getTransactionTypes(); - - $types[] = PhamePostTransaction::TYPE_BLOG; - $types[] = PhamePostTransaction::TYPE_TITLE; - $types[] = PhamePostTransaction::TYPE_SUBTITLE; - $types[] = PhamePostTransaction::TYPE_BODY; - $types[] = PhamePostTransaction::TYPE_VISIBILITY; - $types[] = PhamePostTransaction::TYPE_HEADERIMAGE; $types[] = PhabricatorTransactions::TYPE_COMMENT; return $types; } - protected function getCustomTransactionOldValue( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case PhamePostTransaction::TYPE_BLOG: - return $object->getBlogPHID(); - case PhamePostTransaction::TYPE_TITLE: - return $object->getTitle(); - case PhamePostTransaction::TYPE_SUBTITLE: - return $object->getSubtitle(); - case PhamePostTransaction::TYPE_BODY: - return $object->getBody(); - case PhamePostTransaction::TYPE_VISIBILITY: - return $object->getVisibility(); - case PhamePostTransaction::TYPE_HEADERIMAGE: - return $object->getHeaderImagePHID(); - } - } - - protected function getCustomTransactionNewValue( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case PhamePostTransaction::TYPE_TITLE: - case PhamePostTransaction::TYPE_SUBTITLE: - case PhamePostTransaction::TYPE_BODY: - case PhamePostTransaction::TYPE_VISIBILITY: - case PhamePostTransaction::TYPE_HEADERIMAGE: - case PhamePostTransaction::TYPE_BLOG: - return $xaction->getNewValue(); - } - } - - protected function applyCustomInternalTransaction( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case PhamePostTransaction::TYPE_TITLE: - return $object->setTitle($xaction->getNewValue()); - case PhamePostTransaction::TYPE_SUBTITLE: - return $object->setSubtitle($xaction->getNewValue()); - case PhamePostTransaction::TYPE_BODY: - return $object->setBody($xaction->getNewValue()); - case PhamePostTransaction::TYPE_BLOG: - return $object->setBlogPHID($xaction->getNewValue()); - case PhamePostTransaction::TYPE_HEADERIMAGE: - return $object->setHeaderImagePHID($xaction->getNewValue()); - case PhamePostTransaction::TYPE_VISIBILITY: - if ($xaction->getNewValue() == PhameConstants::VISIBILITY_DRAFT) { - $object->setDatePublished(0); - } else if ($xaction->getNewValue() == - PhameConstants::VISIBILITY_ARCHIVED) { - $object->setDatePublished(0); - } else { - $object->setDatePublished(PhabricatorTime::getNow()); - } - return $object->setVisibility($xaction->getNewValue()); - } - - return parent::applyCustomInternalTransaction($object, $xaction); - } - - protected function applyCustomExternalTransaction( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case PhamePostTransaction::TYPE_TITLE: - case PhamePostTransaction::TYPE_SUBTITLE: - case PhamePostTransaction::TYPE_BODY: - case PhamePostTransaction::TYPE_VISIBILITY: - case PhamePostTransaction::TYPE_HEADERIMAGE: - case PhamePostTransaction::TYPE_BLOG: - return; - } - - return parent::applyCustomExternalTransaction($object, $xaction); - } - - protected function validateTransaction( - PhabricatorLiskDAO $object, - $type, - array $xactions) { - - $errors = parent::validateTransaction($object, $type, $xactions); - - switch ($type) { - case PhamePostTransaction::TYPE_TITLE: - $missing = $this->validateIsEmptyTextField( - $object->getTitle(), - $xactions); - - if ($missing) { - $error = new PhabricatorApplicationTransactionValidationError( - $type, - pht('Required'), - pht('Title is required.'), - nonempty(last($xactions), null)); - - $error->setIsMissingFieldError(true); - $errors[] = $error; - } - break; - case PhamePostTransaction::TYPE_BLOG: - if ($this->getIsNewObject()) { - if (!$xactions) { - $error = new PhabricatorApplicationTransactionValidationError( - $type, - pht('Required'), - pht( - 'When creating a post, you must specify which blog it '. - 'should belong to.'), - null); - - $error->setIsMissingFieldError(true); - - $errors[] = $error; - break; - } - } - - foreach ($xactions as $xaction) { - $new_phid = $xaction->getNewValue(); - - $blog = id(new PhameBlogQuery()) - ->setViewer($this->getActor()) - ->withPHIDs(array($new_phid)) - ->requireCapabilities( - array( - PhabricatorPolicyCapability::CAN_VIEW, - PhabricatorPolicyCapability::CAN_EDIT, - )) - ->execute(); - - if ($blog) { - continue; - } - - $errors[] = new PhabricatorApplicationTransactionValidationError( - $type, - pht('Invalid'), - pht( - 'The specified blog PHID ("%s") is not valid. You can only '. - 'create a post on (or move a post into) a blog which you '. - 'have permission to see and edit.', - $new_phid), - $xaction); - } - - break; - } - return $errors; - } - protected function shouldSendMail( PhabricatorLiskDAO $object, array $xactions) { diff --git a/src/applications/phame/storage/PhamePostTransaction.php b/src/applications/phame/storage/PhamePostTransaction.php index 6e54aeda6d..1c259911f3 100644 --- a/src/applications/phame/storage/PhamePostTransaction.php +++ b/src/applications/phame/storage/PhamePostTransaction.php @@ -1,14 +1,7 @@ getTransactionType()) { - case self::TYPE_BODY: - $blocks[] = $this->getNewValue(); - break; - } - - return $blocks; - } - - public function shouldHide() { - return parent::shouldHide(); - } - - public function getRequiredHandlePHIDs() { - $phids = parent::getRequiredHandlePHIDs(); - - switch ($this->getTransactionType()) { - case self::TYPE_BLOG: - $old = $this->getOldValue(); - $new = $this->getNewValue(); - - if ($old) { - $phids[] = $old; - } - - if ($new) { - $phids[] = $new; - } - break; - } - - return $phids; - } - - - public function getIcon() { - $old = $this->getOldValue(); - $new = $this->getNewValue(); - switch ($this->getTransactionType()) { - case PhabricatorTransactions::TYPE_CREATE: - return 'fa-plus'; - break; - case self::TYPE_HEADERIMAGE: - return 'fa-camera-retro'; - break; - case self::TYPE_VISIBILITY: - if ($new == PhameConstants::VISIBILITY_PUBLISHED) { - return 'fa-globe'; - } else if ($new == PhameConstants::VISIBILITY_ARCHIVED) { - return 'fa-ban'; - } else { - return 'fa-eye-slash'; - } - break; - } - return parent::getIcon(); - } - public function getMailTags() { $tags = parent::getMailTags(); @@ -110,200 +46,4 @@ final class PhamePostTransaction return $tags; } - - public function getTitle() { - $author_phid = $this->getAuthorPHID(); - $object_phid = $this->getObjectPHID(); - - $old = $this->getOldValue(); - $new = $this->getNewValue(); - - $type = $this->getTransactionType(); - switch ($type) { - case PhabricatorTransactions::TYPE_CREATE: - return pht( - '%s authored this post.', - $this->renderHandleLink($author_phid)); - case self::TYPE_BLOG: - return pht( - '%s moved this post from "%s" to "%s".', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($old), - $this->renderHandleLink($new)); - case self::TYPE_TITLE: - if ($old === null) { - return pht( - '%s authored this post.', - $this->renderHandleLink($author_phid)); - } else { - return pht( - '%s updated the post\'s name to "%s".', - $this->renderHandleLink($author_phid), - $new); - } - break; - case self::TYPE_SUBTITLE: - if ($old === null) { - return pht( - '%s set the post\'s subtitle to "%s".', - $this->renderHandleLink($author_phid), - $new); - } else { - return pht( - '%s updated the post\'s subtitle to "%s".', - $this->renderHandleLink($author_phid), - $new); - } - break; - case self::TYPE_BODY: - return pht( - '%s updated the blog post.', - $this->renderHandleLink($author_phid)); - break; - case self::TYPE_HEADERIMAGE: - return pht( - '%s updated the header image.', - $this->renderHandleLink($author_phid)); - break; - case self::TYPE_VISIBILITY: - if ($new == PhameConstants::VISIBILITY_DRAFT) { - return pht( - '%s marked this post as a draft.', - $this->renderHandleLink($author_phid)); - } else if ($new == PhameConstants::VISIBILITY_ARCHIVED) { - return pht( - '%s archived this post.', - $this->renderHandleLink($author_phid)); - } else { - return pht( - '%s published this post.', - $this->renderHandleLink($author_phid)); - } - break; - } - - return parent::getTitle(); - } - - public function getTitleForFeed() { - $author_phid = $this->getAuthorPHID(); - $object_phid = $this->getObjectPHID(); - - $old = $this->getOldValue(); - $new = $this->getNewValue(); - - $type = $this->getTransactionType(); - switch ($type) { - case PhabricatorTransactions::TYPE_CREATE: - return pht( - '%s authored %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - case self::TYPE_BLOG: - return pht( - '%s moved post "%s" from "%s" to "%s".', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid), - $this->renderHandleLink($old), - $this->renderHandleLink($new)); - case self::TYPE_TITLE: - if ($old === null) { - return pht( - '%s authored %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - } else { - return pht( - '%s updated the name for %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - } - break; - case self::TYPE_SUBTITLE: - return pht( - '%s updated the subtitle for %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - break; - case self::TYPE_BODY: - return pht( - '%s updated the blog post %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - break; - case self::TYPE_HEADERIMAGE: - return pht( - '%s updated the header image for post %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - break; - case self::TYPE_VISIBILITY: - if ($new == PhameConstants::VISIBILITY_DRAFT) { - return pht( - '%s marked %s as a draft.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - } else if ($new == PhameConstants::VISIBILITY_ARCHIVED) { - return pht( - '%s marked %s as archived.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - } else { - return pht( - '%s published %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - } - break; - } - - return parent::getTitleForFeed(); - } - - public function getRemarkupBodyForFeed(PhabricatorFeedStory $story) { - $old = $this->getOldValue(); - - switch ($this->getTransactionType()) { - case self::TYPE_BODY: - if ($old === null) { - return $this->getNewValue(); - } - break; - } - - return null; - } - - public function getColor() { - switch ($this->getTransactionType()) { - case PhabricatorTransactions::TYPE_CREATE: - return PhabricatorTransactions::COLOR_GREEN; - } - return parent::getColor(); - } - - public function hasChangeDetails() { - switch ($this->getTransactionType()) { - case self::TYPE_BODY: - return ($this->getOldValue() !== null); - } - - return parent::hasChangeDetails(); - } - - public function renderChangeDetails(PhabricatorUser $viewer) { - switch ($this->getTransactionType()) { - case self::TYPE_BODY: - $old = $this->getOldValue(); - $new = $this->getNewValue(); - - return $this->renderTextCorpusChangeDetails( - $viewer, - $old, - $new); - } - - return parent::renderChangeDetails($viewer); - } - } diff --git a/src/applications/phame/xaction/PhameBlogNameTransaction.php b/src/applications/phame/xaction/PhameBlogNameTransaction.php index dbca5304a8..c219ba494b 100644 --- a/src/applications/phame/xaction/PhameBlogNameTransaction.php +++ b/src/applications/phame/xaction/PhameBlogNameTransaction.php @@ -23,7 +23,7 @@ final class PhameBlogNameTransaction public function getTitleForFeed() { return pht( - '%s renamed %s blog froms %s to %s.', + '%s renamed %s blog from %s to %s.', $this->renderAuthor(), $this->renderObject(), $this->renderOldValue(), diff --git a/src/applications/phame/xaction/PhameBlogStatusTransaction.php b/src/applications/phame/xaction/PhameBlogStatusTransaction.php index 21345ea249..b3366bece7 100644 --- a/src/applications/phame/xaction/PhameBlogStatusTransaction.php +++ b/src/applications/phame/xaction/PhameBlogStatusTransaction.php @@ -45,11 +45,11 @@ final class PhameBlogStatusTransaction public function getIcon() { $new = $this->getNewValue(); - if ($new == PhameBlog::STATUS_ARCHIVED) { - return 'fa-ban'; - } else { - return 'fa-check'; - } + if ($new == PhameBlog::STATUS_ARCHIVED) { + return 'fa-ban'; + } else { + return 'fa-check'; } + } } diff --git a/src/applications/phame/xaction/PhamePostBlogTransaction.php b/src/applications/phame/xaction/PhamePostBlogTransaction.php new file mode 100644 index 0000000000..cfe335a6ce --- /dev/null +++ b/src/applications/phame/xaction/PhamePostBlogTransaction.php @@ -0,0 +1,64 @@ +getBlogPHID(); + } + + public function applyInternalEffects($object, $value) { + $object->setBlogPHID($value); + } + + public function getTitle() { + return pht( + '%s changed the blog for this post.', + $this->renderAuthor()); + } + + public function getTitleForFeed() { + return pht( + '%s changed the blog for post %s.', + $this->renderAuthor(), + $this->renderObject()); + } + + public function validateTransactions($object, array $xactions) { + $errors = array(); + + if ($this->isEmptyTextTransaction($object->getBlogPHID(), $xactions)) { + $errors[] = $this->newRequiredError( + pht('Posts must be attached to a blog.')); + } + + foreach ($xactions as $xaction) { + $new_phid = $xaction->getNewValue(); + + $blog = id(new PhameBlogQuery()) + ->setViewer($this->getActor()) + ->withPHIDs(array($new_phid)) + ->requireCapabilities( + array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + )) + ->execute(); + + if ($blog) { + continue; + } + + $errors[] = $this->newInvalidError( + pht('The specified blog PHID ("%s") is not valid. You can only '. + 'create a post on (or move a post into) a blog which you '. + 'have permission to see and edit.', + $new_phid)); + } + + return $errors; + } + +} diff --git a/src/applications/phame/xaction/PhamePostBodyTransaction.php b/src/applications/phame/xaction/PhamePostBodyTransaction.php new file mode 100644 index 0000000000..bf34cf73ff --- /dev/null +++ b/src/applications/phame/xaction/PhamePostBodyTransaction.php @@ -0,0 +1,60 @@ +getBody(); + } + + public function applyInternalEffects($object, $value) { + $object->setBody($value); + } + + public function getTitle() { + return pht( + '%s updated the post content.', + $this->renderAuthor()); + } + + public function getTitleForFeed() { + return pht( + '%s updated the post content for %s.', + $this->renderAuthor(), + $this->renderObject()); + } + + public function hasChangeDetailView() { + return true; + } + + public function getMailDiffSectionHeader() { + return pht('CHANGES TO POST CONTENT'); + } + + public function newChangeDetailView() { + $viewer = $this->getViewer(); + + return id(new PhabricatorApplicationTransactionTextDiffDetailView()) + ->setViewer($viewer) + ->setOldText($this->getOldValue()) + ->setNewText($this->getNewValue()); + } + + public function newRemarkupChanges() { + $changes = array(); + + $changes[] = $this->newRemarkupChange() + ->setOldValue($this->getOldValue()) + ->setNewValue($this->getNewValue()); + + return $changes; + } + + public function getIcon() { + return 'fa-file-text-o'; + } + +} diff --git a/src/applications/phame/xaction/PhamePostHeaderImageTransaction.php b/src/applications/phame/xaction/PhamePostHeaderImageTransaction.php new file mode 100644 index 0000000000..2b9631cdc4 --- /dev/null +++ b/src/applications/phame/xaction/PhamePostHeaderImageTransaction.php @@ -0,0 +1,33 @@ +getHeaderImagePHID(); + } + + public function applyInternalEffects($object, $value) { + $object->setHeaderImagePHID($value); + } + + public function getTitle() { + return pht( + '%s changed the header image for this post.', + $this->renderAuthor()); + } + + public function getTitleForFeed() { + return pht( + '%s changed the header image for post %s.', + $this->renderAuthor(), + $this->renderObject()); + } + + public function getIcon() { + return 'fa-camera'; + } + +} diff --git a/src/applications/phame/xaction/PhamePostSubtitleTransaction.php b/src/applications/phame/xaction/PhamePostSubtitleTransaction.php new file mode 100644 index 0000000000..05b0f34790 --- /dev/null +++ b/src/applications/phame/xaction/PhamePostSubtitleTransaction.php @@ -0,0 +1,63 @@ +getSubtitle(); + } + + public function applyInternalEffects($object, $value) { + $object->setSubtitle($value); + } + + public function getTitle() { + $old = $this->getOldValue(); + if ($old === null) { + return pht( + '%s set this post\'s subtitle to "%s".', + $this->renderAuthor(), + $this->renderNewValue()); + } else { + return pht( + '%s updated the post\'s subtitle to "%s".', + $this->renderAuthor(), + $this->renderNewValue()); + } + } + + public function getTitleForFeed() { + $old = $this->getOldValue(); + if ($old === null) { + return pht( + '%s set the subtitle for %s.', + $this->renderAuthor(), + $this->renderObject()); + } else { + return pht( + '%s updated the subtitle for %s.', + $this->renderAuthor(), + $this->renderObject()); + } + } + + public function validateTransactions($object, array $xactions) { + $errors = array(); + + $max_length = $object->getColumnMaximumByteLength('subtitle'); + foreach ($xactions as $xaction) { + $new_value = $xaction->getNewValue(); + $new_length = strlen($new_value); + if ($new_length > $max_length) { + $errors[] = $this->newInvalidError( + pht('The subtitle can be no longer than %s characters.', + new PhutilNumber($max_length))); + } + } + + return $errors; + } + +} diff --git a/src/applications/phame/xaction/PhamePostTitleTransaction.php b/src/applications/phame/xaction/PhamePostTitleTransaction.php new file mode 100644 index 0000000000..99c556cc3a --- /dev/null +++ b/src/applications/phame/xaction/PhamePostTitleTransaction.php @@ -0,0 +1,55 @@ +getTitle(); + } + + public function applyInternalEffects($object, $value) { + $object->setTitle($value); + } + + public function getTitle() { + return pht( + '%s renamed this blog post from %s to %s.', + $this->renderAuthor(), + $this->renderOldValue(), + $this->renderNewValue()); + } + + public function getTitleForFeed() { + return pht( + '%s renamed %s blog post from %s to %s.', + $this->renderAuthor(), + $this->renderObject(), + $this->renderOldValue(), + $this->renderNewValue()); + } + + public function validateTransactions($object, array $xactions) { + $errors = array(); + + if ($this->isEmptyTextTransaction($object->getTitle(), $xactions)) { + $errors[] = $this->newRequiredError( + pht('Posts must have a title.')); + } + + $max_length = $object->getColumnMaximumByteLength('title'); + foreach ($xactions as $xaction) { + $new_value = $xaction->getNewValue(); + $new_length = strlen($new_value); + if ($new_length > $max_length) { + $errors[] = $this->newInvalidError( + pht('The title can be no longer than %s characters.', + new PhutilNumber($max_length))); + } + } + + return $errors; + } + +} diff --git a/src/applications/phame/xaction/PhamePostTransactionType.php b/src/applications/phame/xaction/PhamePostTransactionType.php new file mode 100644 index 0000000000..b8ce182bc7 --- /dev/null +++ b/src/applications/phame/xaction/PhamePostTransactionType.php @@ -0,0 +1,4 @@ +getVisibility(); + } + + public function applyInternalEffects($object, $value) { + if ($value == PhameConstants::VISIBILITY_DRAFT) { + $object->setDatePublished(0); + } else if ($value == PhameConstants::VISIBILITY_ARCHIVED) { + $object->setDatePublished(0); + } else { + $object->setDatePublished(PhabricatorTime::getNow()); + } + $object->setVisibility($value); + } + + public function getTitle() { + $new = $this->getNewValue(); + if ($new == PhameConstants::VISIBILITY_DRAFT) { + return pht( + '%s marked this post as a draft.', + $this->renderAuthor()); + } else if ($new == PhameConstants::VISIBILITY_ARCHIVED) { + return pht( + '%s archived this post.', + $this->renderAuthor()); + } else { + return pht( + '%s published this post.', + $this->renderAuthor()); + } + } + + public function getTitleForFeed() { + $new = $this->getNewValue(); + if ($new == PhameConstants::VISIBILITY_DRAFT) { + return pht( + '%s marked %s as a draft.', + $this->renderAuthor(), + $this->renderObject()); + } else if ($new == PhameConstants::VISIBILITY_ARCHIVED) { + return pht( + '%s marked %s as archived.', + $this->renderAuthor(), + $this->renderObject()); + } else { + return pht( + '%s published %s.', + $this->renderAuthor(), + $this->renderObject()); + } + } + + public function getIcon() { + $new = $this->getNewValue(); + if ($new == PhameConstants::VISIBILITY_PUBLISHED) { + return 'fa-rss'; + } else if ($new == PhameConstants::VISIBILITY_ARCHIVED) { + return 'fa-ban'; + } else { + return 'fa-eye-slash'; + } + } +} From d467a9e3378c3cdcdece8f54e44e9ee1f391b919 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Tue, 2 May 2017 08:52:09 -0700 Subject: [PATCH 14/25] Modernize PonderQuestion with EditEngine Summary: Just a small touch up to move this to edit engine. Test Plan: - Create a question - Edit a question - Close question - Test NUX state Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Differential Revision: https://secure.phabricator.com/D17812 --- src/__phutil_library_map__.php | 2 + .../PhabricatorPonderApplication.php | 36 +-- .../ponder/controller/PonderController.php | 10 +- .../PonderQuestionEditController.php | 221 +----------------- .../ponder/editor/PonderAnswerEditor.php | 8 + .../editor/PonderQuestionEditEngine.php | 109 +++++++++ .../ponder/editor/PonderQuestionEditor.php | 11 +- .../ponder/storage/PonderQuestion.php | 8 + .../PonderQuestionAnswerTransaction.php | 7 + 9 files changed, 170 insertions(+), 242 deletions(-) create mode 100644 src/applications/ponder/editor/PonderQuestionEditEngine.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 70c5ea2cf1..9a3f4fb538 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -4606,6 +4606,7 @@ phutil_register_library_map(array( 'PonderQuestionContentTransaction' => 'applications/ponder/xaction/PonderQuestionContentTransaction.php', 'PonderQuestionCreateMailReceiver' => 'applications/ponder/mail/PonderQuestionCreateMailReceiver.php', 'PonderQuestionEditController' => 'applications/ponder/controller/PonderQuestionEditController.php', + 'PonderQuestionEditEngine' => 'applications/ponder/editor/PonderQuestionEditEngine.php', 'PonderQuestionEditor' => 'applications/ponder/editor/PonderQuestionEditor.php', 'PonderQuestionFulltextEngine' => 'applications/ponder/search/PonderQuestionFulltextEngine.php', 'PonderQuestionHistoryController' => 'applications/ponder/controller/PonderQuestionHistoryController.php', @@ -10194,6 +10195,7 @@ phutil_register_library_map(array( 'PonderQuestionContentTransaction' => 'PonderQuestionTransactionType', 'PonderQuestionCreateMailReceiver' => 'PhabricatorMailReceiver', 'PonderQuestionEditController' => 'PonderController', + 'PonderQuestionEditEngine' => 'PhabricatorEditEngine', 'PonderQuestionEditor' => 'PonderEditor', 'PonderQuestionFulltextEngine' => 'PhabricatorFulltextEngine', 'PonderQuestionHistoryController' => 'PonderController', diff --git a/src/applications/ponder/application/PhabricatorPonderApplication.php b/src/applications/ponder/application/PhabricatorPonderApplication.php index ced8606e99..ed37c7ef6e 100644 --- a/src/applications/ponder/application/PhabricatorPonderApplication.php +++ b/src/applications/ponder/application/PhabricatorPonderApplication.php @@ -60,22 +60,26 @@ final class PhabricatorPonderApplication extends PhabricatorApplication { '/ponder/' => array( '(?:query/(?P[^/]+)/)?' => 'PonderQuestionListController', - 'answer/add/' - => 'PonderAnswerSaveController', - 'answer/edit/(?P\d+)/' - => 'PonderAnswerEditController', - 'answer/comment/(?P\d+)/' - => 'PonderAnswerCommentController', - 'answer/history/(?P\d+)/' - => 'PonderAnswerHistoryController', - 'question/edit/(?:(?P\d+)/)?' - => 'PonderQuestionEditController', - 'question/create/' - => 'PonderQuestionEditController', - 'question/comment/(?P\d+)/' - => 'PonderQuestionCommentController', - 'question/history/(?P\d+)/' - => 'PonderQuestionHistoryController', + 'answer/' => array( + 'add/' + => 'PonderAnswerSaveController', + 'edit/(?P\d+)/' + => 'PonderAnswerEditController', + 'comment/(?P\d+)/' + => 'PonderAnswerCommentController', + 'history/(?P\d+)/' + => 'PonderAnswerHistoryController', + ), + 'question/' => array( + $this->getEditRoutePattern('edit/') + => 'PonderQuestionEditController', + 'create/' + => 'PonderQuestionEditController', + 'comment/(?P\d+)/' + => 'PonderQuestionCommentController', + 'history/(?P\d+)/' + => 'PonderQuestionHistoryController', + ), 'preview/' => 'PhabricatorMarkupPreviewController', 'question/status/(?P[1-9]\d*)/' diff --git a/src/applications/ponder/controller/PonderController.php b/src/applications/ponder/controller/PonderController.php index a14d70c773..99edcc1af1 100644 --- a/src/applications/ponder/controller/PonderController.php +++ b/src/applications/ponder/controller/PonderController.php @@ -27,13 +27,9 @@ abstract class PonderController extends PhabricatorController { protected function buildApplicationCrumbs() { $crumbs = parent::buildApplicationCrumbs(); - $href = $this->getApplicationURI('question/create/'); - $crumbs - ->addAction( - id(new PHUIListItemView()) - ->setName(pht('Ask Question')) - ->setHref($href) - ->setIcon('fa-plus-square')); + id(new PonderQuestionEditEngine()) + ->setViewer($this->getViewer()) + ->addActionToCrumbs($crumbs); return $crumbs; } diff --git a/src/applications/ponder/controller/PonderQuestionEditController.php b/src/applications/ponder/controller/PonderQuestionEditController.php index c872933ca2..c881d60f92 100644 --- a/src/applications/ponder/controller/PonderQuestionEditController.php +++ b/src/applications/ponder/controller/PonderQuestionEditController.php @@ -1,222 +1,11 @@ getViewer(); - $id = $request->getURIData('id'); - - if ($id) { - $question = id(new PonderQuestionQuery()) - ->setViewer($viewer) - ->withIDs(array($id)) - ->requireCapabilities( - array( - PhabricatorPolicyCapability::CAN_VIEW, - PhabricatorPolicyCapability::CAN_EDIT, - )) - ->executeOne(); - if (!$question) { - return new Aphront404Response(); - } - $v_projects = PhabricatorEdgeQuery::loadDestinationPHIDs( - $question->getPHID(), - PhabricatorProjectObjectHasProjectEdgeType::EDGECONST); - $v_projects = array_reverse($v_projects); - $is_new = false; - } else { - $is_new = true; - $question = PonderQuestion::initializeNewQuestion($viewer); - $v_projects = array(); - } - - $v_title = $question->getTitle(); - $v_content = $question->getContent(); - $v_wiki = $question->getAnswerWiki(); - $v_view = $question->getViewPolicy(); - $v_space = $question->getSpacePHID(); - $v_status = $question->getStatus(); - - - $errors = array(); - $e_title = true; - if ($request->isFormPost()) { - $v_title = $request->getStr('title'); - $v_content = $request->getStr('content'); - $v_wiki = $request->getStr('answerWiki'); - $v_projects = $request->getArr('projects'); - $v_view = $request->getStr('viewPolicy'); - $v_space = $request->getStr('spacePHID'); - $v_status = $request->getStr('status'); - - $len = phutil_utf8_strlen($v_title); - if ($len < 1) { - $errors[] = pht('Title must not be empty.'); - $e_title = pht('Required'); - } else if ($len > 255) { - $errors[] = pht('Title is too long.'); - $e_title = pht('Too Long'); - } - - if (!$errors) { - $template = id(new PonderQuestionTransaction()); - $xactions = array(); - - $xactions[] = id(clone $template) - ->setTransactionType(PonderQuestionTitleTransaction::TRANSACTIONTYPE) - ->setNewValue($v_title); - - $xactions[] = id(clone $template) - ->setTransactionType( - PonderQuestionContentTransaction::TRANSACTIONTYPE) - ->setNewValue($v_content); - - $xactions[] = id(clone $template) - ->setTransactionType( - PonderQuestionAnswerWikiTransaction::TRANSACTIONTYPE) - ->setNewValue($v_wiki); - - if (!$is_new) { - $xactions[] = id(clone $template) - ->setTransactionType( - PonderQuestionStatusTransaction::TRANSACTIONTYPE) - ->setNewValue($v_status); - } - - $xactions[] = id(clone $template) - ->setTransactionType(PhabricatorTransactions::TYPE_VIEW_POLICY) - ->setNewValue($v_view); - - $xactions[] = id(clone $template) - ->setTransactionType(PhabricatorTransactions::TYPE_SPACE) - ->setNewValue($v_space); - - $proj_edge_type = PhabricatorProjectObjectHasProjectEdgeType::EDGECONST; - $xactions[] = id(new PonderQuestionTransaction()) - ->setTransactionType(PhabricatorTransactions::TYPE_EDGE) - ->setMetadataValue('edge:type', $proj_edge_type) - ->setNewValue(array('=' => array_fuse($v_projects))); - - $editor = id(new PonderQuestionEditor()) - ->setActor($viewer) - ->setContentSourceFromRequest($request) - ->setContinueOnNoEffect(true); - - $editor->applyTransactions($question, $xactions); - - return id(new AphrontRedirectResponse()) - ->setURI('/Q'.$question->getID()); - } - } - - $policies = id(new PhabricatorPolicyQuery()) - ->setViewer($viewer) - ->setObject($question) - ->execute(); - - $form = id(new AphrontFormView()) - ->setUser($viewer) - ->appendChild( - id(new AphrontFormTextControl()) - ->setLabel(pht('Question')) - ->setName('title') - ->setValue($v_title) - ->setError($e_title)) - ->appendChild( - id(new PhabricatorRemarkupControl()) - ->setUser($viewer) - ->setName('content') - ->setID('content') - ->setValue($v_content) - ->setLabel(pht('Question Details')) - ->setUser($viewer)) - ->appendChild( - id(new PhabricatorRemarkupControl()) - ->setUser($viewer) - ->setName('answerWiki') - ->setID('answerWiki') - ->setValue($v_wiki) - ->setLabel(pht('Answer Summary')) - ->setUser($viewer)) - ->appendControl( - id(new AphrontFormPolicyControl()) - ->setName('viewPolicy') - ->setPolicyObject($question) - ->setSpacePHID($v_space) - ->setPolicies($policies) - ->setValue($v_view) - ->setCapability(PhabricatorPolicyCapability::CAN_VIEW)); - - - if (!$is_new) { - $form->appendChild( - id(new AphrontFormSelectControl()) - ->setLabel(pht('Status')) - ->setName('status') - ->setValue($v_status) - ->setOptions(PonderQuestionStatus::getQuestionStatusMap())); - } - - $form->appendControl( - id(new AphrontFormTokenizerControl()) - ->setLabel(pht('Tags')) - ->setName('projects') - ->setValue($v_projects) - ->setDatasource(new PhabricatorProjectDatasource())); - - $form->appendChild( - id(new AphrontFormSubmitControl()) - ->addCancelButton($this->getApplicationURI()) - ->setValue(pht('Submit'))); - - $preview = id(new PHUIRemarkupPreviewPanel()) - ->setHeader(pht('Question Preview')) - ->setControlID('content') - ->setPreviewURI($this->getApplicationURI('preview/')); - - $answer_preview = id(new PHUIRemarkupPreviewPanel()) - ->setHeader(pht('Answer Summary Preview')) - ->setControlID('answerWiki') - ->setPreviewURI($this->getApplicationURI('preview/')); - - $crumbs = $this->buildApplicationCrumbs(); - - $id = $question->getID(); - if ($id) { - $crumbs->addTextCrumb("Q{$id}", "/Q{$id}"); - $crumbs->addTextCrumb(pht('Edit')); - $title = pht('Edit Question'); - $header = id(new PHUIHeaderView()) - ->setHeader($title) - ->setHeaderIcon('fa-pencil'); - } else { - $crumbs->addTextCrumb(pht('Ask Question')); - $title = pht('Ask New Question'); - $header = id(new PHUIHeaderView()) - ->setHeader($title) - ->setHeaderIcon('fa-plus-square'); - } - $crumbs->setBorder(true); - - $box = id(new PHUIObjectBoxView()) - ->setHeaderText(pht('Question')) - ->setFormErrors($errors) - ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) - ->setForm($form); - - $view = id(new PHUITwoColumnView()) - ->setHeader($header) - ->setFooter(array( - $box, - $preview, - $answer_preview, - )); - - return $this->newPage() - ->setTitle($title) - ->setCrumbs($crumbs) - ->appendChild($view); - + return id(new PonderQuestionEditEngine()) + ->setController($this) + ->buildResponse(); } } diff --git a/src/applications/ponder/editor/PonderAnswerEditor.php b/src/applications/ponder/editor/PonderAnswerEditor.php index 5bde437e3e..8d66fffc17 100644 --- a/src/applications/ponder/editor/PonderAnswerEditor.php +++ b/src/applications/ponder/editor/PonderAnswerEditor.php @@ -6,6 +6,14 @@ final class PonderAnswerEditor extends PonderEditor { return pht('Ponder Answers'); } + public function getCreateObjectTitle($author, $object) { + return pht('%s added this answer.', $author); + } + + public function getCreateObjectTitleForFeed($author, $object) { + return pht('%s added %s.', $author, $object); + } + public function getTransactionTypes() { $types = parent::getTransactionTypes(); $types[] = PhabricatorTransactions::TYPE_COMMENT; diff --git a/src/applications/ponder/editor/PonderQuestionEditEngine.php b/src/applications/ponder/editor/PonderQuestionEditEngine.php new file mode 100644 index 0000000000..640f657ad1 --- /dev/null +++ b/src/applications/ponder/editor/PonderQuestionEditEngine.php @@ -0,0 +1,109 @@ +getViewer()); + } + + protected function newObjectQuery() { + return new PonderQuestionQuery(); + } + + protected function getObjectCreateTitleText($object) { + return pht('Create New Question'); + } + + protected function getObjectEditTitleText($object) { + return pht('Edit Question: %s', $object->getTitle()); + } + + protected function getObjectEditShortText($object) { + return $object->getTitle(); + } + + protected function getObjectCreateShortText() { + return pht('New Question'); + } + + protected function getObjectName() { + return pht('Question'); + } + + protected function getObjectCreateCancelURI($object) { + return $this->getApplication()->getApplicationURI('/'); + } + + protected function getEditorURI() { + return $this->getApplication()->getApplicationURI('question/edit/'); + } + + protected function getObjectViewURI($object) { + return $object->getViewURI(); + } + + protected function buildCustomEditFields($object) { + + return array( + id(new PhabricatorTextEditField()) + ->setKey('title') + ->setLabel(pht('Question')) + ->setDescription(pht('Question title.')) + ->setConduitTypeDescription(pht('New question title.')) + ->setTransactionType( + PonderQuestionTitleTransaction::TRANSACTIONTYPE) + ->setValue($object->getTitle()) + ->setIsRequired(true), + id(new PhabricatorRemarkupEditField()) + ->setKey('content') + ->setLabel(pht('Details')) + ->setDescription(pht('Long details of the question.')) + ->setConduitTypeDescription(pht('New question details.')) + ->setValue($object->getContent()) + ->setTransactionType( + PonderQuestionContentTransaction::TRANSACTIONTYPE), + id(new PhabricatorRemarkupEditField()) + ->setKey('answerWiki') + ->setLabel(pht('Answer Summary')) + ->setDescription(pht('Answer summary of the question.')) + ->setConduitTypeDescription(pht('New question answer summary.')) + ->setValue($object->getAnswerWiki()) + ->setTransactionType( + PonderQuestionAnswerWikiTransaction::TRANSACTIONTYPE), + id(new PhabricatorSelectEditField()) + ->setKey('status') + ->setLabel(pht('Status')) + ->setDescription(pht('Status of the question.')) + ->setConduitTypeDescription(pht('New question status.')) + ->setValue($object->getStatus()) + ->setTransactionType( + PonderQuestionStatusTransaction::TRANSACTIONTYPE) + ->setOptions(PonderQuestionStatus::getQuestionStatusMap()), + + ); + } + +} diff --git a/src/applications/ponder/editor/PonderQuestionEditor.php b/src/applications/ponder/editor/PonderQuestionEditor.php index 9b34031f13..a17aebecf8 100644 --- a/src/applications/ponder/editor/PonderQuestionEditor.php +++ b/src/applications/ponder/editor/PonderQuestionEditor.php @@ -9,6 +9,14 @@ final class PonderQuestionEditor return pht('Ponder Questions'); } + public function getCreateObjectTitle($author, $object) { + return pht('%s created this question.', $author); + } + + public function getCreateObjectTitleForFeed($author, $object) { + return pht('%s created %s.', $author, $object); + } + /** * This is used internally on @{method:applyInitialEffects} if a transaction * of type PonderQuestionTransaction::TYPE_ANSWERS is in the mix. The value @@ -64,11 +72,8 @@ final class PonderQuestionEditor public function getTransactionTypes() { $types = parent::getTransactionTypes(); - $types[] = PhabricatorTransactions::TYPE_COMMENT; $types[] = PhabricatorTransactions::TYPE_VIEW_POLICY; - $types[] = PhabricatorTransactions::TYPE_EDIT_POLICY; - $types[] = PhabricatorTransactions::TYPE_SPACE; return $types; } diff --git a/src/applications/ponder/storage/PonderQuestion.php b/src/applications/ponder/storage/PonderQuestion.php index 6594219f5a..c505deeed9 100644 --- a/src/applications/ponder/storage/PonderQuestion.php +++ b/src/applications/ponder/storage/PonderQuestion.php @@ -105,6 +105,14 @@ final class PonderQuestion extends PonderDAO return $this->comments; } + public function getMonogram() { + return 'Q'.$this->getID(); + } + + public function getViewURI() { + return '/'.$this->getMonogram(); + } + public function attachAnswers(array $answers) { assert_instances_of($answers, 'PonderAnswer'); $this->answers = $answers; diff --git a/src/applications/ponder/xaction/PonderQuestionAnswerTransaction.php b/src/applications/ponder/xaction/PonderQuestionAnswerTransaction.php index a51eada7b4..ca78b61d3f 100644 --- a/src/applications/ponder/xaction/PonderQuestionAnswerTransaction.php +++ b/src/applications/ponder/xaction/PonderQuestionAnswerTransaction.php @@ -21,6 +21,13 @@ final class PonderQuestionAnswerTransaction $this->renderAuthor()); } + public function getTitleForFeed() { + return pht( + '%s added an answer to %s.', + $this->renderAuthor(), + $this->renderObject()); + } + public function getIcon() { return 'fa-plus'; } From 60a19e36463b201b5c0e1b52e814b038bb4514c5 Mon Sep 17 00:00:00 2001 From: epriestley Date: Wed, 3 May 2017 10:39:37 -0700 Subject: [PATCH 15/25] Allow ApplicationTransactionEditor to figure out whether TYPE_COMMENT is supported or not Summary: See D17812, etc. We can figure this out by looking at the object carefully. We don't need to go delete all the old TYPE_COMMENT (it doesn't hurt anything) but can nuke it when we see it. Test Plan: - Made a comment in Slowvote (supports commenting). - Viewed an Almanac device (does not support commenting). Reviewers: chad Reviewed By: chad Differential Revision: https://secure.phabricator.com/D17822 --- .../slowvote/editor/PhabricatorSlowvoteEditor.php | 1 - .../PhabricatorApplicationTransactionEditor.php | 12 ++++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/applications/slowvote/editor/PhabricatorSlowvoteEditor.php b/src/applications/slowvote/editor/PhabricatorSlowvoteEditor.php index 94e31e8b92..fa320428e5 100644 --- a/src/applications/slowvote/editor/PhabricatorSlowvoteEditor.php +++ b/src/applications/slowvote/editor/PhabricatorSlowvoteEditor.php @@ -14,7 +14,6 @@ final class PhabricatorSlowvoteEditor public function getTransactionTypes() { $types = parent::getTransactionTypes(); - $types[] = PhabricatorTransactions::TYPE_COMMENT; $types[] = PhabricatorTransactions::TYPE_VIEW_POLICY; $types[] = PhabricatorSlowvoteTransaction::TYPE_QUESTION; diff --git a/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php b/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php index 8362d1328d..d58c8d5c76 100644 --- a/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php +++ b/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php @@ -298,6 +298,18 @@ abstract class PhabricatorApplicationTransactionEditor } } + if ($template) { + try { + $comment = $template->getApplicationTransactionCommentObject(); + } catch (PhutilMethodNotImplementedException $ex) { + $comment = null; + } + + if ($comment) { + $types[] = PhabricatorTransactions::TYPE_COMMENT; + } + } + return $types; } From 5307f511703c74ed81991c9f4e7383f8b25682a5 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Wed, 3 May 2017 11:26:14 -0700 Subject: [PATCH 16/25] Update Macro comment form Summary: Moves over to transaction commenting. Test Plan: Leave a comment (tested with TYPE_COMMENT still present). Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Differential Revision: https://secure.phabricator.com/D17823 --- src/__phutil_library_map__.php | 2 - .../PhabricatorMacroApplication.php | 1 - .../PhabricatorMacroCommentController.php | 63 ------------------- .../PhabricatorMacroViewController.php | 30 ++++----- 4 files changed, 13 insertions(+), 83 deletions(-) delete mode 100644 src/applications/macro/controller/PhabricatorMacroCommentController.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 9a3f4fb538..0198b253dc 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -2975,7 +2975,6 @@ phutil_register_library_map(array( 'PhabricatorMacroAudioBehaviorTransaction' => 'applications/macro/xaction/PhabricatorMacroAudioBehaviorTransaction.php', 'PhabricatorMacroAudioController' => 'applications/macro/controller/PhabricatorMacroAudioController.php', 'PhabricatorMacroAudioTransaction' => 'applications/macro/xaction/PhabricatorMacroAudioTransaction.php', - 'PhabricatorMacroCommentController' => 'applications/macro/controller/PhabricatorMacroCommentController.php', 'PhabricatorMacroConfigOptions' => 'applications/macro/config/PhabricatorMacroConfigOptions.php', 'PhabricatorMacroController' => 'applications/macro/controller/PhabricatorMacroController.php', 'PhabricatorMacroDatasource' => 'applications/macro/typeahead/PhabricatorMacroDatasource.php', @@ -8190,7 +8189,6 @@ phutil_register_library_map(array( 'PhabricatorMacroAudioBehaviorTransaction' => 'PhabricatorMacroTransactionType', 'PhabricatorMacroAudioController' => 'PhabricatorMacroController', 'PhabricatorMacroAudioTransaction' => 'PhabricatorMacroTransactionType', - 'PhabricatorMacroCommentController' => 'PhabricatorMacroController', 'PhabricatorMacroConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorMacroController' => 'PhabricatorController', 'PhabricatorMacroDatasource' => 'PhabricatorTypeaheadDatasource', diff --git a/src/applications/macro/application/PhabricatorMacroApplication.php b/src/applications/macro/application/PhabricatorMacroApplication.php index d0e6bbab04..3db2ad49c8 100644 --- a/src/applications/macro/application/PhabricatorMacroApplication.php +++ b/src/applications/macro/application/PhabricatorMacroApplication.php @@ -32,7 +32,6 @@ final class PhabricatorMacroApplication extends PhabricatorApplication { '(query/(?P[^/]+)/)?' => 'PhabricatorMacroListController', 'create/' => 'PhabricatorMacroEditController', 'view/(?P[1-9]\d*)/' => 'PhabricatorMacroViewController', - 'comment/(?P[1-9]\d*)/' => 'PhabricatorMacroCommentController', $this->getEditRoutePattern('edit/') => 'PhabricatorMacroEditController', 'audio/(?P[1-9]\d*)/' => 'PhabricatorMacroAudioController', diff --git a/src/applications/macro/controller/PhabricatorMacroCommentController.php b/src/applications/macro/controller/PhabricatorMacroCommentController.php deleted file mode 100644 index f038140be1..0000000000 --- a/src/applications/macro/controller/PhabricatorMacroCommentController.php +++ /dev/null @@ -1,63 +0,0 @@ -getViewer(); - $id = $request->getURIData('id'); - - if (!$request->isFormPost()) { - return new Aphront400Response(); - } - - $macro = id(new PhabricatorMacroQuery()) - ->setViewer($viewer) - ->withIDs(array($id)) - ->executeOne(); - if (!$macro) { - return new Aphront404Response(); - } - - $is_preview = $request->isPreviewRequest(); - $draft = PhabricatorDraft::buildFromRequest($request); - - $view_uri = $this->getApplicationURI('/view/'.$macro->getID().'/'); - - $xactions = array(); - $xactions[] = id(new PhabricatorMacroTransaction()) - ->setTransactionType(PhabricatorTransactions::TYPE_COMMENT) - ->attachComment( - id(new PhabricatorMacroTransactionComment()) - ->setContent($request->getStr('comment'))); - - $editor = id(new PhabricatorMacroEditor()) - ->setActor($viewer) - ->setContinueOnNoEffect($request->isContinueRequest()) - ->setContentSourceFromRequest($request) - ->setIsPreview($is_preview); - - try { - $xactions = $editor->applyTransactions($macro, $xactions); - } catch (PhabricatorApplicationTransactionNoEffectException $ex) { - return id(new PhabricatorApplicationTransactionNoEffectResponse()) - ->setCancelURI($view_uri) - ->setException($ex); - } - - if ($draft) { - $draft->replaceOrDelete(); - } - - if ($request->isAjax() && $is_preview) { - return id(new PhabricatorApplicationTransactionResponse()) - ->setViewer($viewer) - ->setTransactions($xactions) - ->setIsPreview($is_preview); - } else { - return id(new AphrontRedirectResponse()) - ->setURI($view_uri); - } - } - -} diff --git a/src/applications/macro/controller/PhabricatorMacroViewController.php b/src/applications/macro/controller/PhabricatorMacroViewController.php index 032d2228a9..1bcf34240a 100644 --- a/src/applications/macro/controller/PhabricatorMacroViewController.php +++ b/src/applications/macro/controller/PhabricatorMacroViewController.php @@ -36,6 +36,8 @@ final class PhabricatorMacroViewController $macro, new PhabricatorMacroTransactionQuery()); + $comment_form = $this->buildCommentForm($macro, $timeline); + $header = id(new PHUIHeaderView()) ->setUser($viewer) ->setPolicyObject($macro) @@ -48,29 +50,13 @@ final class PhabricatorMacroViewController $header->setStatus('fa-ban', 'indigo', pht('Archived')); } - $is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business'); - - $comment_header = $is_serious - ? pht('Add Comment') - : pht('Grovel in Awe'); - - $draft = PhabricatorDraft::newFromUserAndKey($viewer, $macro->getPHID()); - - $add_comment_form = id(new PhabricatorApplicationTransactionCommentView()) - ->setUser($viewer) - ->setObjectPHID($macro->getPHID()) - ->setDraft($draft) - ->setHeaderText($comment_header) - ->setAction($this->getApplicationURI('/comment/'.$macro->getID().'/')) - ->setSubmitButtonName(pht('Add Comment')); - $view = id(new PHUITwoColumnView()) ->setHeader($header) ->setSubheader($subheader) ->setCurtain($curtain) ->setMainColumn(array( $timeline, - $add_comment_form, + $comment_form, )) ->addPropertySection(pht('Macro'), $file) ->addPropertySection(pht('Details'), $details); @@ -82,6 +68,16 @@ final class PhabricatorMacroViewController ->appendChild($view); } + private function buildCommentForm( + PhabricatorFileImageMacro $macro, $timeline) { + $viewer = $this->getViewer(); + + return id(new PhabricatorMacroEditEngine()) + ->setViewer($viewer) + ->buildEditEngineCommentView($macro) + ->setTransactionTimeline($timeline); + } + private function buildCurtain( PhabricatorFileImageMacro $macro) { $can_manage = $this->hasApplicationCapability( From d34b338f3f85b08523a4ed663a090faa496030c8 Mon Sep 17 00:00:00 2001 From: Austin McKinley Date: Wed, 3 May 2017 17:45:14 -0700 Subject: [PATCH 17/25] Implement modular transactions for application policy changes Summary: Still needs some cleanup, but ready for review in broad outline form. Test Plan: Made lots of policy changes to the Badges application and confirmed expected rows in `application_xactions`, confirmed expected changes to `phabricator.application-settings`. See example output (not quite working for custom policy objects) here: {F4922240} Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin, chad, epriestley Maniphest Tasks: T11476 Differential Revision: https://secure.phabricator.com/D17757 --- src/__phutil_library_map__.php | 6 + .../base/PhabricatorApplication.php | 1 - ...ricatorApplicationDetailViewController.php | 6 + .../PhabricatorApplicationEditController.php | 82 +++----- .../PhabricatorApplicationEditEngine.php | 64 ++++++ .../editor/PhabricatorApplicationEditor.php | 46 ++++ ...catorApplicationApplicationTransaction.php | 4 - ...atorApplicationPolicyChangeTransaction.php | 197 ++++++++++++++++++ .../policy/storage/PhabricatorPolicy.php | 8 +- ...habricatorApplicationTransactionEditor.php | 14 +- .../PhabricatorModularTransactionType.php | 4 + 11 files changed, 371 insertions(+), 61 deletions(-) create mode 100644 src/applications/meta/editor/PhabricatorApplicationEditEngine.php create mode 100644 src/applications/meta/editor/PhabricatorApplicationEditor.php create mode 100644 src/applications/meta/xactions/PhabricatorApplicationPolicyChangeTransaction.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 0198b253dc..0e1294957d 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1849,9 +1849,12 @@ phutil_register_library_map(array( 'PhabricatorApplicationDatasource' => 'applications/meta/typeahead/PhabricatorApplicationDatasource.php', 'PhabricatorApplicationDetailViewController' => 'applications/meta/controller/PhabricatorApplicationDetailViewController.php', 'PhabricatorApplicationEditController' => 'applications/meta/controller/PhabricatorApplicationEditController.php', + 'PhabricatorApplicationEditEngine' => 'applications/meta/editor/PhabricatorApplicationEditEngine.php', 'PhabricatorApplicationEditHTTPParameterHelpView' => 'applications/transactions/view/PhabricatorApplicationEditHTTPParameterHelpView.php', + 'PhabricatorApplicationEditor' => 'applications/meta/editor/PhabricatorApplicationEditor.php', 'PhabricatorApplicationEmailCommandsController' => 'applications/meta/controller/PhabricatorApplicationEmailCommandsController.php', 'PhabricatorApplicationPanelController' => 'applications/meta/controller/PhabricatorApplicationPanelController.php', + 'PhabricatorApplicationPolicyChangeTransaction' => 'applications/meta/xactions/PhabricatorApplicationPolicyChangeTransaction.php', 'PhabricatorApplicationProfileMenuItem' => 'applications/search/menuitem/PhabricatorApplicationProfileMenuItem.php', 'PhabricatorApplicationQuery' => 'applications/meta/query/PhabricatorApplicationQuery.php', 'PhabricatorApplicationSchemaSpec' => 'applications/meta/storage/PhabricatorApplicationSchemaSpec.php', @@ -6889,9 +6892,12 @@ phutil_register_library_map(array( 'PhabricatorApplicationDatasource' => 'PhabricatorTypeaheadDatasource', 'PhabricatorApplicationDetailViewController' => 'PhabricatorApplicationsController', 'PhabricatorApplicationEditController' => 'PhabricatorApplicationsController', + 'PhabricatorApplicationEditEngine' => 'PhabricatorEditEngine', 'PhabricatorApplicationEditHTTPParameterHelpView' => 'AphrontView', + 'PhabricatorApplicationEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorApplicationEmailCommandsController' => 'PhabricatorApplicationsController', 'PhabricatorApplicationPanelController' => 'PhabricatorApplicationsController', + 'PhabricatorApplicationPolicyChangeTransaction' => 'PhabricatorApplicationTransactionType', 'PhabricatorApplicationProfileMenuItem' => 'PhabricatorProfileMenuItem', 'PhabricatorApplicationQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorApplicationSchemaSpec' => 'PhabricatorConfigSchemaSpec', diff --git a/src/applications/base/PhabricatorApplication.php b/src/applications/base/PhabricatorApplication.php index 29f5ed35be..af683e0592 100644 --- a/src/applications/base/PhabricatorApplication.php +++ b/src/applications/base/PhabricatorApplication.php @@ -284,7 +284,6 @@ abstract class PhabricatorApplication throw new PhutilMethodNotImplementedException(); } - /* -( Fact Integration )--------------------------------------------------- */ diff --git a/src/applications/meta/controller/PhabricatorApplicationDetailViewController.php b/src/applications/meta/controller/PhabricatorApplicationDetailViewController.php index 709558eaa2..8be6d73a1d 100644 --- a/src/applications/meta/controller/PhabricatorApplicationDetailViewController.php +++ b/src/applications/meta/controller/PhabricatorApplicationDetailViewController.php @@ -38,6 +38,11 @@ final class PhabricatorApplicationDetailViewController $header->setStatus('fa-ban', 'dark', pht('Uninstalled')); } + $timeline = $this->buildTransactionTimeline( + $selected, + new PhabricatorApplicationApplicationTransactionQuery()); + $timeline->setShouldTerminate(true); + $curtain = $this->buildCurtain($selected); $details = $this->buildPropertySectionView($selected); $policies = $this->buildPolicyView($selected); @@ -61,6 +66,7 @@ final class PhabricatorApplicationDetailViewController ->setMainColumn(array( $policies, $panels, + $timeline, )) ->addPropertySection(pht('Details'), $details); diff --git a/src/applications/meta/controller/PhabricatorApplicationEditController.php b/src/applications/meta/controller/PhabricatorApplicationEditController.php index ed51405db9..c9f6a2cafb 100644 --- a/src/applications/meta/controller/PhabricatorApplicationEditController.php +++ b/src/applications/meta/controller/PhabricatorApplicationEditController.php @@ -30,8 +30,15 @@ final class PhabricatorApplicationEditController ->execute(); if ($request->isFormPost()) { + $xactions = array(); + $result = array(); + $template = $application->getApplicationTransactionTemplate(); foreach ($application->getCapabilities() as $capability) { + if (!$application->isCapabilityEditable($capability)) { + continue; + } + $old = $application->getPolicy($capability); $new = $request->getStr('policy:'.$capability); @@ -40,67 +47,36 @@ final class PhabricatorApplicationEditController continue; } - if (empty($policies[$new])) { - // Not a standard policy, check for a custom policy. - $policy = id(new PhabricatorPolicyQuery()) - ->setViewer($user) - ->withPHIDs(array($new)) - ->executeOne(); - if (!$policy) { - // Not a custom policy either. Can't set the policy to something - // invalid, so skip this. - continue; - } - } - - if ($new == PhabricatorPolicies::POLICY_PUBLIC) { - $capobj = PhabricatorPolicyCapability::getCapabilityByKey( - $capability); - if (!$capobj || !$capobj->shouldAllowPublicPolicySetting()) { - // Can't set non-public policies to public. - continue; - } - } - $result[$capability] = $new; + + $xactions[] = id(clone $template) + ->setTransactionType( + PhabricatorApplicationPolicyChangeTransaction::TRANSACTIONTYPE) + ->setMetadataValue( + PhabricatorApplicationPolicyChangeTransaction::METADATA_ATTRIBUTE, + $capability) + ->setNewValue($new); } if ($result) { - $key = 'phabricator.application-settings'; - $config_entry = PhabricatorConfigEntry::loadConfigEntry($key); - $value = $config_entry->getValue(); + $editor = id(new PhabricatorApplicationEditor()) + ->setActor($user) + ->setContentSourceFromRequest($request) + ->setContinueOnNoEffect(true) + ->setContinueOnMissingFields(true); - $phid = $application->getPHID(); - if (empty($value[$phid])) { - $value[$application->getPHID()] = array(); - } - if (empty($value[$phid]['policy'])) { - $value[$phid]['policy'] = array(); + try { + $editor->applyTransactions($application, $xactions); + return id(new AphrontRedirectResponse())->setURI($view_uri); + } catch (PhabricatorApplicationTransactionValidationException $ex) { + $validation_exception = $ex; } - $value[$phid]['policy'] = $result + $value[$phid]['policy']; - - // Don't allow users to make policy edits which would lock them out of - // applications, since they would be unable to undo those actions. - PhabricatorEnv::overrideConfig($key, $value); - PhabricatorPolicyFilter::mustRetainCapability( - $user, - $application, - PhabricatorPolicyCapability::CAN_VIEW); - - PhabricatorPolicyFilter::mustRetainCapability( - $user, - $application, - PhabricatorPolicyCapability::CAN_EDIT); - - PhabricatorConfigEditor::storeNewValue( - $user, - $config_entry, - $value, - PhabricatorContentSource::newFromRequest($request)); + return $this->newDialog() + ->setTitle('Validation Failed') + ->setValidationException($validation_exception) + ->addCancelButton($view_uri); } - - return id(new AphrontRedirectResponse())->setURI($view_uri); } $descriptions = PhabricatorPolicyQuery::renderPolicyDescriptions( diff --git a/src/applications/meta/editor/PhabricatorApplicationEditEngine.php b/src/applications/meta/editor/PhabricatorApplicationEditEngine.php new file mode 100644 index 0000000000..7cad5d9242 --- /dev/null +++ b/src/applications/meta/editor/PhabricatorApplicationEditEngine.php @@ -0,0 +1,64 @@ +getName()); + } + + protected function getObjectEditShortText($object) { + return $object->getName(); + } + + protected function getObjectCreateShortText() { + return pht('Create Application'); + } + + protected function getObjectName() { + return pht('Application'); + } + + protected function getObjectViewURI($object) { + return $object->getViewURI(); + } + + protected function buildCustomEditFields($object) { + return array(); + } + +} diff --git a/src/applications/meta/editor/PhabricatorApplicationEditor.php b/src/applications/meta/editor/PhabricatorApplicationEditor.php new file mode 100644 index 0000000000..83003b4c27 --- /dev/null +++ b/src/applications/meta/editor/PhabricatorApplicationEditor.php @@ -0,0 +1,46 @@ +getCapabilityName(); + return $application->getPolicy($capability); + } + + public function applyInternalEffects($object, $value) { + $application = $object; + $user = $this->getActor(); + + $key = 'phabricator.application-settings'; + $config_entry = PhabricatorConfigEntry::loadConfigEntry($key); + $current_value = $config_entry->getValue(); + + $phid = $application->getPHID(); + if (empty($current_value[$phid])) { + $current_value[$application->getPHID()] = array(); + } + if (empty($current_value[$phid]['policy'])) { + $current_value[$phid]['policy'] = array(); + } + + $new = array($this->getCapabilityName() => $value); + $current_value[$phid]['policy'] = $new + $current_value[$phid]['policy']; + + $editor = $this->getEditor(); + $content_source = $editor->getContentSource(); + PhabricatorConfigEditor::storeNewValue( + $user, + $config_entry, + $current_value, + $content_source); + } + + public function getTitle() { + $old = $this->renderPolicy($this->getOldValue()); + $new = $this->renderPolicy($this->getNewValue()); + + return pht( + '%s changed the "%s" policy from "%s" to "%s".', + $this->renderAuthor(), + $this->renderCapability(), + $old, + $new); + } + + public function getTitleForFeed() { + $old = $this->renderPolicy($this->getOldValue()); + $new = $this->renderPolicy($this->getNewValue()); + + return pht( + '%s changed the "%s" policy for application %s from "%s" to "%s".', + $this->renderAuthor(), + $this->renderCapability(), + $this->renderObject(), + $old, + $new); + } + + public function validateTransactions($object, array $xactions) { + $user = $this->getActor(); + $application = $object; + $policies = id(new PhabricatorPolicyQuery()) + ->setViewer($user) + ->setObject($application) + ->execute(); + + $errors = array(); + foreach ($xactions as $xaction) { + $new = $xaction->getNewValue(); + $capability = $xaction->getMetadataValue(self::METADATA_ATTRIBUTE); + + if (empty($policies[$new])) { + // Not a standard policy, check for a custom policy. + $policy = id(new PhabricatorPolicyQuery()) + ->setViewer($user) + ->withPHIDs(array($new)) + ->executeOne(); + if (!$policy) { + $errors[] = $this->newInvalidError( + pht('Policy does not exist.')); + continue; + } + } else { + $policy = idx($policies, $new); + } + + if (!$policy->isValidPolicyForEdit()) { + $errors[] = $this->newInvalidError( + pht('Can\'t set the policy to a policy you can\'t view!')); + continue; + } + + if ($new == PhabricatorPolicies::POLICY_PUBLIC) { + $capobj = PhabricatorPolicyCapability::getCapabilityByKey( + $capability); + if (!$capobj || !$capobj->shouldAllowPublicPolicySetting()) { + $errors[] = $this->newInvalidError( + pht('Can\'t set non-public policies to public.')); + continue; + } + } + + if (!$application->isCapabilityEditable($capability)) { + $errors[] = $this->newInvalidError( + pht('Capability "%s" is not editable for this application.', + $capability)); + continue; + } + } + + // If we're changing these policies, the viewer needs to still be able to + // view or edit the application under the new policy. + $validate_map = array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + ); + $validate_map = array_fill_keys($validate_map, array()); + + foreach ($xactions as $xaction) { + $capability = $xaction->getMetadataValue(self::METADATA_ATTRIBUTE); + if (!isset($validate_map[$capability])) { + continue; + } + + $validate_map[$capability][] = $xaction; + } + + foreach ($validate_map as $capability => $cap_xactions) { + if (!$cap_xactions) { + continue; + } + + $editor = $this->getEditor(); + $policy_errors = $editor->validatePolicyTransaction( + $object, + $cap_xactions, + self::TRANSACTIONTYPE, + $capability); + + foreach ($policy_errors as $error) { + $errors[] = $error; + } + } + + return $errors; + } + + private function renderPolicy($name) { + $policies = $this->getAllPolicies(); + if (empty($policies[$name])) { + // Not a standard policy, check for a custom policy. + $policy = id(new PhabricatorPolicyQuery()) + ->setViewer($this->getViewer()) + ->withPHIDs(array($name)) + ->executeOne(); + $policies[$name] = $policy; + } + + $policy = idx($policies, $name); + return $this->renderValue($policy->getFullName()); + } + + private function getAllPolicies() { + if (!$this->policies) { + $viewer = $this->getViewer(); + $application = $this->getObject(); + $this->policies = id(new PhabricatorPolicyQuery()) + ->setViewer($viewer) + ->setObject($application) + ->execute(); + } + + return $this->policies; + } + + private function renderCapability() { + $application = $this->getObject(); + $capability = $this->getCapabilityName(); + return $application->getCapabilityLabel($capability); + } + + private function getCapabilityName() { + return $this->getMetadataValue(self::METADATA_ATTRIBUTE); + } + +} diff --git a/src/applications/policy/storage/PhabricatorPolicy.php b/src/applications/policy/storage/PhabricatorPolicy.php index 68462cbc19..4141ef9c36 100644 --- a/src/applications/policy/storage/PhabricatorPolicy.php +++ b/src/applications/policy/storage/PhabricatorPolicy.php @@ -264,9 +264,11 @@ final class PhabricatorPolicy public function getFullName() { switch ($this->getType()) { case PhabricatorPolicyType::TYPE_PROJECT: - return pht('Project: %s', $this->getName()); + return pht('Members of Project: %s', $this->getName()); case PhabricatorPolicyType::TYPE_MASKED: return pht('Other: %s', $this->getName()); + case PhabricatorPolicyType::TYPE_USER: + return pht('Only User: %s', $this->getName()); default: return $this->getName(); } @@ -422,6 +424,10 @@ final class PhabricatorPolicy return ($this_strength > $other_strength); } + public function isValidPolicyForEdit() { + return $this->getType() !== PhabricatorPolicyType::TYPE_MASKED; + } + public static function getSpecialRules( PhabricatorPolicyInterface $object, PhabricatorUser $viewer, diff --git a/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php b/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php index d58c8d5c76..b5aa399521 100644 --- a/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php +++ b/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php @@ -334,6 +334,8 @@ abstract class PhabricatorApplicationTransactionEditor $xtype = $this->getModularTransactionType($type); if ($xtype) { + $xtype = clone $xtype; + $xtype->setStorage($xaction); return $xtype->generateOldValue($object); } @@ -414,6 +416,8 @@ abstract class PhabricatorApplicationTransactionEditor $xtype = $this->getModularTransactionType($type); if ($xtype) { + $xtype = clone $xtype; + $xtype->setStorage($xaction); return $xtype->generateNewValue($object, $xaction->getNewValue()); } @@ -553,6 +557,8 @@ abstract class PhabricatorApplicationTransactionEditor $xtype = $this->getModularTransactionType($type); if ($xtype) { + $xtype = clone $xtype; + $xtype->setStorage($xaction); return $xtype->applyInternalEffects($object, $xaction->getNewValue()); } @@ -2163,7 +2169,7 @@ abstract class PhabricatorApplicationTransactionEditor return array_mergev($errors); } - private function validatePolicyTransaction( + public function validatePolicyTransaction( PhabricatorLiskDAO $object, array $xactions, $transaction_type, @@ -2772,7 +2778,11 @@ abstract class PhabricatorApplicationTransactionEditor } if (!$has_support) { - throw new Exception(pht('Capability not supported.')); + throw new Exception( + pht('The object being edited does not implement any standard '. + 'interfaces (like PhabricatorSubscribableInterface) which allow '. + 'CCs to be generated automatically. Override the "getMailCC()" '. + 'method and generate CCs explicitly.')); } return array_mergev($phids); diff --git a/src/applications/transactions/storage/PhabricatorModularTransactionType.php b/src/applications/transactions/storage/PhabricatorModularTransactionType.php index 9d8510cdc9..8a56e8e8ce 100644 --- a/src/applications/transactions/storage/PhabricatorModularTransactionType.php +++ b/src/applications/transactions/storage/PhabricatorModularTransactionType.php @@ -315,4 +315,8 @@ abstract class PhabricatorModularTransactionType return $editor->getPHIDList($old, $new); } + public function getMetadataValue($key, $default = null) { + return $this->getStorage()->getMetadataValue($key, $default); + } + } From 06eae5578bff389c8a1f941a230c0616584579d5 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Thu, 4 May 2017 11:17:47 -0700 Subject: [PATCH 18/25] Update Passphrase for modular transactions Summary: Updates Passphrase for modular transactions. Test Plan: Create, edit, lock, view, lots of different types of Passphrases. Enable Conduit, Lock Passphrases, Destroy Secrets from the interface and verify from the DB it was eradicated. Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Differential Revision: https://secure.phabricator.com/D17824 --- src/__phutil_library_map__.php | 20 +- .../PassphraseCredentialConduitController.php | 3 +- .../PassphraseCredentialDestroyController.php | 3 +- .../PassphraseCredentialEditController.php | 19 +- .../PassphraseCredentialLockController.php | 6 +- .../PassphraseCredentialRevealController.php | 2 +- .../PassphraseCredentialTransactionEditor.php | 178 +----------------- .../PassphraseCredentialTransaction.php | 123 +----------- ...PassphraseCredentialConduitTransaction.php | 53 ++++++ ...phraseCredentialDescriptionTransaction.php | 64 +++++++ ...PassphraseCredentialDestroyTransaction.php | 52 +++++ .../PassphraseCredentialLockTransaction.php | 41 ++++ ...assphraseCredentialLookedAtTransaction.php | 33 ++++ .../PassphraseCredentialNameTransaction.php | 71 +++++++ ...assphraseCredentialSecretIDTransaction.php | 56 ++++++ .../PassphraseCredentialTransactionType.php | 15 ++ ...assphraseCredentialUsernameTransaction.php | 56 ++++++ 17 files changed, 489 insertions(+), 306 deletions(-) create mode 100644 src/applications/passphrase/xaction/PassphraseCredentialConduitTransaction.php create mode 100644 src/applications/passphrase/xaction/PassphraseCredentialDescriptionTransaction.php create mode 100644 src/applications/passphrase/xaction/PassphraseCredentialDestroyTransaction.php create mode 100644 src/applications/passphrase/xaction/PassphraseCredentialLockTransaction.php create mode 100644 src/applications/passphrase/xaction/PassphraseCredentialLookedAtTransaction.php create mode 100644 src/applications/passphrase/xaction/PassphraseCredentialNameTransaction.php create mode 100644 src/applications/passphrase/xaction/PassphraseCredentialSecretIDTransaction.php create mode 100644 src/applications/passphrase/xaction/PassphraseCredentialTransactionType.php create mode 100644 src/applications/passphrase/xaction/PassphraseCredentialUsernameTransaction.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 0e1294957d..35ea8488d0 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1762,23 +1762,32 @@ phutil_register_library_map(array( 'PassphraseCredential' => 'applications/passphrase/storage/PassphraseCredential.php', 'PassphraseCredentialAuthorPolicyRule' => 'applications/passphrase/policyrule/PassphraseCredentialAuthorPolicyRule.php', 'PassphraseCredentialConduitController' => 'applications/passphrase/controller/PassphraseCredentialConduitController.php', + 'PassphraseCredentialConduitTransaction' => 'applications/passphrase/xaction/PassphraseCredentialConduitTransaction.php', 'PassphraseCredentialControl' => 'applications/passphrase/view/PassphraseCredentialControl.php', 'PassphraseCredentialCreateController' => 'applications/passphrase/controller/PassphraseCredentialCreateController.php', + 'PassphraseCredentialDescriptionTransaction' => 'applications/passphrase/xaction/PassphraseCredentialDescriptionTransaction.php', 'PassphraseCredentialDestroyController' => 'applications/passphrase/controller/PassphraseCredentialDestroyController.php', + 'PassphraseCredentialDestroyTransaction' => 'applications/passphrase/xaction/PassphraseCredentialDestroyTransaction.php', 'PassphraseCredentialEditController' => 'applications/passphrase/controller/PassphraseCredentialEditController.php', 'PassphraseCredentialFulltextEngine' => 'applications/passphrase/search/PassphraseCredentialFulltextEngine.php', 'PassphraseCredentialListController' => 'applications/passphrase/controller/PassphraseCredentialListController.php', 'PassphraseCredentialLockController' => 'applications/passphrase/controller/PassphraseCredentialLockController.php', + 'PassphraseCredentialLockTransaction' => 'applications/passphrase/xaction/PassphraseCredentialLockTransaction.php', + 'PassphraseCredentialLookedAtTransaction' => 'applications/passphrase/xaction/PassphraseCredentialLookedAtTransaction.php', + 'PassphraseCredentialNameTransaction' => 'applications/passphrase/xaction/PassphraseCredentialNameTransaction.php', 'PassphraseCredentialPHIDType' => 'applications/passphrase/phid/PassphraseCredentialPHIDType.php', 'PassphraseCredentialPublicController' => 'applications/passphrase/controller/PassphraseCredentialPublicController.php', 'PassphraseCredentialQuery' => 'applications/passphrase/query/PassphraseCredentialQuery.php', 'PassphraseCredentialRevealController' => 'applications/passphrase/controller/PassphraseCredentialRevealController.php', 'PassphraseCredentialSearchEngine' => 'applications/passphrase/query/PassphraseCredentialSearchEngine.php', + 'PassphraseCredentialSecretIDTransaction' => 'applications/passphrase/xaction/PassphraseCredentialSecretIDTransaction.php', 'PassphraseCredentialTransaction' => 'applications/passphrase/storage/PassphraseCredentialTransaction.php', 'PassphraseCredentialTransactionEditor' => 'applications/passphrase/editor/PassphraseCredentialTransactionEditor.php', 'PassphraseCredentialTransactionQuery' => 'applications/passphrase/query/PassphraseCredentialTransactionQuery.php', + 'PassphraseCredentialTransactionType' => 'applications/passphrase/xaction/PassphraseCredentialTransactionType.php', 'PassphraseCredentialType' => 'applications/passphrase/credentialtype/PassphraseCredentialType.php', 'PassphraseCredentialTypeTestCase' => 'applications/passphrase/credentialtype/__tests__/PassphraseCredentialTypeTestCase.php', + 'PassphraseCredentialUsernameTransaction' => 'applications/passphrase/xaction/PassphraseCredentialUsernameTransaction.php', 'PassphraseCredentialViewController' => 'applications/passphrase/controller/PassphraseCredentialViewController.php', 'PassphraseDAO' => 'applications/passphrase/storage/PassphraseDAO.php', 'PassphraseDefaultEditCapability' => 'applications/passphrase/capability/PassphraseDefaultEditCapability.php', @@ -6801,23 +6810,32 @@ phutil_register_library_map(array( ), 'PassphraseCredentialAuthorPolicyRule' => 'PhabricatorPolicyRule', 'PassphraseCredentialConduitController' => 'PassphraseController', + 'PassphraseCredentialConduitTransaction' => 'PassphraseCredentialTransactionType', 'PassphraseCredentialControl' => 'AphrontFormControl', 'PassphraseCredentialCreateController' => 'PassphraseController', + 'PassphraseCredentialDescriptionTransaction' => 'PassphraseCredentialTransactionType', 'PassphraseCredentialDestroyController' => 'PassphraseController', + 'PassphraseCredentialDestroyTransaction' => 'PassphraseCredentialTransactionType', 'PassphraseCredentialEditController' => 'PassphraseController', 'PassphraseCredentialFulltextEngine' => 'PhabricatorFulltextEngine', 'PassphraseCredentialListController' => 'PassphraseController', 'PassphraseCredentialLockController' => 'PassphraseController', + 'PassphraseCredentialLockTransaction' => 'PassphraseCredentialTransactionType', + 'PassphraseCredentialLookedAtTransaction' => 'PassphraseCredentialTransactionType', + 'PassphraseCredentialNameTransaction' => 'PassphraseCredentialTransactionType', 'PassphraseCredentialPHIDType' => 'PhabricatorPHIDType', 'PassphraseCredentialPublicController' => 'PassphraseController', 'PassphraseCredentialQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PassphraseCredentialRevealController' => 'PassphraseController', 'PassphraseCredentialSearchEngine' => 'PhabricatorApplicationSearchEngine', - 'PassphraseCredentialTransaction' => 'PhabricatorApplicationTransaction', + 'PassphraseCredentialSecretIDTransaction' => 'PassphraseCredentialTransactionType', + 'PassphraseCredentialTransaction' => 'PhabricatorModularTransaction', 'PassphraseCredentialTransactionEditor' => 'PhabricatorApplicationTransactionEditor', 'PassphraseCredentialTransactionQuery' => 'PhabricatorApplicationTransactionQuery', + 'PassphraseCredentialTransactionType' => 'PhabricatorModularTransactionType', 'PassphraseCredentialType' => 'Phobject', 'PassphraseCredentialTypeTestCase' => 'PhabricatorTestCase', + 'PassphraseCredentialUsernameTransaction' => 'PassphraseCredentialTransactionType', 'PassphraseCredentialViewController' => 'PassphraseController', 'PassphraseDAO' => 'PhabricatorLiskDAO', 'PassphraseDefaultEditCapability' => 'PhabricatorPolicyCapability', diff --git a/src/applications/passphrase/controller/PassphraseCredentialConduitController.php b/src/applications/passphrase/controller/PassphraseCredentialConduitController.php index ce8f21f62d..3c95fd8459 100644 --- a/src/applications/passphrase/controller/PassphraseCredentialConduitController.php +++ b/src/applications/passphrase/controller/PassphraseCredentialConduitController.php @@ -50,7 +50,8 @@ final class PassphraseCredentialConduitController $xactions = array(); $xactions[] = id(new PassphraseCredentialTransaction()) - ->setTransactionType(PassphraseCredentialTransaction::TYPE_CONDUIT) + ->setTransactionType( + PassphraseCredentialConduitTransaction::TRANSACTIONTYPE) ->setNewValue(!$credential->getAllowConduit()); $editor = id(new PassphraseCredentialTransactionEditor()) diff --git a/src/applications/passphrase/controller/PassphraseCredentialDestroyController.php b/src/applications/passphrase/controller/PassphraseCredentialDestroyController.php index 8858d0ef6b..e1f0532f8a 100644 --- a/src/applications/passphrase/controller/PassphraseCredentialDestroyController.php +++ b/src/applications/passphrase/controller/PassphraseCredentialDestroyController.php @@ -32,7 +32,8 @@ final class PassphraseCredentialDestroyController $xactions = array(); $xactions[] = id(new PassphraseCredentialTransaction()) - ->setTransactionType(PassphraseCredentialTransaction::TYPE_DESTROY) + ->setTransactionType( + PassphraseCredentialDestroyTransaction::TRANSACTIONTYPE) ->setNewValue(1); $editor = id(new PassphraseCredentialTransactionEditor()) diff --git a/src/applications/passphrase/controller/PassphraseCredentialEditController.php b/src/applications/passphrase/controller/PassphraseCredentialEditController.php index bdb1802880..9c86a7f5c9 100644 --- a/src/applications/passphrase/controller/PassphraseCredentialEditController.php +++ b/src/applications/passphrase/controller/PassphraseCredentialEditController.php @@ -117,12 +117,19 @@ final class PassphraseCredentialEditController extends PassphraseController { } if (!$errors) { - $type_name = PassphraseCredentialTransaction::TYPE_NAME; - $type_desc = PassphraseCredentialTransaction::TYPE_DESCRIPTION; - $type_username = PassphraseCredentialTransaction::TYPE_USERNAME; - $type_destroy = PassphraseCredentialTransaction::TYPE_DESTROY; - $type_secret_id = PassphraseCredentialTransaction::TYPE_SECRET_ID; - $type_is_locked = PassphraseCredentialTransaction::TYPE_LOCK; + $type_name = + PassphraseCredentialNameTransaction::TRANSACTIONTYPE; + $type_desc = + PassphraseCredentialDescriptionTransaction::TRANSACTIONTYPE; + $type_username = + PassphraseCredentialUsernameTransaction::TRANSACTIONTYPE; + $type_destroy = + PassphraseCredentialDestroyTransaction::TRANSACTIONTYPE; + $type_secret_id = + PassphraseCredentialSecretIDTransaction::TRANSACTIONTYPE; + $type_is_locked = + PassphraseCredentialLockTransaction::TRANSACTIONTYPE; + $type_view_policy = PhabricatorTransactions::TYPE_VIEW_POLICY; $type_edit_policy = PhabricatorTransactions::TYPE_EDIT_POLICY; $type_space = PhabricatorTransactions::TYPE_SPACE; diff --git a/src/applications/passphrase/controller/PassphraseCredentialLockController.php b/src/applications/passphrase/controller/PassphraseCredentialLockController.php index 9832705427..b489851baa 100644 --- a/src/applications/passphrase/controller/PassphraseCredentialLockController.php +++ b/src/applications/passphrase/controller/PassphraseCredentialLockController.php @@ -40,11 +40,13 @@ final class PassphraseCredentialLockController $xactions = array(); $xactions[] = id(new PassphraseCredentialTransaction()) - ->setTransactionType(PassphraseCredentialTransaction::TYPE_CONDUIT) + ->setTransactionType( + PassphraseCredentialConduitTransaction::TRANSACTIONTYPE) ->setNewValue(0); $xactions[] = id(new PassphraseCredentialTransaction()) - ->setTransactionType(PassphraseCredentialTransaction::TYPE_LOCK) + ->setTransactionType( + PassphraseCredentialLockTransaction::TRANSACTIONTYPE) ->setNewValue(1); $editor = id(new PassphraseCredentialTransactionEditor()) diff --git a/src/applications/passphrase/controller/PassphraseCredentialRevealController.php b/src/applications/passphrase/controller/PassphraseCredentialRevealController.php index 4fb299b85e..3a40d253c9 100644 --- a/src/applications/passphrase/controller/PassphraseCredentialRevealController.php +++ b/src/applications/passphrase/controller/PassphraseCredentialRevealController.php @@ -67,7 +67,7 @@ final class PassphraseCredentialRevealController ->setDisableWorkflowOnCancel(true) ->addCancelButton($view_uri, pht('Done')); - $type_secret = PassphraseCredentialTransaction::TYPE_LOOKEDATSECRET; + $type_secret = PassphraseCredentialLookedAtTransaction::TRANSACTIONTYPE; $xactions = array( id(new PassphraseCredentialTransaction()) ->setTransactionType($type_secret) diff --git a/src/applications/passphrase/editor/PassphraseCredentialTransactionEditor.php b/src/applications/passphrase/editor/PassphraseCredentialTransactionEditor.php index fd743f4aac..1e23c874cf 100644 --- a/src/applications/passphrase/editor/PassphraseCredentialTransactionEditor.php +++ b/src/applications/passphrase/editor/PassphraseCredentialTransactionEditor.php @@ -17,185 +17,15 @@ final class PassphraseCredentialTransactionEditor $types[] = PhabricatorTransactions::TYPE_VIEW_POLICY; $types[] = PhabricatorTransactions::TYPE_EDIT_POLICY; - $types[] = PassphraseCredentialTransaction::TYPE_NAME; - $types[] = PassphraseCredentialTransaction::TYPE_DESCRIPTION; - $types[] = PassphraseCredentialTransaction::TYPE_USERNAME; - $types[] = PassphraseCredentialTransaction::TYPE_SECRET_ID; - $types[] = PassphraseCredentialTransaction::TYPE_DESTROY; - $types[] = PassphraseCredentialTransaction::TYPE_LOOKEDATSECRET; - $types[] = PassphraseCredentialTransaction::TYPE_LOCK; - $types[] = PassphraseCredentialTransaction::TYPE_CONDUIT; - return $types; } - protected function getCustomTransactionOldValue( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - switch ($xaction->getTransactionType()) { - case PassphraseCredentialTransaction::TYPE_NAME: - if ($this->getIsNewObject()) { - return null; - } - return $object->getName(); - case PassphraseCredentialTransaction::TYPE_DESCRIPTION: - return $object->getDescription(); - case PassphraseCredentialTransaction::TYPE_USERNAME: - return $object->getUsername(); - case PassphraseCredentialTransaction::TYPE_SECRET_ID: - return $object->getSecretID(); - case PassphraseCredentialTransaction::TYPE_DESTROY: - return (int)$object->getIsDestroyed(); - case PassphraseCredentialTransaction::TYPE_LOCK: - return (int)$object->getIsLocked(); - case PassphraseCredentialTransaction::TYPE_CONDUIT: - return (int)$object->getAllowConduit(); - case PassphraseCredentialTransaction::TYPE_LOOKEDATSECRET: - return null; - } - - return parent::getCustomTransactionOldValue($object, $xaction); + public function getCreateObjectTitle($author, $object) { + return pht('%s created this credential.', $author); } - protected function getCustomTransactionNewValue( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - switch ($xaction->getTransactionType()) { - case PassphraseCredentialTransaction::TYPE_NAME: - case PassphraseCredentialTransaction::TYPE_DESCRIPTION: - case PassphraseCredentialTransaction::TYPE_USERNAME: - case PassphraseCredentialTransaction::TYPE_SECRET_ID: - case PassphraseCredentialTransaction::TYPE_LOOKEDATSECRET: - return $xaction->getNewValue(); - case PassphraseCredentialTransaction::TYPE_DESTROY: - case PassphraseCredentialTransaction::TYPE_LOCK: - return (int)$xaction->getNewValue(); - case PassphraseCredentialTransaction::TYPE_CONDUIT: - return (int)$xaction->getNewValue(); - } - return parent::getCustomTransactionNewValue($object, $xaction); - } - - protected function applyCustomInternalTransaction( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - switch ($xaction->getTransactionType()) { - case PassphraseCredentialTransaction::TYPE_NAME: - $object->setName($xaction->getNewValue()); - return; - case PassphraseCredentialTransaction::TYPE_DESCRIPTION: - $object->setDescription($xaction->getNewValue()); - return; - case PassphraseCredentialTransaction::TYPE_USERNAME: - $object->setUsername($xaction->getNewValue()); - return; - case PassphraseCredentialTransaction::TYPE_SECRET_ID: - $old_id = $object->getSecretID(); - if ($old_id) { - $this->destroySecret($old_id); - } - $object->setSecretID($xaction->getNewValue()); - return; - case PassphraseCredentialTransaction::TYPE_DESTROY: - // When destroying a credential, wipe out its secret. - $is_destroyed = $xaction->getNewValue(); - $object->setIsDestroyed($is_destroyed); - if ($is_destroyed) { - $secret_id = $object->getSecretID(); - if ($secret_id) { - $this->destroySecret($secret_id); - $object->setSecretID(null); - } - } - return; - case PassphraseCredentialTransaction::TYPE_LOOKEDATSECRET: - return; - case PassphraseCredentialTransaction::TYPE_LOCK: - $object->setIsLocked((int)$xaction->getNewValue()); - return; - case PassphraseCredentialTransaction::TYPE_CONDUIT: - $object->setAllowConduit((int)$xaction->getNewValue()); - return; - } - - return parent::applyCustomInternalTransaction($object, $xaction); - } - - protected function applyCustomExternalTransaction( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case PassphraseCredentialTransaction::TYPE_NAME: - case PassphraseCredentialTransaction::TYPE_DESCRIPTION: - case PassphraseCredentialTransaction::TYPE_USERNAME: - case PassphraseCredentialTransaction::TYPE_SECRET_ID: - case PassphraseCredentialTransaction::TYPE_DESTROY: - case PassphraseCredentialTransaction::TYPE_LOOKEDATSECRET: - case PassphraseCredentialTransaction::TYPE_LOCK: - case PassphraseCredentialTransaction::TYPE_CONDUIT: - return; - } - - return parent::applyCustomExternalTransaction($object, $xaction); - } - - private function destroySecret($secret_id) { - $table = new PassphraseSecret(); - queryfx( - $table->establishConnection('w'), - 'DELETE FROM %T WHERE id = %d', - $table->getTableName(), - $secret_id); - } - - protected function validateTransaction( - PhabricatorLiskDAO $object, - $type, - array $xactions) { - - $errors = parent::validateTransaction($object, $type, $xactions); - - switch ($type) { - case PassphraseCredentialTransaction::TYPE_NAME: - $missing = $this->validateIsEmptyTextField( - $object->getName(), - $xactions); - - if ($missing) { - $error = new PhabricatorApplicationTransactionValidationError( - $type, - pht('Required'), - pht('Credential name is required.'), - nonempty(last($xactions), null)); - - $error->setIsMissingFieldError(true); - $errors[] = $error; - } - break; - case PassphraseCredentialTransaction::TYPE_USERNAME: - $credential_type = $object->getImplementation(); - if (!$credential_type->shouldRequireUsername()) { - break; - } - $missing = $this->validateIsEmptyTextField( - $object->getUsername(), - $xactions); - - if ($missing) { - $error = new PhabricatorApplicationTransactionValidationError( - $type, - pht('Required'), - pht('Username is required.'), - nonempty(last($xactions), null)); - - $error->setIsMissingFieldError(true); - $errors[] = $error; - } - break; - } - - return $errors; + public function getCreateObjectTitleForFeed($author, $object) { + return pht('%s created %s.', $author, $object); } protected function supportsSearch() { diff --git a/src/applications/passphrase/storage/PassphraseCredentialTransaction.php b/src/applications/passphrase/storage/PassphraseCredentialTransaction.php index e0c90fcdb9..b7e4f904ef 100644 --- a/src/applications/passphrase/storage/PassphraseCredentialTransaction.php +++ b/src/applications/passphrase/storage/PassphraseCredentialTransaction.php @@ -1,16 +1,7 @@ getOldValue(); - $new = $this->getNewValue(); - switch ($this->getTransactionType()) { - case self::TYPE_DESCRIPTION: - return ($old === null); - case self::TYPE_LOCK: - return ($old === null); - case self::TYPE_USERNAME: - return !strlen($old); - case self::TYPE_LOOKEDATSECRET: - return false; - case self::TYPE_DESTROY: - // Don't show "undestroy" transactions because they're a bit confusing - // and redundant with restoring a secret. - if (!$new) { - return true; - } - } - return parent::shouldHide(); - } - - public function getTitle() { - $old = $this->getOldValue(); - $new = $this->getNewValue(); - $author_phid = $this->getAuthorPHID(); - - switch ($this->getTransactionType()) { - case self::TYPE_NAME: - if ($old === null) { - return pht( - '%s created this credential.', - $this->renderHandleLink($author_phid)); - } else { - return pht( - '%s renamed this credential from "%s" to "%s".', - $this->renderHandleLink($author_phid), - $old, - $new); - } - break; - case self::TYPE_DESCRIPTION: - return pht( - '%s updated the description for this credential.', - $this->renderHandleLink($author_phid)); - case self::TYPE_USERNAME: - if (strlen($old)) { - return pht( - '%s changed the username for this credential from "%s" to "%s".', - $this->renderHandleLink($author_phid), - $old, - $new); - } else { - return pht( - '%s set the username for this credential to "%s".', - $this->renderHandleLink($author_phid), - $new); - } - break; - case self::TYPE_SECRET_ID: - if ($old === null) { - return pht( - '%s attached a new secret to this credential.', - $this->renderHandleLink($author_phid)); - } else { - return pht( - '%s updated the secret for this credential.', - $this->renderHandleLink($author_phid)); - } - case self::TYPE_DESTROY: - return pht( - '%s destroyed the secret for this credential.', - $this->renderHandleLink($author_phid)); - case self::TYPE_LOOKEDATSECRET: - return pht( - '%s examined the secret plaintext for this credential.', - $this->renderHandleLink($author_phid)); - case self::TYPE_LOCK: - return pht( - '%s locked this credential.', - $this->renderHandleLink($author_phid)); - case self::TYPE_CONDUIT: - if ($old) { - return pht( - '%s disallowed Conduit API access to this credential.', - $this->renderHandleLink($author_phid)); - } else { - return pht( - '%s allowed Conduit API access to this credential.', - $this->renderHandleLink($author_phid)); - } - break; - } - - return parent::getTitle(); - } - - public function hasChangeDetails() { - switch ($this->getTransactionType()) { - case self::TYPE_DESCRIPTION: - return true; - } - return parent::hasChangeDetails(); - } - - public function renderChangeDetails(PhabricatorUser $viewer) { - return $this->renderTextCorpusChangeDetails( - $viewer, - json_encode($this->getOldValue()), - json_encode($this->getNewValue())); + public function getBaseTransactionClass() { + return 'PassphraseCredentialTransactionType'; } } diff --git a/src/applications/passphrase/xaction/PassphraseCredentialConduitTransaction.php b/src/applications/passphrase/xaction/PassphraseCredentialConduitTransaction.php new file mode 100644 index 0000000000..57d9828560 --- /dev/null +++ b/src/applications/passphrase/xaction/PassphraseCredentialConduitTransaction.php @@ -0,0 +1,53 @@ +getAllowConduit(); + } + + public function applyInternalEffects($object, $value) { + $object->setAllowConduit((int)$value); + } + + public function getTitle() { + $new = $this->getNewValue(); + if ($new) { + return pht( + '%s allowed Conduit API access to this credential.', + $this->renderAuthor()); + } else { + return pht( + '%s disallowed Conduit API access to this credential.', + $this->renderAuthor()); + } + } + + public function getTitleForFeed() { + $new = $this->getNewValue(); + if ($new) { + return pht( + '%s allowed Conduit API access to credential %s.', + $this->renderAuthor(), + $this->renderObject()); + } else { + return pht( + '%s disallowed Conduit API access to credential %s.', + $this->renderAuthor(), + $this->renderObject()); + } + } + + public function getIcon() { + $new = $this->getNewValue(); + if ($new) { + return 'fa-tty'; + } else { + return 'fa-ban'; + } + } + +} diff --git a/src/applications/passphrase/xaction/PassphraseCredentialDescriptionTransaction.php b/src/applications/passphrase/xaction/PassphraseCredentialDescriptionTransaction.php new file mode 100644 index 0000000000..ec989cf9c9 --- /dev/null +++ b/src/applications/passphrase/xaction/PassphraseCredentialDescriptionTransaction.php @@ -0,0 +1,64 @@ +getDescription(); + } + + public function applyInternalEffects($object, $value) { + $object->setDescription($value); + } + + public function shouldHide() { + $old = $this->getOldValue(); + if (!strlen($old)) { + return true; + } + return false; + } + + public function getTitle() { + return pht( + '%s updated the description for this credential.', + $this->renderAuthor()); + } + + public function getTitleForFeed() { + return pht( + '%s updated the description for credential %s.', + $this->renderAuthor(), + $this->renderObject()); + } + + public function hasChangeDetailView() { + return true; + } + + public function getMailDiffSectionHeader() { + return pht('CHANGES TO CREDENTIAL DESCRIPTION'); + } + + public function newChangeDetailView() { + $viewer = $this->getViewer(); + + return id(new PhabricatorApplicationTransactionTextDiffDetailView()) + ->setViewer($viewer) + ->setOldText($this->getOldValue()) + ->setNewText($this->getNewValue()); + } + + public function newRemarkupChanges() { + $changes = array(); + + $changes[] = $this->newRemarkupChange() + ->setOldValue($this->getOldValue()) + ->setNewValue($this->getNewValue()); + + return $changes; + } + +} diff --git a/src/applications/passphrase/xaction/PassphraseCredentialDestroyTransaction.php b/src/applications/passphrase/xaction/PassphraseCredentialDestroyTransaction.php new file mode 100644 index 0000000000..3983fd0bbc --- /dev/null +++ b/src/applications/passphrase/xaction/PassphraseCredentialDestroyTransaction.php @@ -0,0 +1,52 @@ +getIsDestroyed(); + } + + public function applyInternalEffects($object, $value) { + $is_destroyed = $value; + $object->setIsDestroyed($is_destroyed); + if ($is_destroyed) { + $secret_id = $object->getSecretID(); + if ($secret_id) { + $this->destroySecret($secret_id); + $object->setSecretID(null); + } + } + } + + public function shouldHide() { + $new = $this->getNewValue(); + if (!$new) { + return true; + } + } + + public function getTitle() { + return pht( + '%s destroyed the secret for this credential.', + $this->renderAuthor()); + } + + public function getTitleForFeed() { + return pht( + '%s destroyed the secret for credential %s.', + $this->renderAuthor(), + $this->renderObject()); + } + + public function getIcon() { + return 'fa-ban'; + } + + public function getColor() { + return 'red'; + } + +} diff --git a/src/applications/passphrase/xaction/PassphraseCredentialLockTransaction.php b/src/applications/passphrase/xaction/PassphraseCredentialLockTransaction.php new file mode 100644 index 0000000000..64eba1da71 --- /dev/null +++ b/src/applications/passphrase/xaction/PassphraseCredentialLockTransaction.php @@ -0,0 +1,41 @@ +getIsLocked(); + } + + public function applyInternalEffects($object, $value) { + $object->setIsLocked((int)$value); + } + + public function shouldHide() { + $new = $this->getNewValue(); + if ($new === null) { + return true; + } + return false; + } + + public function getTitle() { + return pht( + '%s locked this credential.', + $this->renderAuthor()); + } + + public function getTitleForFeed() { + return pht( + '%s locked credential %s.', + $this->renderAuthor(), + $this->renderObject()); + } + + public function getIcon() { + return 'fa-lock'; + } + +} diff --git a/src/applications/passphrase/xaction/PassphraseCredentialLookedAtTransaction.php b/src/applications/passphrase/xaction/PassphraseCredentialLookedAtTransaction.php new file mode 100644 index 0000000000..3d8cb36f31 --- /dev/null +++ b/src/applications/passphrase/xaction/PassphraseCredentialLookedAtTransaction.php @@ -0,0 +1,33 @@ +renderAuthor()); + } + + public function getTitleForFeed() { + return pht( + '%s examined the secret plaintext for credential %s.', + $this->renderAuthor(), + $this->renderObject()); + } + + public function getIcon() { + return 'fa-eye'; + } + + public function getColor() { + return 'blue'; + } + +} diff --git a/src/applications/passphrase/xaction/PassphraseCredentialNameTransaction.php b/src/applications/passphrase/xaction/PassphraseCredentialNameTransaction.php new file mode 100644 index 0000000000..1afac71395 --- /dev/null +++ b/src/applications/passphrase/xaction/PassphraseCredentialNameTransaction.php @@ -0,0 +1,71 @@ +getName(); + } + + public function applyInternalEffects($object, $value) { + $object->setName($value); + } + + public function getTitle() { + $old = $this->getOldValue(); + if (!strlen($old)) { + return pht( + '%s created this credential.', + $this->renderAuthor()); + } else { + return pht( + '%s renamed this credential from %s to %s.', + $this->renderAuthor(), + $this->renderOldValue(), + $this->renderNewValue()); + } + } + + public function getTitleForFeed() { + $old = $this->getOldValue(); + if (!strlen($old)) { + return pht( + '%s created %s.', + $this->renderAuthor(), + $this->renderObject()); + } else { + return pht( + '%s renamed %s credential %s to %s.', + $this->renderAuthor(), + $this->renderObject(), + $this->renderOldValue(), + $this->renderNewValue()); + } + } + + public function validateTransactions($object, array $xactions) { + $errors = array(); + + if ($this->isEmptyTextTransaction($object->getName(), $xactions)) { + $errors[] = $this->newRequiredError( + pht('Credentials must have a name.')); + } + + $max_length = $object->getColumnMaximumByteLength('name'); + foreach ($xactions as $xaction) { + $new_value = $xaction->getNewValue(); + + $new_length = strlen($new_value); + if ($new_length > $max_length) { + $errors[] = $this->newInvalidError( + pht('The name can be no longer than %s characters.', + new PhutilNumber($max_length))); + } + } + + return $errors; + } + +} diff --git a/src/applications/passphrase/xaction/PassphraseCredentialSecretIDTransaction.php b/src/applications/passphrase/xaction/PassphraseCredentialSecretIDTransaction.php new file mode 100644 index 0000000000..2c8e53553a --- /dev/null +++ b/src/applications/passphrase/xaction/PassphraseCredentialSecretIDTransaction.php @@ -0,0 +1,56 @@ +getSecretID(); + } + + public function applyInternalEffects($object, $value) { + $old_id = $object->getSecretID(); + if ($old_id) { + $this->destroySecret($old_id); + } + $object->setSecretID($value); + } + + public function shouldHide() { + if (!$this->getOldValue()) { + return true; + } + + return false; + } + + public function getTitle() { + $old = $this->getOldValue(); + if ($old === null) { + return pht( + '%s attached a new secret to this credential.', + $this->renderAuthor()); + } else { + return pht( + '%s updated the secret for this credential.', + $this->renderAuthor()); + } + } + + public function getTitleForFeed() { + $old = $this->getOldValue(); + if ($old === null) { + return pht( + '%s attached a new secret to %s.', + $this->renderAuthor(), + $this->renderObject()); + } else { + return pht( + '%s updated the secret for %s.', + $this->renderAuthor(), + $this->renderObject()); + } + } + +} diff --git a/src/applications/passphrase/xaction/PassphraseCredentialTransactionType.php b/src/applications/passphrase/xaction/PassphraseCredentialTransactionType.php new file mode 100644 index 0000000000..4e6aadb697 --- /dev/null +++ b/src/applications/passphrase/xaction/PassphraseCredentialTransactionType.php @@ -0,0 +1,15 @@ +establishConnection('w'), + 'DELETE FROM %T WHERE id = %d', + $table->getTableName(), + $secret_id); + } + +} diff --git a/src/applications/passphrase/xaction/PassphraseCredentialUsernameTransaction.php b/src/applications/passphrase/xaction/PassphraseCredentialUsernameTransaction.php new file mode 100644 index 0000000000..fe07bd2990 --- /dev/null +++ b/src/applications/passphrase/xaction/PassphraseCredentialUsernameTransaction.php @@ -0,0 +1,56 @@ +getUsername(); + } + + public function applyInternalEffects($object, $value) { + $object->setUsername($value); + } + + public function getTitle() { + return pht( + '%s set the username for this credential to %s.', + $this->renderAuthor(), + $this->renderNewValue()); + } + + public function getTitleForFeed() { + return pht( + '%s set the username for credential %s to %s.', + $this->renderAuthor(), + $this->renderObject(), + $this->renderNewValue()); + } + + public function validateTransactions($object, array $xactions) { + $errors = array(); + + $credential_type = $object->getImplementation(); + if ($credential_type->shouldRequireUsername()) { + if ($this->isEmptyTextTransaction($object->getUsername(), $xactions)) { + $errors[] = $this->newRequiredError( + pht('This credential must have a username.')); + } + } + + $max_length = $object->getColumnMaximumByteLength('username'); + foreach ($xactions as $xaction) { + $new_value = $xaction->getNewValue(); + $new_length = strlen($new_value); + if ($new_length > $max_length) { + $errors[] = $this->newInvalidError( + pht('The username can be no longer than %s characters.', + new PhutilNumber($max_length))); + } + } + + return $errors; + } + +} From 705fd11ba1735b736a6ab10ff2abeca97f0b7a19 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Thu, 4 May 2017 11:53:52 -0700 Subject: [PATCH 19/25] Update Legalpad to use modular transactions Summary: Update Legalpad for modular transactions Test Plan: - New Document (no sign) - New Document (individual) - New Document (corp) - Require Signature - get prompted to sign before I can do anything. - Edit Documents - Sign Documents - Comment on Documents Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Differential Revision: https://secure.phabricator.com/D17826 --- src/__phutil_library_map__.php | 14 +- .../LegalpadDocumentEditController.php | 15 +- .../editor/LegalpadDocumentEditor.php | 133 +++--------------- .../legalpad/storage/LegalpadTransaction.php | 77 +--------- .../LegalpadDocumentPreambleTransaction.php | 57 ++++++++ ...padDocumentRequireSignatureTransaction.php | 58 ++++++++ ...galpadDocumentSignatureTypeTransaction.php | 29 ++++ .../LegalpadDocumentTextTransaction.php | 60 ++++++++ .../LegalpadDocumentTitleTransaction.php | 58 ++++++++ .../LegalpadDocumentTransactionType.php | 4 + 10 files changed, 308 insertions(+), 197 deletions(-) create mode 100644 src/applications/legalpad/xaction/LegalpadDocumentPreambleTransaction.php create mode 100644 src/applications/legalpad/xaction/LegalpadDocumentRequireSignatureTransaction.php create mode 100644 src/applications/legalpad/xaction/LegalpadDocumentSignatureTypeTransaction.php create mode 100644 src/applications/legalpad/xaction/LegalpadDocumentTextTransaction.php create mode 100644 src/applications/legalpad/xaction/LegalpadDocumentTitleTransaction.php create mode 100644 src/applications/legalpad/xaction/LegalpadDocumentTransactionType.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 35ea8488d0..bed1a60426 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1400,8 +1400,10 @@ phutil_register_library_map(array( 'LegalpadDocumentEditor' => 'applications/legalpad/editor/LegalpadDocumentEditor.php', 'LegalpadDocumentListController' => 'applications/legalpad/controller/LegalpadDocumentListController.php', 'LegalpadDocumentManageController' => 'applications/legalpad/controller/LegalpadDocumentManageController.php', + 'LegalpadDocumentPreambleTransaction' => 'applications/legalpad/xaction/LegalpadDocumentPreambleTransaction.php', 'LegalpadDocumentQuery' => 'applications/legalpad/query/LegalpadDocumentQuery.php', 'LegalpadDocumentRemarkupRule' => 'applications/legalpad/remarkup/LegalpadDocumentRemarkupRule.php', + 'LegalpadDocumentRequireSignatureTransaction' => 'applications/legalpad/xaction/LegalpadDocumentRequireSignatureTransaction.php', 'LegalpadDocumentSearchEngine' => 'applications/legalpad/query/LegalpadDocumentSearchEngine.php', 'LegalpadDocumentSignController' => 'applications/legalpad/controller/LegalpadDocumentSignController.php', 'LegalpadDocumentSignature' => 'applications/legalpad/storage/LegalpadDocumentSignature.php', @@ -1409,8 +1411,12 @@ phutil_register_library_map(array( 'LegalpadDocumentSignatureListController' => 'applications/legalpad/controller/LegalpadDocumentSignatureListController.php', 'LegalpadDocumentSignatureQuery' => 'applications/legalpad/query/LegalpadDocumentSignatureQuery.php', 'LegalpadDocumentSignatureSearchEngine' => 'applications/legalpad/query/LegalpadDocumentSignatureSearchEngine.php', + 'LegalpadDocumentSignatureTypeTransaction' => 'applications/legalpad/xaction/LegalpadDocumentSignatureTypeTransaction.php', 'LegalpadDocumentSignatureVerificationController' => 'applications/legalpad/controller/LegalpadDocumentSignatureVerificationController.php', 'LegalpadDocumentSignatureViewController' => 'applications/legalpad/controller/LegalpadDocumentSignatureViewController.php', + 'LegalpadDocumentTextTransaction' => 'applications/legalpad/xaction/LegalpadDocumentTextTransaction.php', + 'LegalpadDocumentTitleTransaction' => 'applications/legalpad/xaction/LegalpadDocumentTitleTransaction.php', + 'LegalpadDocumentTransactionType' => 'applications/legalpad/xaction/LegalpadDocumentTransactionType.php', 'LegalpadMailReceiver' => 'applications/legalpad/mail/LegalpadMailReceiver.php', 'LegalpadObjectNeedsSignatureEdgeType' => 'applications/legalpad/edge/LegalpadObjectNeedsSignatureEdgeType.php', 'LegalpadReplyHandler' => 'applications/legalpad/mail/LegalpadReplyHandler.php', @@ -6395,8 +6401,10 @@ phutil_register_library_map(array( 'LegalpadDocumentEditor' => 'PhabricatorApplicationTransactionEditor', 'LegalpadDocumentListController' => 'LegalpadController', 'LegalpadDocumentManageController' => 'LegalpadController', + 'LegalpadDocumentPreambleTransaction' => 'LegalpadDocumentTransactionType', 'LegalpadDocumentQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'LegalpadDocumentRemarkupRule' => 'PhabricatorObjectRemarkupRule', + 'LegalpadDocumentRequireSignatureTransaction' => 'LegalpadDocumentTransactionType', 'LegalpadDocumentSearchEngine' => 'PhabricatorApplicationSearchEngine', 'LegalpadDocumentSignController' => 'LegalpadController', 'LegalpadDocumentSignature' => array( @@ -6407,15 +6415,19 @@ phutil_register_library_map(array( 'LegalpadDocumentSignatureListController' => 'LegalpadController', 'LegalpadDocumentSignatureQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'LegalpadDocumentSignatureSearchEngine' => 'PhabricatorApplicationSearchEngine', + 'LegalpadDocumentSignatureTypeTransaction' => 'LegalpadDocumentTransactionType', 'LegalpadDocumentSignatureVerificationController' => 'LegalpadController', 'LegalpadDocumentSignatureViewController' => 'LegalpadController', + 'LegalpadDocumentTextTransaction' => 'LegalpadDocumentTransactionType', + 'LegalpadDocumentTitleTransaction' => 'LegalpadDocumentTransactionType', + 'LegalpadDocumentTransactionType' => 'PhabricatorModularTransactionType', 'LegalpadMailReceiver' => 'PhabricatorObjectMailReceiver', 'LegalpadObjectNeedsSignatureEdgeType' => 'PhabricatorEdgeType', 'LegalpadReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler', 'LegalpadRequireSignatureHeraldAction' => 'HeraldAction', 'LegalpadSchemaSpec' => 'PhabricatorConfigSchemaSpec', 'LegalpadSignatureNeededByObjectEdgeType' => 'PhabricatorEdgeType', - 'LegalpadTransaction' => 'PhabricatorApplicationTransaction', + 'LegalpadTransaction' => 'PhabricatorModularTransaction', 'LegalpadTransactionComment' => 'PhabricatorApplicationTransactionComment', 'LegalpadTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'LegalpadTransactionView' => 'PhabricatorApplicationTransactionView', diff --git a/src/applications/legalpad/controller/LegalpadDocumentEditController.php b/src/applications/legalpad/controller/LegalpadDocumentEditController.php index 8f84f60339..9b1d2ead22 100644 --- a/src/applications/legalpad/controller/LegalpadDocumentEditController.php +++ b/src/applications/legalpad/controller/LegalpadDocumentEditController.php @@ -57,7 +57,8 @@ final class LegalpadDocumentEditController extends LegalpadController { $errors[] = pht('The document title may not be blank.'); } else { $xactions[] = id(new LegalpadTransaction()) - ->setTransactionType(LegalpadTransaction::TYPE_TITLE) + ->setTransactionType( + LegalpadDocumentTitleTransaction::TRANSACTIONTYPE) ->setNewValue($title); } @@ -67,7 +68,8 @@ final class LegalpadDocumentEditController extends LegalpadController { $errors[] = pht('The document may not be blank.'); } else { $xactions[] = id(new LegalpadTransaction()) - ->setTransactionType(LegalpadTransaction::TYPE_TEXT) + ->setTransactionType( + LegalpadDocumentTextTransaction::TRANSACTIONTYPE) ->setNewValue($text); } @@ -83,13 +85,15 @@ final class LegalpadDocumentEditController extends LegalpadController { if ($is_create) { $v_signature_type = $request->getStr('signatureType'); $xactions[] = id(new LegalpadTransaction()) - ->setTransactionType(LegalpadTransaction::TYPE_SIGNATURE_TYPE) + ->setTransactionType( + LegalpadDocumentSignatureTypeTransaction::TRANSACTIONTYPE) ->setNewValue($v_signature_type); } $v_preamble = $request->getStr('preamble'); $xactions[] = id(new LegalpadTransaction()) - ->setTransactionType(LegalpadTransaction::TYPE_PREAMBLE) + ->setTransactionType( + LegalpadDocumentPreambleTransaction::TRANSACTIONTYPE) ->setNewValue($v_preamble); $v_require_signature = $request->getBool('requireSignature', 0); @@ -106,7 +110,8 @@ final class LegalpadDocumentEditController extends LegalpadController { } if ($viewer->getIsAdmin()) { $xactions[] = id(new LegalpadTransaction()) - ->setTransactionType(LegalpadTransaction::TYPE_REQUIRE_SIGNATURE) + ->setTransactionType( + LegalpadDocumentRequireSignatureTransaction::TRANSACTIONTYPE) ->setNewValue($v_require_signature); } diff --git a/src/applications/legalpad/editor/LegalpadDocumentEditor.php b/src/applications/legalpad/editor/LegalpadDocumentEditor.php index 5e319b5905..14430b2c33 100644 --- a/src/applications/legalpad/editor/LegalpadDocumentEditor.php +++ b/src/applications/legalpad/editor/LegalpadDocumentEditor.php @@ -3,8 +3,6 @@ final class LegalpadDocumentEditor extends PhabricatorApplicationTransactionEditor { - private $isContribution = false; - public function getEditorApplicationClass() { return 'PhabricatorLegalpadApplication'; } @@ -13,15 +11,6 @@ final class LegalpadDocumentEditor return pht('Legalpad Documents'); } - private function setIsContribution($is_contribution) { - $this->isContribution = $is_contribution; - return $this; - } - - private function isContribution() { - return $this->isContribution; - } - public function getTransactionTypes() { $types = parent::getTransactionTypes(); @@ -29,99 +18,25 @@ final class LegalpadDocumentEditor $types[] = PhabricatorTransactions::TYPE_VIEW_POLICY; $types[] = PhabricatorTransactions::TYPE_EDIT_POLICY; - $types[] = LegalpadTransaction::TYPE_TITLE; - $types[] = LegalpadTransaction::TYPE_TEXT; - $types[] = LegalpadTransaction::TYPE_SIGNATURE_TYPE; - $types[] = LegalpadTransaction::TYPE_PREAMBLE; - $types[] = LegalpadTransaction::TYPE_REQUIRE_SIGNATURE; - return $types; } - protected function getCustomTransactionOldValue( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case LegalpadTransaction::TYPE_TITLE: - return $object->getDocumentBody()->getTitle(); - case LegalpadTransaction::TYPE_TEXT: - return $object->getDocumentBody()->getText(); - case LegalpadTransaction::TYPE_SIGNATURE_TYPE: - return $object->getSignatureType(); - case LegalpadTransaction::TYPE_PREAMBLE: - return $object->getPreamble(); - case LegalpadTransaction::TYPE_REQUIRE_SIGNATURE: - return (bool)$object->getRequireSignature(); - } - } - - protected function getCustomTransactionNewValue( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case LegalpadTransaction::TYPE_TITLE: - case LegalpadTransaction::TYPE_TEXT: - case LegalpadTransaction::TYPE_SIGNATURE_TYPE: - case LegalpadTransaction::TYPE_PREAMBLE: - return $xaction->getNewValue(); - case LegalpadTransaction::TYPE_REQUIRE_SIGNATURE: - return (bool)$xaction->getNewValue(); - } - } - - protected function applyCustomInternalTransaction( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case LegalpadTransaction::TYPE_TITLE: - $object->setTitle($xaction->getNewValue()); - $body = $object->getDocumentBody(); - $body->setTitle($xaction->getNewValue()); - $this->setIsContribution(true); - break; - case LegalpadTransaction::TYPE_TEXT: - $body = $object->getDocumentBody(); - $body->setText($xaction->getNewValue()); - $this->setIsContribution(true); - break; - case LegalpadTransaction::TYPE_SIGNATURE_TYPE: - $object->setSignatureType($xaction->getNewValue()); - break; - case LegalpadTransaction::TYPE_PREAMBLE: - $object->setPreamble($xaction->getNewValue()); - break; - case LegalpadTransaction::TYPE_REQUIRE_SIGNATURE: - $object->setRequireSignature((int)$xaction->getNewValue()); - break; - } - } - - protected function applyCustomExternalTransaction( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case LegalpadTransaction::TYPE_REQUIRE_SIGNATURE: - if ($xaction->getNewValue()) { - $session = new PhabricatorAuthSession(); - queryfx( - $session->establishConnection('w'), - 'UPDATE %T SET signedLegalpadDocuments = 0', - $session->getTableName()); - } - break; - } - return; - } - protected function applyFinalEffects( PhabricatorLiskDAO $object, array $xactions) { - if ($this->isContribution()) { + $is_contribution = false; + + foreach ($xactions as $xaction) { + switch ($xaction->getTransactionType()) { + case LegalpadDocumentTitleTransaction::TRANSACTIONTYPE: + case LegalpadDocumentTextTransaction::TRANSACTIONTYPE: + $is_contribution = true; + break; + } + } + + if ($is_contribution) { $object->setVersions($object->getVersions() + 1); $body = $object->getDocumentBody(); $body->setVersion($object->getVersions()); @@ -149,22 +64,6 @@ final class LegalpadDocumentEditor return $xactions; } - protected function mergeTransactions( - PhabricatorApplicationTransaction $u, - PhabricatorApplicationTransaction $v) { - - $type = $u->getTransactionType(); - switch ($type) { - case LegalpadTransaction::TYPE_TITLE: - case LegalpadTransaction::TYPE_TEXT: - case LegalpadTransaction::TYPE_SIGNATURE_TYPE: - case LegalpadTransaction::TYPE_PREAMBLE: - case LegalpadTransaction::TYPE_REQUIRE_SIGNATURE: - return $v; - } - - return parent::mergeTransactions($u, $v); - } /* -( Sending Mail )------------------------------------------------------- */ @@ -201,10 +100,10 @@ final class LegalpadDocumentEditor PhabricatorApplicationTransaction $xaction) { switch ($xaction->getTransactionType()) { - case LegalpadTransaction::TYPE_TEXT: - case LegalpadTransaction::TYPE_TITLE: - case LegalpadTransaction::TYPE_PREAMBLE: - case LegalpadTransaction::TYPE_REQUIRE_SIGNATURE: + case LegalpadDocumentTextTransaction::TRANSACTIONTYPE: + case LegalpadDocumentTitleTransaction::TRANSACTIONTYPE: + case LegalpadDocumentPreambleTransaction::TRANSACTIONTYPE: + case LegalpadDocumentRequireSignatureTransaction::TRANSACTIONTYPE: return true; } diff --git a/src/applications/legalpad/storage/LegalpadTransaction.php b/src/applications/legalpad/storage/LegalpadTransaction.php index f85c569279..c43c86c5fc 100644 --- a/src/applications/legalpad/storage/LegalpadTransaction.php +++ b/src/applications/legalpad/storage/LegalpadTransaction.php @@ -1,12 +1,6 @@ getOldValue(); - - switch ($this->getTransactionType()) { - case self::TYPE_TITLE: - case self::TYPE_TEXT: - return ($old === null); - case self::TYPE_SIGNATURE_TYPE: - return true; - } - - return parent::shouldHide(); - } - - public function getTitle() { - $author_phid = $this->getAuthorPHID(); - - $old = $this->getOldValue(); - $new = $this->getNewValue(); - - $type = $this->getTransactionType(); - switch ($type) { - case self::TYPE_TITLE: - return pht( - '%s renamed this document from "%s" to "%s".', - $this->renderHandleLink($author_phid), - $old, - $new); - case self::TYPE_TEXT: - return pht( - "%s updated the document's text.", - $this->renderHandleLink($author_phid)); - case self::TYPE_PREAMBLE: - return pht( - '%s updated the preamble.', - $this->renderHandleLink($author_phid)); - case self::TYPE_REQUIRE_SIGNATURE: - if ($new) { - $text = pht( - '%s set the document to require signatures.', - $this->renderHandleLink($author_phid)); - } else { - $text = pht( - '%s set the document to not require signatures.', - $this->renderHandleLink($author_phid)); - } - return $text; - } - - return parent::getTitle(); - } - - public function hasChangeDetails() { - switch ($this->getTransactionType()) { - case self::TYPE_TITLE: - case self::TYPE_TEXT: - case self::TYPE_PREAMBLE: - return true; - } - return parent::hasChangeDetails(); - } - - public function renderChangeDetails(PhabricatorUser $viewer) { - return $this->renderTextCorpusChangeDetails( - $viewer, - $this->getOldValue(), - $this->getNewValue()); + public function getBaseTransactionClass() { + return 'LegalpadDocumentTransactionType'; } } diff --git a/src/applications/legalpad/xaction/LegalpadDocumentPreambleTransaction.php b/src/applications/legalpad/xaction/LegalpadDocumentPreambleTransaction.php new file mode 100644 index 0000000000..a2b5e1f5cd --- /dev/null +++ b/src/applications/legalpad/xaction/LegalpadDocumentPreambleTransaction.php @@ -0,0 +1,57 @@ +getPreamble(); + } + + public function applyInternalEffects($object, $value) { + $object->setPreamble($value); + } + + public function getTitle() { + return pht( + '%s updated the document preamble.', + $this->renderAuthor()); + } + + public function getTitleForFeed() { + return pht( + '%s updated the document preamble for %s.', + $this->renderAuthor(), + $this->renderObject()); + } + + public function hasChangeDetailView() { + return true; + } + + public function getMailDiffSectionHeader() { + return pht('CHANGES TO DOCUMENT PREAMBLE'); + } + + public function newChangeDetailView() { + $viewer = $this->getViewer(); + + return id(new PhabricatorApplicationTransactionTextDiffDetailView()) + ->setViewer($viewer) + ->setOldText($this->getOldValue()) + ->setNewText($this->getNewValue()); + } + + public function newRemarkupChanges() { + $changes = array(); + + $changes[] = $this->newRemarkupChange() + ->setOldValue($this->getOldValue()) + ->setNewValue($this->getNewValue()); + + return $changes; + } + + +} diff --git a/src/applications/legalpad/xaction/LegalpadDocumentRequireSignatureTransaction.php b/src/applications/legalpad/xaction/LegalpadDocumentRequireSignatureTransaction.php new file mode 100644 index 0000000000..ffef42f0ce --- /dev/null +++ b/src/applications/legalpad/xaction/LegalpadDocumentRequireSignatureTransaction.php @@ -0,0 +1,58 @@ +getRequireSignature(); + } + + public function applyInternalEffects($object, $value) { + $object->setRequireSignature($value); + } + + public function applyExternalEffects($object, $value) { + if (strlen($value)) { + $session = new PhabricatorAuthSession(); + queryfx( + $session->establishConnection('w'), + 'UPDATE %T SET signedLegalpadDocuments = 0', + $session->getTableName()); + } + } + + public function getTitle() { + $new = $this->getNewValue(); + if ($new) { + return pht( + '%s set the document to require signatures.', + $this->renderAuthor()); + } else { + return pht( + '%s set the document to not require signatures.', + $this->renderAuthor()); + } + } + + public function getTitleForFeed() { + $new = $this->getNewValue(); + if ($new) { + return pht( + '%s set the document %s to require signatures.', + $this->renderAuthor(), + $this->renderObject()); + } else { + return pht( + '%s set the document %s to not require signatures.', + $this->renderAuthor(), + $this->renderObject()); + } + } + + public function getIcon() { + return 'fa-pencil-square'; + } + +} diff --git a/src/applications/legalpad/xaction/LegalpadDocumentSignatureTypeTransaction.php b/src/applications/legalpad/xaction/LegalpadDocumentSignatureTypeTransaction.php new file mode 100644 index 0000000000..df9cf60457 --- /dev/null +++ b/src/applications/legalpad/xaction/LegalpadDocumentSignatureTypeTransaction.php @@ -0,0 +1,29 @@ +getSignatureType(); + } + + public function applyInternalEffects($object, $value) { + $object->setSignatureType($value); + } + + public function getTitle() { + return pht( + '%s set the document signature type.', + $this->renderAuthor()); + } + + public function getTitleForFeed() { + return pht( + '%s set the document signature type for %s.', + $this->renderAuthor(), + $this->renderObject()); + } + +} diff --git a/src/applications/legalpad/xaction/LegalpadDocumentTextTransaction.php b/src/applications/legalpad/xaction/LegalpadDocumentTextTransaction.php new file mode 100644 index 0000000000..c17ebc890d --- /dev/null +++ b/src/applications/legalpad/xaction/LegalpadDocumentTextTransaction.php @@ -0,0 +1,60 @@ +getDocumentBody(); + return $body->getText(); + } + + public function applyInternalEffects($object, $value) { + $body = $object->getDocumentBody(); + $body->setText($value); + $object->attachDocumentBody($body); + } + + public function getTitle() { + return pht( + '%s updated the document text.', + $this->renderAuthor()); + } + + public function getTitleForFeed() { + return pht( + '%s updated the document text for %s.', + $this->renderAuthor(), + $this->renderObject()); + } + + public function hasChangeDetailView() { + return true; + } + + public function getMailDiffSectionHeader() { + return pht('CHANGES TO DOCUMENT TEXT'); + } + + public function newChangeDetailView() { + $viewer = $this->getViewer(); + + return id(new PhabricatorApplicationTransactionTextDiffDetailView()) + ->setViewer($viewer) + ->setOldText($this->getOldValue()) + ->setNewText($this->getNewValue()); + } + + public function newRemarkupChanges() { + $changes = array(); + + $changes[] = $this->newRemarkupChange() + ->setOldValue($this->getOldValue()) + ->setNewValue($this->getNewValue()); + + return $changes; + } + + +} diff --git a/src/applications/legalpad/xaction/LegalpadDocumentTitleTransaction.php b/src/applications/legalpad/xaction/LegalpadDocumentTitleTransaction.php new file mode 100644 index 0000000000..c6a4b5b509 --- /dev/null +++ b/src/applications/legalpad/xaction/LegalpadDocumentTitleTransaction.php @@ -0,0 +1,58 @@ +getTitle(); + } + + public function applyInternalEffects($object, $value) { + $object->setTitle($value); + $body = $object->getDocumentBody(); + $body->setTitle($value); + $object->attachDocumentBody($body); + } + + public function getTitle() { + return pht( + '%s renamed this document from %s to %s.', + $this->renderAuthor(), + $this->renderOldValue(), + $this->renderNewValue()); + } + + public function getTitleForFeed() { + return pht( + '%s renamed document %s from %s to %s.', + $this->renderAuthor(), + $this->renderObject(), + $this->renderOldValue(), + $this->renderNewValue()); + } + + public function validateTransactions($object, array $xactions) { + $errors = array(); + + if ($this->isEmptyTextTransaction($object->getTitle(), $xactions)) { + $errors[] = $this->newRequiredError( + pht('Documents must have a title.')); + } + + $max_length = $object->getColumnMaximumByteLength('title'); + foreach ($xactions as $xaction) { + $new_value = $xaction->getNewValue(); + $new_length = strlen($new_value); + if ($new_length > $max_length) { + $errors[] = $this->newInvalidError( + pht('The title can be no longer than %s characters.', + new PhutilNumber($max_length))); + } + } + + return $errors; + } + +} diff --git a/src/applications/legalpad/xaction/LegalpadDocumentTransactionType.php b/src/applications/legalpad/xaction/LegalpadDocumentTransactionType.php new file mode 100644 index 0000000000..58763914ee --- /dev/null +++ b/src/applications/legalpad/xaction/LegalpadDocumentTransactionType.php @@ -0,0 +1,4 @@ + Date: Thu, 4 May 2017 12:06:51 -0700 Subject: [PATCH 20/25] Use a lighter color for completed list items in remarkup Summary: In remarkup lists, it can be hard to clearly see which items still need to be completed. This makes completed items a little lighter for clarity. Test Plan: Review a long list with checked and unchecked items in a task. {F4938611} Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Differential Revision: https://secure.phabricator.com/D17828 --- resources/celerity/map.php | 6 +++--- webroot/rsrc/css/core/remarkup.css | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/resources/celerity/map.php b/resources/celerity/map.php index 3e09edfc4e..930beaa0eb 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -9,7 +9,7 @@ return array( 'names' => array( 'conpherence.pkg.css' => 'ff161f2d', 'conpherence.pkg.js' => 'b5b51108', - 'core.pkg.css' => '84ce260a', + 'core.pkg.css' => '24ffbe93', 'core.pkg.js' => '2ff7879f', 'darkconsole.pkg.js' => '1f9a31bc', 'differential.pkg.css' => '90b30783', @@ -114,7 +114,7 @@ return array( 'rsrc/css/application/tokens/tokens.css' => '3d0f239e', 'rsrc/css/application/uiexample/example.css' => '528b19de', 'rsrc/css/core/core.css' => '9f4cb463', - 'rsrc/css/core/remarkup.css' => '17c0fb37', + 'rsrc/css/core/remarkup.css' => 'd1a5e11e', 'rsrc/css/core/syntax.css' => 'cae95e89', 'rsrc/css/core/z-index.css' => '0233d039', 'rsrc/css/diviner/diviner-shared.css' => '896f1d43', @@ -804,7 +804,7 @@ return array( 'phabricator-object-selector-css' => '85ee8ce6', 'phabricator-phtize' => 'd254d646', 'phabricator-prefab' => 'c5af80a2', - 'phabricator-remarkup-css' => '17c0fb37', + 'phabricator-remarkup-css' => 'd1a5e11e', 'phabricator-search-results-css' => 'f87d23ad', 'phabricator-shaped-request' => '7cbe244b', 'phabricator-slowvote-css' => 'a94b7230', diff --git a/webroot/rsrc/css/core/remarkup.css b/webroot/rsrc/css/core/remarkup.css index a986409227..0c07c145a8 100644 --- a/webroot/rsrc/css/core/remarkup.css +++ b/webroot/rsrc/css/core/remarkup.css @@ -126,12 +126,13 @@ } .phabricator-remarkup .remarkup-list-with-checkmarks input { - margin-right: 2px; + margin-right: 4px; opacity: 1; } .phabricator-remarkup .remarkup-list-with-checkmarks .remarkup-checked-item { text-decoration: line-through; + color: {$lightgreytext}; } .phabricator-remarkup ul.remarkup-list ol.remarkup-list, From d77a3f8760b4c73cfb98af526b597c155a9892c6 Mon Sep 17 00:00:00 2001 From: Chad Little Date: Thu, 4 May 2017 21:48:13 +0000 Subject: [PATCH 21/25] Update Spaces for modular transactions Summary: Updates the Spaces application for modular transactions, seemed easy to bang out. Test Plan: Create a space, edit a space, archive a space. Verify default space works as intended. Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Differential Revision: https://secure.phabricator.com/D17829 --- src/__phutil_library_map__.php | 12 +- .../__tests__/PhabricatorSpacesTestCase.php | 6 +- .../PhabricatorSpacesArchiveController.php | 3 +- .../PhabricatorSpacesEditController.php | 9 +- .../PhabricatorSpacesViewController.php | 2 +- .../PhabricatorSpacesNamespaceEditor.php | 143 +----------------- .../PhabricatorSpacesNamespaceTransaction.php | 81 +--------- ...catorSpacesNamespaceArchiveTransaction.php | 60 ++++++++ ...catorSpacesNamespaceDefaultTransaction.php | 44 ++++++ ...rSpacesNamespaceDescriptionTransaction.php | 57 +++++++ ...bricatorSpacesNamespaceNameTransaction.php | 62 ++++++++ ...bricatorSpacesNamespaceTransactionType.php | 4 + 12 files changed, 258 insertions(+), 225 deletions(-) create mode 100644 src/applications/spaces/xaction/PhabricatorSpacesNamespaceArchiveTransaction.php create mode 100644 src/applications/spaces/xaction/PhabricatorSpacesNamespaceDefaultTransaction.php create mode 100644 src/applications/spaces/xaction/PhabricatorSpacesNamespaceDescriptionTransaction.php create mode 100644 src/applications/spaces/xaction/PhabricatorSpacesNamespaceNameTransaction.php create mode 100644 src/applications/spaces/xaction/PhabricatorSpacesNamespaceTransactionType.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index bed1a60426..14305c04da 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -3937,13 +3937,18 @@ phutil_register_library_map(array( 'PhabricatorSpacesInterface' => 'applications/spaces/interface/PhabricatorSpacesInterface.php', 'PhabricatorSpacesListController' => 'applications/spaces/controller/PhabricatorSpacesListController.php', 'PhabricatorSpacesNamespace' => 'applications/spaces/storage/PhabricatorSpacesNamespace.php', + 'PhabricatorSpacesNamespaceArchiveTransaction' => 'applications/spaces/xaction/PhabricatorSpacesNamespaceArchiveTransaction.php', 'PhabricatorSpacesNamespaceDatasource' => 'applications/spaces/typeahead/PhabricatorSpacesNamespaceDatasource.php', + 'PhabricatorSpacesNamespaceDefaultTransaction' => 'applications/spaces/xaction/PhabricatorSpacesNamespaceDefaultTransaction.php', + 'PhabricatorSpacesNamespaceDescriptionTransaction' => 'applications/spaces/xaction/PhabricatorSpacesNamespaceDescriptionTransaction.php', 'PhabricatorSpacesNamespaceEditor' => 'applications/spaces/editor/PhabricatorSpacesNamespaceEditor.php', + 'PhabricatorSpacesNamespaceNameTransaction' => 'applications/spaces/xaction/PhabricatorSpacesNamespaceNameTransaction.php', 'PhabricatorSpacesNamespacePHIDType' => 'applications/spaces/phid/PhabricatorSpacesNamespacePHIDType.php', 'PhabricatorSpacesNamespaceQuery' => 'applications/spaces/query/PhabricatorSpacesNamespaceQuery.php', 'PhabricatorSpacesNamespaceSearchEngine' => 'applications/spaces/query/PhabricatorSpacesNamespaceSearchEngine.php', 'PhabricatorSpacesNamespaceTransaction' => 'applications/spaces/storage/PhabricatorSpacesNamespaceTransaction.php', 'PhabricatorSpacesNamespaceTransactionQuery' => 'applications/spaces/query/PhabricatorSpacesNamespaceTransactionQuery.php', + 'PhabricatorSpacesNamespaceTransactionType' => 'applications/spaces/xaction/PhabricatorSpacesNamespaceTransactionType.php', 'PhabricatorSpacesNoAccessController' => 'applications/spaces/controller/PhabricatorSpacesNoAccessController.php', 'PhabricatorSpacesRemarkupRule' => 'applications/spaces/remarkup/PhabricatorSpacesRemarkupRule.php', 'PhabricatorSpacesSchemaSpec' => 'applications/spaces/storage/PhabricatorSpacesSchemaSpec.php', @@ -9373,13 +9378,18 @@ phutil_register_library_map(array( 'PhabricatorApplicationTransactionInterface', 'PhabricatorDestructibleInterface', ), + 'PhabricatorSpacesNamespaceArchiveTransaction' => 'PhabricatorSpacesNamespaceTransactionType', 'PhabricatorSpacesNamespaceDatasource' => 'PhabricatorTypeaheadDatasource', + 'PhabricatorSpacesNamespaceDefaultTransaction' => 'PhabricatorSpacesNamespaceTransactionType', + 'PhabricatorSpacesNamespaceDescriptionTransaction' => 'PhabricatorSpacesNamespaceTransactionType', 'PhabricatorSpacesNamespaceEditor' => 'PhabricatorApplicationTransactionEditor', + 'PhabricatorSpacesNamespaceNameTransaction' => 'PhabricatorSpacesNamespaceTransactionType', 'PhabricatorSpacesNamespacePHIDType' => 'PhabricatorPHIDType', 'PhabricatorSpacesNamespaceQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorSpacesNamespaceSearchEngine' => 'PhabricatorApplicationSearchEngine', - 'PhabricatorSpacesNamespaceTransaction' => 'PhabricatorApplicationTransaction', + 'PhabricatorSpacesNamespaceTransaction' => 'PhabricatorModularTransaction', 'PhabricatorSpacesNamespaceTransactionQuery' => 'PhabricatorApplicationTransactionQuery', + 'PhabricatorSpacesNamespaceTransactionType' => 'PhabricatorModularTransactionType', 'PhabricatorSpacesNoAccessController' => 'PhabricatorSpacesController', 'PhabricatorSpacesRemarkupRule' => 'PhabricatorObjectRemarkupRule', 'PhabricatorSpacesSchemaSpec' => 'PhabricatorConfigSchemaSpec', diff --git a/src/applications/spaces/__tests__/PhabricatorSpacesTestCase.php b/src/applications/spaces/__tests__/PhabricatorSpacesTestCase.php index 4215ec96fe..b2a6b0b87f 100644 --- a/src/applications/spaces/__tests__/PhabricatorSpacesTestCase.php +++ b/src/applications/spaces/__tests__/PhabricatorSpacesTestCase.php @@ -190,8 +190,10 @@ final class PhabricatorSpacesTestCase extends PhabricatorTestCase { $space = PhabricatorSpacesNamespace::initializeNewNamespace($actor); - $type_name = PhabricatorSpacesNamespaceTransaction::TYPE_NAME; - $type_default = PhabricatorSpacesNamespaceTransaction::TYPE_DEFAULT; + $type_name = + PhabricatorSpacesNamespaceNameTransaction::TRANSACTIONTYPE; + $type_default = + PhabricatorSpacesNamespaceDefaultTransaction::TRANSACTIONTYPE; $type_view = PhabricatorTransactions::TYPE_VIEW_POLICY; $type_edit = PhabricatorTransactions::TYPE_EDIT_POLICY; diff --git a/src/applications/spaces/controller/PhabricatorSpacesArchiveController.php b/src/applications/spaces/controller/PhabricatorSpacesArchiveController.php index 82cf19e9e8..b0ab8cd45b 100644 --- a/src/applications/spaces/controller/PhabricatorSpacesArchiveController.php +++ b/src/applications/spaces/controller/PhabricatorSpacesArchiveController.php @@ -23,7 +23,8 @@ final class PhabricatorSpacesArchiveController $cancel_uri = '/'.$space->getMonogram(); if ($request->isFormPost()) { - $type_archive = PhabricatorSpacesNamespaceTransaction::TYPE_ARCHIVE; + $type_archive = + PhabricatorSpacesNamespaceArchiveTransaction::TRANSACTIONTYPE; $xactions = array(); $xactions[] = id(new PhabricatorSpacesNamespaceTransaction()) diff --git a/src/applications/spaces/controller/PhabricatorSpacesEditController.php b/src/applications/spaces/controller/PhabricatorSpacesEditController.php index 3f7dae9e82..faca39d634 100644 --- a/src/applications/spaces/controller/PhabricatorSpacesEditController.php +++ b/src/applications/spaces/controller/PhabricatorSpacesEditController.php @@ -67,9 +67,12 @@ final class PhabricatorSpacesEditController $v_view = $request->getStr('viewPolicy'); $v_edit = $request->getStr('editPolicy'); - $type_name = PhabricatorSpacesNamespaceTransaction::TYPE_NAME; - $type_desc = PhabricatorSpacesNamespaceTransaction::TYPE_DESCRIPTION; - $type_default = PhabricatorSpacesNamespaceTransaction::TYPE_DEFAULT; + $type_name = + PhabricatorSpacesNamespaceNameTransaction::TRANSACTIONTYPE; + $type_desc = + PhabricatorSpacesNamespaceDescriptionTransaction::TRANSACTIONTYPE; + $type_default = + PhabricatorSpacesNamespaceDefaultTransaction::TRANSACTIONTYPE; $type_view = PhabricatorTransactions::TYPE_VIEW_POLICY; $type_edit = PhabricatorTransactions::TYPE_EDIT_POLICY; diff --git a/src/applications/spaces/controller/PhabricatorSpacesViewController.php b/src/applications/spaces/controller/PhabricatorSpacesViewController.php index 495a0c8dee..5fa1c01143 100644 --- a/src/applications/spaces/controller/PhabricatorSpacesViewController.php +++ b/src/applications/spaces/controller/PhabricatorSpacesViewController.php @@ -39,7 +39,7 @@ final class PhabricatorSpacesViewController ->setHeaderIcon('fa-th-large'); if ($space->getIsArchived()) { - $header->setStatus('fa-ban', 'red', pht('Archived')); + $header->setStatus('fa-ban', 'indigo', pht('Archived')); } else { $header->setStatus('fa-check', 'bluegrey', pht('Active')); } diff --git a/src/applications/spaces/editor/PhabricatorSpacesNamespaceEditor.php b/src/applications/spaces/editor/PhabricatorSpacesNamespaceEditor.php index caa45f28c2..e4dc9c5b69 100644 --- a/src/applications/spaces/editor/PhabricatorSpacesNamespaceEditor.php +++ b/src/applications/spaces/editor/PhabricatorSpacesNamespaceEditor.php @@ -14,153 +14,18 @@ final class PhabricatorSpacesNamespaceEditor public function getTransactionTypes() { $types = parent::getTransactionTypes(); - $types[] = PhabricatorSpacesNamespaceTransaction::TYPE_NAME; - $types[] = PhabricatorSpacesNamespaceTransaction::TYPE_DESCRIPTION; - $types[] = PhabricatorSpacesNamespaceTransaction::TYPE_DEFAULT; - $types[] = PhabricatorSpacesNamespaceTransaction::TYPE_ARCHIVE; - $types[] = PhabricatorTransactions::TYPE_VIEW_POLICY; $types[] = PhabricatorTransactions::TYPE_EDIT_POLICY; return $types; } - protected function getCustomTransactionOldValue( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case PhabricatorSpacesNamespaceTransaction::TYPE_NAME: - $name = $object->getNamespaceName(); - if (!strlen($name)) { - return null; - } - return $name; - case PhabricatorSpacesNamespaceTransaction::TYPE_DESCRIPTION: - if ($this->getIsNewObject()) { - return null; - } - return $object->getDescription(); - case PhabricatorSpacesNamespaceTransaction::TYPE_ARCHIVE: - return $object->getIsArchived(); - case PhabricatorSpacesNamespaceTransaction::TYPE_DEFAULT: - return $object->getIsDefaultNamespace() ? 1 : null; - case PhabricatorTransactions::TYPE_VIEW_POLICY: - return $object->getViewPolicy(); - case PhabricatorTransactions::TYPE_EDIT_POLICY: - return $object->getEditPolicy(); - } - - return parent::getCustomTransactionOldValue($object, $xaction); + public function getCreateObjectTitle($author, $object) { + return pht('%s created this space.', $author); } - protected function getCustomTransactionNewValue( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case PhabricatorSpacesNamespaceTransaction::TYPE_NAME: - case PhabricatorSpacesNamespaceTransaction::TYPE_DESCRIPTION: - case PhabricatorTransactions::TYPE_VIEW_POLICY: - case PhabricatorTransactions::TYPE_EDIT_POLICY: - return $xaction->getNewValue(); - case PhabricatorSpacesNamespaceTransaction::TYPE_ARCHIVE: - return $xaction->getNewValue() ? 1 : 0; - case PhabricatorSpacesNamespaceTransaction::TYPE_DEFAULT: - return $xaction->getNewValue() ? 1 : null; - } - - return parent::getCustomTransactionNewValue($object, $xaction); - } - - protected function applyCustomInternalTransaction( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - $new = $xaction->getNewValue(); - - switch ($xaction->getTransactionType()) { - case PhabricatorSpacesNamespaceTransaction::TYPE_NAME: - $object->setNamespaceName($new); - return; - case PhabricatorSpacesNamespaceTransaction::TYPE_DESCRIPTION: - $object->setDescription($new); - return; - case PhabricatorSpacesNamespaceTransaction::TYPE_DEFAULT: - $object->setIsDefaultNamespace($new ? 1 : null); - return; - case PhabricatorSpacesNamespaceTransaction::TYPE_ARCHIVE: - $object->setIsArchived($new ? 1 : 0); - return; - case PhabricatorTransactions::TYPE_VIEW_POLICY: - $object->setViewPolicy($new); - return; - case PhabricatorTransactions::TYPE_EDIT_POLICY: - $object->setEditPolicy($new); - return; - } - - return parent::applyCustomInternalTransaction($object, $xaction); - } - - protected function applyCustomExternalTransaction( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case PhabricatorSpacesNamespaceTransaction::TYPE_NAME: - case PhabricatorSpacesNamespaceTransaction::TYPE_DESCRIPTION: - case PhabricatorSpacesNamespaceTransaction::TYPE_DEFAULT: - case PhabricatorSpacesNamespaceTransaction::TYPE_ARCHIVE: - case PhabricatorTransactions::TYPE_VIEW_POLICY: - case PhabricatorTransactions::TYPE_EDIT_POLICY: - return; - } - - return parent::applyCustomExternalTransaction($object, $xaction); - } - - protected function validateTransaction( - PhabricatorLiskDAO $object, - $type, - array $xactions) { - - $errors = parent::validateTransaction($object, $type, $xactions); - - switch ($type) { - case PhabricatorSpacesNamespaceTransaction::TYPE_NAME: - $missing = $this->validateIsEmptyTextField( - $object->getNamespaceName(), - $xactions); - - if ($missing) { - $error = new PhabricatorApplicationTransactionValidationError( - $type, - pht('Required'), - pht('Spaces must have a name.'), - nonempty(last($xactions), null)); - - $error->setIsMissingFieldError(true); - $errors[] = $error; - } - break; - case PhabricatorSpacesNamespaceTransaction::TYPE_DEFAULT: - if (!$this->getIsNewObject()) { - foreach ($xactions as $xaction) { - $errors[] = new PhabricatorApplicationTransactionValidationError( - $type, - pht('Invalid'), - pht( - 'Only the first space created can be the default space, and '. - 'it must remain the default space evermore.'), - $xaction); - } - } - break; - - } - - return $errors; + public function getCreateObjectTitleForFeed($author, $object) { + return pht('%s created space %s.', $author, $object); } } diff --git a/src/applications/spaces/storage/PhabricatorSpacesNamespaceTransaction.php b/src/applications/spaces/storage/PhabricatorSpacesNamespaceTransaction.php index 4c438537f1..0f50a870f6 100644 --- a/src/applications/spaces/storage/PhabricatorSpacesNamespaceTransaction.php +++ b/src/applications/spaces/storage/PhabricatorSpacesNamespaceTransaction.php @@ -1,12 +1,7 @@ getOldValue(); - - switch ($this->getTransactionType()) { - case self::TYPE_DESCRIPTION: - return ($old === null); - } - - return parent::shouldHide(); - } - - public function hasChangeDetails() { - switch ($this->getTransactionType()) { - case self::TYPE_DESCRIPTION: - return true; - } - - return parent::hasChangeDetails(); - } - - public function getRemarkupBlocks() { - $blocks = parent::getRemarkupBlocks(); - - switch ($this->getTransactionType()) { - case self::TYPE_DESCRIPTION: - $blocks[] = $this->getNewValue(); - break; - } - - return $blocks; - } - - public function getTitle() { - $old = $this->getOldValue(); - $new = $this->getNewValue(); - - $author_phid = $this->getAuthorPHID(); - - switch ($this->getTransactionType()) { - case self::TYPE_NAME: - if ($old === null) { - return pht( - '%s created this space.', - $this->renderHandleLink($author_phid)); - } else { - return pht( - '%s renamed this space from "%s" to "%s".', - $this->renderHandleLink($author_phid), - $old, - $new); - } - case self::TYPE_DESCRIPTION: - return pht( - '%s updated the description for this space.', - $this->renderHandleLink($author_phid)); - case self::TYPE_DEFAULT: - return pht( - '%s made this the default space.', - $this->renderHandleLink($author_phid)); - case self::TYPE_ARCHIVE: - if ($new) { - return pht( - '%s archived this space.', - $this->renderHandleLink($author_phid)); - } else { - return pht( - '%s activated this space.', - $this->renderHandleLink($author_phid)); - } - } - - return parent::getTitle(); + public function getBaseTransactionClass() { + return 'PhabricatorSpacesNamespaceTransactionType'; } } diff --git a/src/applications/spaces/xaction/PhabricatorSpacesNamespaceArchiveTransaction.php b/src/applications/spaces/xaction/PhabricatorSpacesNamespaceArchiveTransaction.php new file mode 100644 index 0000000000..a1dedbd85f --- /dev/null +++ b/src/applications/spaces/xaction/PhabricatorSpacesNamespaceArchiveTransaction.php @@ -0,0 +1,60 @@ +getIsArchived(); + } + + public function applyInternalEffects($object, $value) { + $object->setIsArchived((int)$value); + } + + public function getTitle() { + $new = $this->getNewValue(); + if ($new) { + return pht( + '%s archived this space.', + $this->renderAuthor()); + } else { + return pht( + '%s activated this space.', + $this->renderAuthor()); + } + } + + public function getTitleForFeed() { + $new = $this->getNewValue(); + if ($new) { + return pht( + '%s archived space %s.', + $this->renderAuthor(), + $this->renderObject()); + } else { + return pht( + '%s activated space %s.', + $this->renderAuthor(), + $this->renderObject()); + } + } + + public function getIcon() { + $new = $this->getNewValue(); + if ($new) { + return 'fa-ban'; + } else { + return 'fa-check'; + } + } + + public function getColor() { + $new = $this->getNewValue(); + if ($new) { + return 'indigo'; + } + } + +} diff --git a/src/applications/spaces/xaction/PhabricatorSpacesNamespaceDefaultTransaction.php b/src/applications/spaces/xaction/PhabricatorSpacesNamespaceDefaultTransaction.php new file mode 100644 index 0000000000..bc09b06d91 --- /dev/null +++ b/src/applications/spaces/xaction/PhabricatorSpacesNamespaceDefaultTransaction.php @@ -0,0 +1,44 @@ +getIsDefaultNamespace(); + } + + public function applyInternalEffects($object, $value) { + $object->setIsDefaultNamespace($value); + } + + public function getTitle() { + return pht( + '%s made this the default space.', + $this->renderAuthor()); + } + + public function getTitleForFeed() { + return pht( + '%s made space %s the default space.', + $this->renderAuthor(), + $this->renderObject()); + + } + + public function validateTransactions($object, array $xactions) { + $errors = array(); + + if (!$this->isNewObject()) { + foreach ($xactions as $xaction) { + $errors[] = $this->newInvalidError( + pht('Only the first space created can be the default space, and '. + 'it must remain the default space evermore.')); + } + } + + return $errors; + } + +} diff --git a/src/applications/spaces/xaction/PhabricatorSpacesNamespaceDescriptionTransaction.php b/src/applications/spaces/xaction/PhabricatorSpacesNamespaceDescriptionTransaction.php new file mode 100644 index 0000000000..22b0faa5d1 --- /dev/null +++ b/src/applications/spaces/xaction/PhabricatorSpacesNamespaceDescriptionTransaction.php @@ -0,0 +1,57 @@ +getDescription(); + } + + public function applyInternalEffects($object, $value) { + $object->setDescription($value); + } + + public function getTitle() { + return pht( + '%s updated the space description.', + $this->renderAuthor()); + } + + public function getTitleForFeed() { + return pht( + '%s updated the space description for %s.', + $this->renderAuthor(), + $this->renderObject()); + } + + public function hasChangeDetailView() { + return true; + } + + public function getMailDiffSectionHeader() { + return pht('CHANGES TO SPACE DESCRIPTION'); + } + + public function newChangeDetailView() { + $viewer = $this->getViewer(); + + return id(new PhabricatorApplicationTransactionTextDiffDetailView()) + ->setViewer($viewer) + ->setOldText($this->getOldValue()) + ->setNewText($this->getNewValue()); + } + + public function newRemarkupChanges() { + $changes = array(); + + $changes[] = $this->newRemarkupChange() + ->setOldValue($this->getOldValue()) + ->setNewValue($this->getNewValue()); + + return $changes; + } + + +} diff --git a/src/applications/spaces/xaction/PhabricatorSpacesNamespaceNameTransaction.php b/src/applications/spaces/xaction/PhabricatorSpacesNamespaceNameTransaction.php new file mode 100644 index 0000000000..d7fcbc2c7a --- /dev/null +++ b/src/applications/spaces/xaction/PhabricatorSpacesNamespaceNameTransaction.php @@ -0,0 +1,62 @@ +getNamespaceName(); + } + + public function applyInternalEffects($object, $value) { + $object->setNamespaceName($value); + } + + public function getTitle() { + $old = $this->getOldValue(); + if (!strlen($old)) { + return pht( + '%s created this space.', + $this->renderAuthor()); + } else { + return pht( + '%s renamed this space from %s to %s.', + $this->renderAuthor(), + $this->renderOldValue(), + $this->renderNewValue()); + } + } + + public function getTitleForFeed() { + return pht( + '%s renamed space %s from %s to %s.', + $this->renderAuthor(), + $this->renderObject(), + $this->renderOldValue(), + $this->renderNewValue()); + } + + public function validateTransactions($object, array $xactions) { + $errors = array(); + + if ($this->isEmptyTextTransaction($object->getNamespaceName(), $xactions)) { + $errors[] = $this->newRequiredError( + pht('Spaces must have a name.')); + } + + $max_length = $object->getColumnMaximumByteLength('namespaceName'); + foreach ($xactions as $xaction) { + $new_value = $xaction->getNewValue(); + $new_length = strlen($new_value); + if ($new_length > $max_length) { + $errors[] = $this->newInvalidError( + pht('The name can be no longer than %s characters.', + new PhutilNumber($max_length))); + } + } + + return $errors; + } + +} diff --git a/src/applications/spaces/xaction/PhabricatorSpacesNamespaceTransactionType.php b/src/applications/spaces/xaction/PhabricatorSpacesNamespaceTransactionType.php new file mode 100644 index 0000000000..a6f206a16c --- /dev/null +++ b/src/applications/spaces/xaction/PhabricatorSpacesNamespaceTransactionType.php @@ -0,0 +1,4 @@ + Date: Thu, 4 May 2017 17:00:02 -0700 Subject: [PATCH 22/25] Explicitly quote "From" name part when submitting mail to the Mailgun API Summary: We are submitting `epriestley (Evan Priestley) `, but should be submitting `"epriestley (Evan Priestley)" `. Add the missing quotes. Test Plan: Locally, this makes the API calls work against the Mailgun sandbox domain. Reviewers: chad, amckinley Reviewed By: chad, amckinley Differential Revision: https://secure.phabricator.com/D17831 --- .../adapter/PhabricatorMailImplementationMailgunAdapter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/applications/metamta/adapter/PhabricatorMailImplementationMailgunAdapter.php b/src/applications/metamta/adapter/PhabricatorMailImplementationMailgunAdapter.php index 0890ac3004..cfe6491fe0 100644 --- a/src/applications/metamta/adapter/PhabricatorMailImplementationMailgunAdapter.php +++ b/src/applications/metamta/adapter/PhabricatorMailImplementationMailgunAdapter.php @@ -86,7 +86,7 @@ final class PhabricatorMailImplementationMailgunAdapter $from = idx($this->params, 'from'); if (idx($this->params, 'from-name')) { - $params['from'] = "{$this->params['from-name']} <{$from}>"; + $params['from'] = "\"{$this->params['from-name']}\" <{$from}>"; } else { $params['from'] = $from; } From 0dc90b891a7c6d0fe6bef3b5d6a8b40147c17f74 Mon Sep 17 00:00:00 2001 From: Austin McKinley Date: Thu, 4 May 2017 20:16:21 -0700 Subject: [PATCH 23/25] Reimplement Slowvote transactions using modular transactions Summary: Fixes T12623. Adds new modular transactions to Slowvote. Also converts the `shuffle` column to `bool` for consistency with other boolean-ish columns. Test Plan: Create a new vote, modified everything that could be modified from the web UI, observed expected timeline. Example timeline: {F4938843} Example transaction values in DB: {F4938850} Reviewers: #blessed_reviewers, epriestley Reviewed By: #blessed_reviewers, epriestley Subscribers: Korvin, epriestley Maniphest Tasks: T12623 Differential Revision: https://secure.phabricator.com/D17830 --- .../20170504.1.slowvote.shuffle.sql | 2 + src/__phutil_library_map__.php | 14 +- .../PhabricatorSlowvoteCloseController.php | 3 +- .../PhabricatorSlowvoteEditController.php | 19 +- .../editor/PhabricatorSlowvoteEditor.php | 94 +------ .../storage/PhabricatorSlowvotePoll.php | 6 +- .../PhabricatorSlowvoteTransaction.php | 238 +----------------- .../PhabricatorSlowvoteCloseTransaction.php | 60 +++++ ...bricatorSlowvoteDescriptionTransaction.php | 60 +++++ ...PhabricatorSlowvoteQuestionTransaction.php | 70 ++++++ ...habricatorSlowvoteResponsesTransaction.php | 31 +++ .../PhabricatorSlowvoteShuffleTransaction.php | 55 ++++ .../PhabricatorSlowvoteTransactionType.php | 4 + 13 files changed, 323 insertions(+), 333 deletions(-) create mode 100644 resources/sql/autopatches/20170504.1.slowvote.shuffle.sql create mode 100644 src/applications/slowvote/xactions/PhabricatorSlowvoteCloseTransaction.php create mode 100644 src/applications/slowvote/xactions/PhabricatorSlowvoteDescriptionTransaction.php create mode 100644 src/applications/slowvote/xactions/PhabricatorSlowvoteQuestionTransaction.php create mode 100644 src/applications/slowvote/xactions/PhabricatorSlowvoteResponsesTransaction.php create mode 100644 src/applications/slowvote/xactions/PhabricatorSlowvoteShuffleTransaction.php create mode 100644 src/applications/slowvote/xactions/PhabricatorSlowvoteTransactionType.php diff --git a/resources/sql/autopatches/20170504.1.slowvote.shuffle.sql b/resources/sql/autopatches/20170504.1.slowvote.shuffle.sql new file mode 100644 index 0000000000..5797f3fd5c --- /dev/null +++ b/resources/sql/autopatches/20170504.1.slowvote.shuffle.sql @@ -0,0 +1,2 @@ +ALTER TABLE {$NAMESPACE}_slowvote.slowvote_poll + MODIFY shuffle BOOL NOT NULL DEFAULT 0; diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 14305c04da..70dae27882 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -3901,10 +3901,12 @@ phutil_register_library_map(array( 'PhabricatorSlowvoteApplication' => 'applications/slowvote/application/PhabricatorSlowvoteApplication.php', 'PhabricatorSlowvoteChoice' => 'applications/slowvote/storage/PhabricatorSlowvoteChoice.php', 'PhabricatorSlowvoteCloseController' => 'applications/slowvote/controller/PhabricatorSlowvoteCloseController.php', + 'PhabricatorSlowvoteCloseTransaction' => 'applications/slowvote/xactions/PhabricatorSlowvoteCloseTransaction.php', 'PhabricatorSlowvoteCommentController' => 'applications/slowvote/controller/PhabricatorSlowvoteCommentController.php', 'PhabricatorSlowvoteController' => 'applications/slowvote/controller/PhabricatorSlowvoteController.php', 'PhabricatorSlowvoteDAO' => 'applications/slowvote/storage/PhabricatorSlowvoteDAO.php', 'PhabricatorSlowvoteDefaultViewCapability' => 'applications/slowvote/capability/PhabricatorSlowvoteDefaultViewCapability.php', + 'PhabricatorSlowvoteDescriptionTransaction' => 'applications/slowvote/xactions/PhabricatorSlowvoteDescriptionTransaction.php', 'PhabricatorSlowvoteEditController' => 'applications/slowvote/controller/PhabricatorSlowvoteEditController.php', 'PhabricatorSlowvoteEditor' => 'applications/slowvote/editor/PhabricatorSlowvoteEditor.php', 'PhabricatorSlowvoteListController' => 'applications/slowvote/controller/PhabricatorSlowvoteListController.php', @@ -3914,12 +3916,16 @@ phutil_register_library_map(array( 'PhabricatorSlowvotePollController' => 'applications/slowvote/controller/PhabricatorSlowvotePollController.php', 'PhabricatorSlowvotePollPHIDType' => 'applications/slowvote/phid/PhabricatorSlowvotePollPHIDType.php', 'PhabricatorSlowvoteQuery' => 'applications/slowvote/query/PhabricatorSlowvoteQuery.php', + 'PhabricatorSlowvoteQuestionTransaction' => 'applications/slowvote/xactions/PhabricatorSlowvoteQuestionTransaction.php', 'PhabricatorSlowvoteReplyHandler' => 'applications/slowvote/mail/PhabricatorSlowvoteReplyHandler.php', + 'PhabricatorSlowvoteResponsesTransaction' => 'applications/slowvote/xactions/PhabricatorSlowvoteResponsesTransaction.php', 'PhabricatorSlowvoteSchemaSpec' => 'applications/slowvote/storage/PhabricatorSlowvoteSchemaSpec.php', 'PhabricatorSlowvoteSearchEngine' => 'applications/slowvote/query/PhabricatorSlowvoteSearchEngine.php', + 'PhabricatorSlowvoteShuffleTransaction' => 'applications/slowvote/xactions/PhabricatorSlowvoteShuffleTransaction.php', 'PhabricatorSlowvoteTransaction' => 'applications/slowvote/storage/PhabricatorSlowvoteTransaction.php', 'PhabricatorSlowvoteTransactionComment' => 'applications/slowvote/storage/PhabricatorSlowvoteTransactionComment.php', 'PhabricatorSlowvoteTransactionQuery' => 'applications/slowvote/query/PhabricatorSlowvoteTransactionQuery.php', + 'PhabricatorSlowvoteTransactionType' => 'applications/slowvote/xactions/PhabricatorSlowvoteTransactionType.php', 'PhabricatorSlowvoteVoteController' => 'applications/slowvote/controller/PhabricatorSlowvoteVoteController.php', 'PhabricatorSlug' => 'infrastructure/util/PhabricatorSlug.php', 'PhabricatorSlugTestCase' => 'infrastructure/util/__tests__/PhabricatorSlugTestCase.php', @@ -9327,10 +9333,12 @@ phutil_register_library_map(array( 'PhabricatorSlowvoteApplication' => 'PhabricatorApplication', 'PhabricatorSlowvoteChoice' => 'PhabricatorSlowvoteDAO', 'PhabricatorSlowvoteCloseController' => 'PhabricatorSlowvoteController', + 'PhabricatorSlowvoteCloseTransaction' => 'PhabricatorSlowvoteTransactionType', 'PhabricatorSlowvoteCommentController' => 'PhabricatorSlowvoteController', 'PhabricatorSlowvoteController' => 'PhabricatorController', 'PhabricatorSlowvoteDAO' => 'PhabricatorLiskDAO', 'PhabricatorSlowvoteDefaultViewCapability' => 'PhabricatorPolicyCapability', + 'PhabricatorSlowvoteDescriptionTransaction' => 'PhabricatorSlowvoteTransactionType', 'PhabricatorSlowvoteEditController' => 'PhabricatorSlowvoteController', 'PhabricatorSlowvoteEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorSlowvoteListController' => 'PhabricatorSlowvoteController', @@ -9350,12 +9358,16 @@ phutil_register_library_map(array( 'PhabricatorSlowvotePollController' => 'PhabricatorSlowvoteController', 'PhabricatorSlowvotePollPHIDType' => 'PhabricatorPHIDType', 'PhabricatorSlowvoteQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', + 'PhabricatorSlowvoteQuestionTransaction' => 'PhabricatorSlowvoteTransactionType', 'PhabricatorSlowvoteReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler', + 'PhabricatorSlowvoteResponsesTransaction' => 'PhabricatorSlowvoteTransactionType', 'PhabricatorSlowvoteSchemaSpec' => 'PhabricatorConfigSchemaSpec', 'PhabricatorSlowvoteSearchEngine' => 'PhabricatorApplicationSearchEngine', - 'PhabricatorSlowvoteTransaction' => 'PhabricatorApplicationTransaction', + 'PhabricatorSlowvoteShuffleTransaction' => 'PhabricatorSlowvoteTransactionType', + 'PhabricatorSlowvoteTransaction' => 'PhabricatorModularTransaction', 'PhabricatorSlowvoteTransactionComment' => 'PhabricatorApplicationTransactionComment', 'PhabricatorSlowvoteTransactionQuery' => 'PhabricatorApplicationTransactionQuery', + 'PhabricatorSlowvoteTransactionType' => 'PhabricatorModularTransactionType', 'PhabricatorSlowvoteVoteController' => 'PhabricatorSlowvoteController', 'PhabricatorSlug' => 'Phobject', 'PhabricatorSlugTestCase' => 'PhabricatorTestCase', diff --git a/src/applications/slowvote/controller/PhabricatorSlowvoteCloseController.php b/src/applications/slowvote/controller/PhabricatorSlowvoteCloseController.php index 05c12aec27..a4da0f7f7d 100644 --- a/src/applications/slowvote/controller/PhabricatorSlowvoteCloseController.php +++ b/src/applications/slowvote/controller/PhabricatorSlowvoteCloseController.php @@ -32,7 +32,8 @@ final class PhabricatorSlowvoteCloseController $xactions = array(); $xactions[] = id(new PhabricatorSlowvoteTransaction()) - ->setTransactionType(PhabricatorSlowvoteTransaction::TYPE_CLOSE) + ->setTransactionType( + PhabricatorSlowvoteCloseTransaction::TRANSACTIONTYPE) ->setNewValue($new_status); id(new PhabricatorSlowvoteEditor()) diff --git a/src/applications/slowvote/controller/PhabricatorSlowvoteEditController.php b/src/applications/slowvote/controller/PhabricatorSlowvoteEditController.php index e9f3d48de4..d490a77c50 100644 --- a/src/applications/slowvote/controller/PhabricatorSlowvoteEditController.php +++ b/src/applications/slowvote/controller/PhabricatorSlowvoteEditController.php @@ -77,23 +77,32 @@ final class PhabricatorSlowvoteEditController } } - $xactions = array(); $template = id(new PhabricatorSlowvoteTransaction()); + $xactions = array(); + + if ($is_new) { + $xactions[] = id(new PhabricatorSlowvoteTransaction()) + ->setTransactionType(PhabricatorTransactions::TYPE_CREATE); + } $xactions[] = id(clone $template) - ->setTransactionType(PhabricatorSlowvoteTransaction::TYPE_QUESTION) + ->setTransactionType( + PhabricatorSlowvoteQuestionTransaction::TRANSACTIONTYPE) ->setNewValue($v_question); $xactions[] = id(clone $template) - ->setTransactionType(PhabricatorSlowvoteTransaction::TYPE_DESCRIPTION) + ->setTransactionType( + PhabricatorSlowvoteDescriptionTransaction::TRANSACTIONTYPE) ->setNewValue($v_description); $xactions[] = id(clone $template) - ->setTransactionType(PhabricatorSlowvoteTransaction::TYPE_RESPONSES) + ->setTransactionType( + PhabricatorSlowvoteResponsesTransaction::TRANSACTIONTYPE) ->setNewValue($v_responses); $xactions[] = id(clone $template) - ->setTransactionType(PhabricatorSlowvoteTransaction::TYPE_SHUFFLE) + ->setTransactionType( + PhabricatorSlowvoteShuffleTransaction::TRANSACTIONTYPE) ->setNewValue($v_shuffle); $xactions[] = id(clone $template) diff --git a/src/applications/slowvote/editor/PhabricatorSlowvoteEditor.php b/src/applications/slowvote/editor/PhabricatorSlowvoteEditor.php index fa320428e5..3f6baefd8d 100644 --- a/src/applications/slowvote/editor/PhabricatorSlowvoteEditor.php +++ b/src/applications/slowvote/editor/PhabricatorSlowvoteEditor.php @@ -13,104 +13,12 @@ final class PhabricatorSlowvoteEditor public function getTransactionTypes() { $types = parent::getTransactionTypes(); - $types[] = PhabricatorTransactions::TYPE_VIEW_POLICY; - $types[] = PhabricatorSlowvoteTransaction::TYPE_QUESTION; - $types[] = PhabricatorSlowvoteTransaction::TYPE_DESCRIPTION; - $types[] = PhabricatorSlowvoteTransaction::TYPE_RESPONSES; - $types[] = PhabricatorSlowvoteTransaction::TYPE_SHUFFLE; - $types[] = PhabricatorSlowvoteTransaction::TYPE_CLOSE; - return $types; } - protected function transactionHasEffect( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - $old = $xaction->getOldValue(); - $new = $xaction->getNewValue(); - - switch ($xaction->getTransactionType()) { - case PhabricatorSlowvoteTransaction::TYPE_RESPONSES: - if ($old === null) { - return true; - } - return ((int)$old !== (int)$new); - case PhabricatorSlowvoteTransaction::TYPE_SHUFFLE: - if ($old === null) { - return true; - } - return ((bool)$old !== (bool)$new); - } - - return parent::transactionHasEffect($object, $xaction); - } - - - protected function getCustomTransactionOldValue( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case PhabricatorSlowvoteTransaction::TYPE_QUESTION: - return $object->getQuestion(); - case PhabricatorSlowvoteTransaction::TYPE_DESCRIPTION: - return $object->getDescription(); - case PhabricatorSlowvoteTransaction::TYPE_RESPONSES: - return $object->getResponseVisibility(); - case PhabricatorSlowvoteTransaction::TYPE_SHUFFLE: - return $object->getShuffle(); - case PhabricatorSlowvoteTransaction::TYPE_CLOSE: - return $object->getIsClosed(); - } - } - - protected function getCustomTransactionNewValue( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case PhabricatorSlowvoteTransaction::TYPE_QUESTION: - case PhabricatorSlowvoteTransaction::TYPE_DESCRIPTION: - case PhabricatorSlowvoteTransaction::TYPE_RESPONSES: - case PhabricatorSlowvoteTransaction::TYPE_SHUFFLE: - case PhabricatorSlowvoteTransaction::TYPE_CLOSE: - return $xaction->getNewValue(); - } - } - - protected function applyCustomInternalTransaction( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case PhabricatorSlowvoteTransaction::TYPE_QUESTION: - $object->setQuestion($xaction->getNewValue()); - break; - case PhabricatorSlowvoteTransaction::TYPE_DESCRIPTION: - $object->setDescription($xaction->getNewValue()); - break; - case PhabricatorSlowvoteTransaction::TYPE_RESPONSES: - $object->setResponseVisibility($xaction->getNewValue()); - break; - case PhabricatorSlowvoteTransaction::TYPE_SHUFFLE: - $object->setShuffle($xaction->getNewValue()); - break; - case PhabricatorSlowvoteTransaction::TYPE_CLOSE: - $object->setIsClosed((int)$xaction->getNewValue()); - break; - } - } - - protected function applyCustomExternalTransaction( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - return; - } - - protected function shouldSendMail( + protected function shouldSendMail( PhabricatorLiskDAO $object, array $xactions) { return true; diff --git a/src/applications/slowvote/storage/PhabricatorSlowvotePoll.php b/src/applications/slowvote/storage/PhabricatorSlowvotePoll.php index 78c21f5d65..06c4f6f68f 100644 --- a/src/applications/slowvote/storage/PhabricatorSlowvotePoll.php +++ b/src/applications/slowvote/storage/PhabricatorSlowvotePoll.php @@ -21,8 +21,8 @@ final class PhabricatorSlowvotePoll extends PhabricatorSlowvoteDAO protected $question; protected $description; protected $authorPHID; - protected $responseVisibility; - protected $shuffle; + protected $responseVisibility = 0; + protected $shuffle = 0; protected $method; protected $mailKey; protected $viewPolicy; @@ -54,7 +54,7 @@ final class PhabricatorSlowvotePoll extends PhabricatorSlowvoteDAO self::CONFIG_COLUMN_SCHEMA => array( 'question' => 'text255', 'responseVisibility' => 'uint32', - 'shuffle' => 'uint32', + 'shuffle' => 'bool', 'method' => 'uint32', 'description' => 'text', 'isClosed' => 'bool', diff --git a/src/applications/slowvote/storage/PhabricatorSlowvoteTransaction.php b/src/applications/slowvote/storage/PhabricatorSlowvoteTransaction.php index fb1b7fc2f3..1781733acf 100644 --- a/src/applications/slowvote/storage/PhabricatorSlowvoteTransaction.php +++ b/src/applications/slowvote/storage/PhabricatorSlowvoteTransaction.php @@ -1,13 +1,7 @@ getOldValue(); - $new = $this->getNewValue(); - - switch ($this->getTransactionType()) { - case self::TYPE_DESCRIPTION: - case self::TYPE_RESPONSES: - case self::TYPE_SHUFFLE: - case self::TYPE_CLOSE: - return ($old === null); - } - - return parent::shouldHide(); - } - - public function getTitle() { - $author_phid = $this->getAuthorPHID(); - - $old = $this->getOldValue(); - $new = $this->getNewValue(); - - switch ($this->getTransactionType()) { - case self::TYPE_QUESTION: - if ($old === null) { - return pht( - '%s created this poll.', - $this->renderHandleLink($author_phid)); - } else { - return pht( - '%s changed the poll question from "%s" to "%s".', - $this->renderHandleLink($author_phid), - $old, - $new); - } - break; - case self::TYPE_DESCRIPTION: - return pht( - '%s updated the description for this poll.', - $this->renderHandleLink($author_phid)); - case self::TYPE_RESPONSES: - // TODO: This could be more detailed - return pht( - '%s changed who can see the responses.', - $this->renderHandleLink($author_phid)); - case self::TYPE_SHUFFLE: - if ($new) { - return pht( - '%s made poll responses appear in a random order.', - $this->renderHandleLink($author_phid)); - } else { - return pht( - '%s made poll responses appear in a fixed order.', - $this->renderHandleLink($author_phid)); - } - break; - case self::TYPE_CLOSE: - if ($new) { - return pht( - '%s closed this poll.', - $this->renderHandleLink($author_phid)); - } else { - return pht( - '%s reopened this poll.', - $this->renderHandleLink($author_phid)); - } - - break; - } - - return parent::getTitle(); - } - - public function getRemarkupBlocks() { - $blocks = parent::getRemarkupBlocks(); - - $type = $this->getTransactionType(); - switch ($type) { - case self::TYPE_DESCRIPTION: - $blocks[] = $this->getNewValue(); - break; - } - - return $blocks; - } - - public function getTitleForFeed() { - $author_phid = $this->getAuthorPHID(); - $object_phid = $this->getObjectPHID(); - - $old = $this->getOldValue(); - $new = $this->getNewValue(); - - $type = $this->getTransactionType(); - switch ($type) { - case self::TYPE_QUESTION: - if ($old === null) { - return pht( - '%s created %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - - } else { - return pht( - '%s renamed %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - } - break; - case self::TYPE_DESCRIPTION: - if ($old === null) { - return pht( - '%s set the description of %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - - } else { - return pht( - '%s edited the description of %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - } - break; - case self::TYPE_RESPONSES: - // TODO: This could be more detailed - return pht( - '%s changed who can see the responses of %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - - case self::TYPE_SHUFFLE: - if ($new) { - return pht( - '%s made %s responses appear in a random order.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - - } else { - return pht( - '%s made %s responses appear in a fixed order.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - } - case self::TYPE_CLOSE: - if ($new) { - return pht( - '%s closed %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - - } else { - return pht( - '%s reopened %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - } - break; - } - - return parent::getTitleForFeed(); - } - - public function getIcon() { - $old = $this->getOldValue(); - $new = $this->getNewValue(); - - switch ($this->getTransactionType()) { - case self::TYPE_QUESTION: - if ($old === null) { - return 'fa-plus'; - } else { - return 'fa-pencil'; - } - case self::TYPE_DESCRIPTION: - case self::TYPE_RESPONSES: - return 'fa-pencil'; - case self::TYPE_SHUFFLE: - return 'fa-refresh'; - case self::TYPE_CLOSE: - if ($new) { - return 'fa-ban'; - } else { - return 'fa-pencil'; - } - } - - return parent::getIcon(); - } - - - public function getColor() { - $old = $this->getOldValue(); - $new = $this->getNewValue(); - - switch ($this->getTransactionType()) { - case self::TYPE_QUESTION: - case self::TYPE_DESCRIPTION: - case self::TYPE_RESPONSES: - case self::TYPE_SHUFFLE: - case self::TYPE_CLOSE: - return PhabricatorTransactions::COLOR_BLUE; - } - - return parent::getColor(); - } - - public function hasChangeDetails() { - switch ($this->getTransactionType()) { - case self::TYPE_DESCRIPTION: - return true; - } - return parent::hasChangeDetails(); - } - - public function renderChangeDetails(PhabricatorUser $viewer) { - return $this->renderTextCorpusChangeDetails( - $viewer, - $this->getOldValue(), - $this->getNewValue()); + public function getBaseTransactionClass() { + return 'PhabricatorSlowvoteTransactionType'; } public function getMailTags() { $tags = parent::getMailTags(); switch ($this->getTransactionType()) { - case self::TYPE_QUESTION: - case self::TYPE_DESCRIPTION: - case self::TYPE_SHUFFLE: - case self::TYPE_CLOSE: + case PhabricatorSlowvoteQuestionTransaction::TRANSACTIONTYPE: + case PhabricatorSlowvoteDescriptionTransaction::TRANSACTIONTYPE: + case PhabricatorSlowvoteShuffleTransaction::TRANSACTIONTYPE: + case PhabricatorSlowvoteCloseTransaction::TRANSACTIONTYPE: $tags[] = self::MAILTAG_DETAILS; break; - case self::TYPE_RESPONSES: + case PhabricatorSlowvoteResponsesTransaction::TRANSACTIONTYPE: $tags[] = self::MAILTAG_RESPONSES; break; default: diff --git a/src/applications/slowvote/xactions/PhabricatorSlowvoteCloseTransaction.php b/src/applications/slowvote/xactions/PhabricatorSlowvoteCloseTransaction.php new file mode 100644 index 0000000000..ce3eaf5879 --- /dev/null +++ b/src/applications/slowvote/xactions/PhabricatorSlowvoteCloseTransaction.php @@ -0,0 +1,60 @@ +getIsClosed(); + } + + public function generateNewValue($object, $value) { + return (bool)$value; + } + + public function applyInternalEffects($object, $value) { + $object->setIsClosed((int)$value); + } + + public function getTitle() { + $new = $this->getNewValue(); + + if ($new) { + return pht( + '%s closed this poll.', + $this->renderAuthor()); + } else { + return pht( + '%s reopened this poll.', + $this->renderAuthor()); + } + } + + public function getTitleForFeed() { + $new = $this->getNewValue(); + + if ($new) { + return pht( + '%s closed %s.', + $this->renderAuthor(), + $this->renderObject()); + } else { + return pht( + '%s reopened %s.', + $this->renderAuthor(), + $this->renderObject()); + } + } + + public function getIcon() { + $new = $this->getNewValue(); + + if ($new) { + return 'fa-ban'; + } else { + return 'fa-pencil'; + } + } + +} diff --git a/src/applications/slowvote/xactions/PhabricatorSlowvoteDescriptionTransaction.php b/src/applications/slowvote/xactions/PhabricatorSlowvoteDescriptionTransaction.php new file mode 100644 index 0000000000..8a46f7dc5e --- /dev/null +++ b/src/applications/slowvote/xactions/PhabricatorSlowvoteDescriptionTransaction.php @@ -0,0 +1,60 @@ +getDescription(); + } + + public function applyInternalEffects($object, $value) { + $object->setDescription($value); + } + + public function getTitle() { + return pht( + '%s updated the description for this poll.', + $this->renderAuthor()); + } + + public function getTitleForFeed() { + $old = $this->getOldValue(); + + if ($old === null) { + return pht( + '%s set the description of %s.', + $this->renderAuthor(), + $this->renderObject()); + + } else { + return pht( + '%s edited the description of %s.', + $this->renderAuthor(), + $this->renderObject()); + } + } + + public function hasChangeDetails() { + return true; + } + + public function newChangeDetailView() { + return $this->renderTextCorpusChangeDetails( + $this->getViewer(), + $this->getOldValue(), + $this->getNewValue()); + } + + public function newRemarkupChanges() { + $changes = array(); + + $changes[] = $this->newRemarkupChange() + ->setOldValue($this->getOldValue()) + ->setNewValue($this->getNewValue()); + + return $changes; + } + +} diff --git a/src/applications/slowvote/xactions/PhabricatorSlowvoteQuestionTransaction.php b/src/applications/slowvote/xactions/PhabricatorSlowvoteQuestionTransaction.php new file mode 100644 index 0000000000..09c5f93e66 --- /dev/null +++ b/src/applications/slowvote/xactions/PhabricatorSlowvoteQuestionTransaction.php @@ -0,0 +1,70 @@ +getQuestion(); + } + + public function applyInternalEffects($object, $value) { + $object->setQuestion($value); + } + + public function getTitle() { + $old = $this->getOldValue(); + $new = $this->getNewValue(); + + if ($old === null) { + return pht( + '%s created this poll.', + $this->renderAuthor()); + } else { + return pht( + '%s changed the poll question from "%s" to "%s".', + $this->renderAuthor(), + $old, + $new); + } + } + + public function getTitleForFeed() { + $old = $this->getOldValue(); + + if ($old === null) { + return pht( + '%s created %s.', + $this->renderAuthor(), + $this->renderObject()); + + } else { + return pht( + '%s renamed %s.', + $this->renderAuthor(), + $this->renderObject()); + } + } + + public function getIcon() { + $old = $this->getOldValue(); + + if ($old === null) { + return 'fa-plus'; + } else { + return 'fa-pencil'; + } + } + + public function validateTransactions($object, array $xactions) { + $errors = array(); + + if ($this->isEmptyTextTransaction($object->getQuestion(), $xactions)) { + $errors[] = $this->newRequiredError(pht('Polls must have a question.')); + } + + return $errors; + } + +} diff --git a/src/applications/slowvote/xactions/PhabricatorSlowvoteResponsesTransaction.php b/src/applications/slowvote/xactions/PhabricatorSlowvoteResponsesTransaction.php new file mode 100644 index 0000000000..93035cbd6a --- /dev/null +++ b/src/applications/slowvote/xactions/PhabricatorSlowvoteResponsesTransaction.php @@ -0,0 +1,31 @@ +getResponseVisibility(); + } + + public function applyInternalEffects($object, $value) { + $object->setResponseVisibility($value); + } + + public function getTitle() { + // TODO: This could be more detailed + return pht( + '%s changed who can see the responses.', + $this->renderAuthor()); + } + + public function getTitleForFeed() { + // TODO: This could be more detailed + return pht( + '%s changed who can see the responses of %s.', + $this->renderAuthor(), + $this->renderObject()); + } + +} diff --git a/src/applications/slowvote/xactions/PhabricatorSlowvoteShuffleTransaction.php b/src/applications/slowvote/xactions/PhabricatorSlowvoteShuffleTransaction.php new file mode 100644 index 0000000000..645e86b393 --- /dev/null +++ b/src/applications/slowvote/xactions/PhabricatorSlowvoteShuffleTransaction.php @@ -0,0 +1,55 @@ +getShuffle(); + } + + public function generateNewValue($object, $value) { + return (bool)$value; + } + + public function applyInternalEffects($object, $value) { + $object->setShuffle((int)$value); + } + + public function getTitle() { + $new = $this->getNewValue(); + + if ($new) { + return pht( + '%s made poll responses appear in a random order.', + $this->renderAuthor()); + } else { + return pht( + '%s made poll responses appear in a fixed order.', + $this->renderAuthor()); + } + } + + public function getTitleForFeed() { + $new = $this->getNewValue(); + + if ($new) { + return pht( + '%s made %s responses appear in a random order.', + $this->renderAuthor(), + $this->renderObject()); + + } else { + return pht( + '%s made %s responses appear in a fixed order.', + $this->renderAuthor(), + $this->renderObject()); + } + } + + public function getIcon() { + return 'fa-refresh'; + } + +} diff --git a/src/applications/slowvote/xactions/PhabricatorSlowvoteTransactionType.php b/src/applications/slowvote/xactions/PhabricatorSlowvoteTransactionType.php new file mode 100644 index 0000000000..f380aa101c --- /dev/null +++ b/src/applications/slowvote/xactions/PhabricatorSlowvoteTransactionType.php @@ -0,0 +1,4 @@ + Date: Fri, 5 May 2017 11:02:54 -0700 Subject: [PATCH 24/25] Update Fund for modular transactions Summary: Fixes T12627. Updates FundInitiative and FundBacker with modular transactions. Test Plan: Create an Initiative, back it with fake monies, close initiative, reopen, edit various fields. Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Maniphest Tasks: T12627 Differential Revision: https://secure.phabricator.com/D17782 --- src/__phutil_library_map__.php | 26 ++- .../FundInitiativeBackController.php | 2 +- .../FundInitiativeCloseController.php | 2 +- .../FundInitiativeEditController.php | 8 +- .../FundInitiativeViewController.php | 4 +- .../fund/editor/FundBackerEditor.php | 63 ------ .../fund/editor/FundInitiativeEditor.php | 214 +----------------- .../fund/phortune/FundBackerProduct.php | 4 +- .../fund/storage/FundBackerTransaction.php | 9 +- .../storage/FundInitiativeTransaction.php | 207 +---------------- .../xaction/FundBackerRefundTransaction.php | 13 ++ .../xaction/FundBackerStatusTransaction.php | 17 ++ .../xaction/FundBackerTransactionType.php | 4 + .../FundInitiativeBackerTransaction.php | 74 ++++++ .../FundInitiativeDescriptionTransaction.php | 75 ++++++ .../FundInitiativeMerchantTransaction.php | 93 ++++++++ .../xaction/FundInitiativeNameTransaction.php | 71 ++++++ .../FundInitiativeRefundTransaction.php | 77 +++++++ .../FundInitiativeRisksTransaction.php | 80 +++++++ .../FundInitiativeStatusTransaction.php | 51 +++++ .../xaction/FundInitiativeTransactionType.php | 4 + 21 files changed, 609 insertions(+), 489 deletions(-) create mode 100644 src/applications/fund/xaction/FundBackerRefundTransaction.php create mode 100644 src/applications/fund/xaction/FundBackerStatusTransaction.php create mode 100644 src/applications/fund/xaction/FundBackerTransactionType.php create mode 100644 src/applications/fund/xaction/FundInitiativeBackerTransaction.php create mode 100644 src/applications/fund/xaction/FundInitiativeDescriptionTransaction.php create mode 100644 src/applications/fund/xaction/FundInitiativeMerchantTransaction.php create mode 100644 src/applications/fund/xaction/FundInitiativeNameTransaction.php create mode 100644 src/applications/fund/xaction/FundInitiativeRefundTransaction.php create mode 100644 src/applications/fund/xaction/FundInitiativeRisksTransaction.php create mode 100644 src/applications/fund/xaction/FundInitiativeStatusTransaction.php create mode 100644 src/applications/fund/xaction/FundInitiativeTransactionType.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 70dae27882..8389ee567e 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1124,29 +1124,40 @@ phutil_register_library_map(array( 'FundBackerPHIDType' => 'applications/fund/phid/FundBackerPHIDType.php', 'FundBackerProduct' => 'applications/fund/phortune/FundBackerProduct.php', 'FundBackerQuery' => 'applications/fund/query/FundBackerQuery.php', + 'FundBackerRefundTransaction' => 'applications/fund/xaction/FundBackerRefundTransaction.php', 'FundBackerSearchEngine' => 'applications/fund/query/FundBackerSearchEngine.php', + 'FundBackerStatusTransaction' => 'applications/fund/xaction/FundBackerStatusTransaction.php', 'FundBackerTransaction' => 'applications/fund/storage/FundBackerTransaction.php', 'FundBackerTransactionQuery' => 'applications/fund/query/FundBackerTransactionQuery.php', + 'FundBackerTransactionType' => 'applications/fund/xaction/FundBackerTransactionType.php', 'FundController' => 'applications/fund/controller/FundController.php', 'FundCreateInitiativesCapability' => 'applications/fund/capability/FundCreateInitiativesCapability.php', 'FundDAO' => 'applications/fund/storage/FundDAO.php', 'FundDefaultViewCapability' => 'applications/fund/capability/FundDefaultViewCapability.php', 'FundInitiative' => 'applications/fund/storage/FundInitiative.php', 'FundInitiativeBackController' => 'applications/fund/controller/FundInitiativeBackController.php', + 'FundInitiativeBackerTransaction' => 'applications/fund/xaction/FundInitiativeBackerTransaction.php', 'FundInitiativeCloseController' => 'applications/fund/controller/FundInitiativeCloseController.php', 'FundInitiativeCommentController' => 'applications/fund/controller/FundInitiativeCommentController.php', + 'FundInitiativeDescriptionTransaction' => 'applications/fund/xaction/FundInitiativeDescriptionTransaction.php', 'FundInitiativeEditController' => 'applications/fund/controller/FundInitiativeEditController.php', 'FundInitiativeEditor' => 'applications/fund/editor/FundInitiativeEditor.php', 'FundInitiativeFulltextEngine' => 'applications/fund/search/FundInitiativeFulltextEngine.php', 'FundInitiativeListController' => 'applications/fund/controller/FundInitiativeListController.php', + 'FundInitiativeMerchantTransaction' => 'applications/fund/xaction/FundInitiativeMerchantTransaction.php', + 'FundInitiativeNameTransaction' => 'applications/fund/xaction/FundInitiativeNameTransaction.php', 'FundInitiativePHIDType' => 'applications/fund/phid/FundInitiativePHIDType.php', 'FundInitiativeQuery' => 'applications/fund/query/FundInitiativeQuery.php', + 'FundInitiativeRefundTransaction' => 'applications/fund/xaction/FundInitiativeRefundTransaction.php', 'FundInitiativeRemarkupRule' => 'applications/fund/remarkup/FundInitiativeRemarkupRule.php', 'FundInitiativeReplyHandler' => 'applications/fund/mail/FundInitiativeReplyHandler.php', + 'FundInitiativeRisksTransaction' => 'applications/fund/xaction/FundInitiativeRisksTransaction.php', 'FundInitiativeSearchEngine' => 'applications/fund/query/FundInitiativeSearchEngine.php', + 'FundInitiativeStatusTransaction' => 'applications/fund/xaction/FundInitiativeStatusTransaction.php', 'FundInitiativeTransaction' => 'applications/fund/storage/FundInitiativeTransaction.php', 'FundInitiativeTransactionComment' => 'applications/fund/storage/FundInitiativeTransactionComment.php', 'FundInitiativeTransactionQuery' => 'applications/fund/query/FundInitiativeTransactionQuery.php', + 'FundInitiativeTransactionType' => 'applications/fund/xaction/FundInitiativeTransactionType.php', 'FundInitiativeViewController' => 'applications/fund/controller/FundInitiativeViewController.php', 'FundSchemaSpec' => 'applications/fund/storage/FundSchemaSpec.php', 'HarbormasterArcLintBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterArcLintBuildStepImplementation.php', @@ -6066,9 +6077,12 @@ phutil_register_library_map(array( 'FundBackerPHIDType' => 'PhabricatorPHIDType', 'FundBackerProduct' => 'PhortuneProductImplementation', 'FundBackerQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', + 'FundBackerRefundTransaction' => 'FundBackerTransactionType', 'FundBackerSearchEngine' => 'PhabricatorApplicationSearchEngine', - 'FundBackerTransaction' => 'PhabricatorApplicationTransaction', + 'FundBackerStatusTransaction' => 'FundBackerTransactionType', + 'FundBackerTransaction' => 'PhabricatorModularTransaction', 'FundBackerTransactionQuery' => 'PhabricatorApplicationTransactionQuery', + 'FundBackerTransactionType' => 'PhabricatorModularTransactionType', 'FundController' => 'PhabricatorController', 'FundCreateInitiativesCapability' => 'PhabricatorPolicyCapability', 'FundDAO' => 'PhabricatorLiskDAO', @@ -6086,20 +6100,28 @@ phutil_register_library_map(array( 'PhabricatorFulltextInterface', ), 'FundInitiativeBackController' => 'FundController', + 'FundInitiativeBackerTransaction' => 'FundInitiativeTransactionType', 'FundInitiativeCloseController' => 'FundController', 'FundInitiativeCommentController' => 'FundController', + 'FundInitiativeDescriptionTransaction' => 'FundInitiativeTransactionType', 'FundInitiativeEditController' => 'FundController', 'FundInitiativeEditor' => 'PhabricatorApplicationTransactionEditor', 'FundInitiativeFulltextEngine' => 'PhabricatorFulltextEngine', 'FundInitiativeListController' => 'FundController', + 'FundInitiativeMerchantTransaction' => 'FundInitiativeTransactionType', + 'FundInitiativeNameTransaction' => 'FundInitiativeTransactionType', 'FundInitiativePHIDType' => 'PhabricatorPHIDType', 'FundInitiativeQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', + 'FundInitiativeRefundTransaction' => 'FundInitiativeTransactionType', 'FundInitiativeRemarkupRule' => 'PhabricatorObjectRemarkupRule', 'FundInitiativeReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler', + 'FundInitiativeRisksTransaction' => 'FundInitiativeTransactionType', 'FundInitiativeSearchEngine' => 'PhabricatorApplicationSearchEngine', - 'FundInitiativeTransaction' => 'PhabricatorApplicationTransaction', + 'FundInitiativeStatusTransaction' => 'FundInitiativeTransactionType', + 'FundInitiativeTransaction' => 'PhabricatorModularTransaction', 'FundInitiativeTransactionComment' => 'PhabricatorApplicationTransactionComment', 'FundInitiativeTransactionQuery' => 'PhabricatorApplicationTransactionQuery', + 'FundInitiativeTransactionType' => 'PhabricatorModularTransactionType', 'FundInitiativeViewController' => 'FundController', 'FundSchemaSpec' => 'PhabricatorConfigSchemaSpec', 'HarbormasterArcLintBuildStepImplementation' => 'HarbormasterBuildStepImplementation', diff --git a/src/applications/fund/controller/FundInitiativeBackController.php b/src/applications/fund/controller/FundInitiativeBackController.php index 414a5ebd64..17ead82ebf 100644 --- a/src/applications/fund/controller/FundInitiativeBackController.php +++ b/src/applications/fund/controller/FundInitiativeBackController.php @@ -96,7 +96,7 @@ final class FundInitiativeBackController $xactions = array(); $xactions[] = id(new FundBackerTransaction()) - ->setTransactionType(FundBackerTransaction::TYPE_STATUS) + ->setTransactionType(FundBackerStatusTransaction::TRANSACTIONTYPE) ->setNewValue(FundBacker::STATUS_IN_CART); $editor = id(new FundBackerEditor()) diff --git a/src/applications/fund/controller/FundInitiativeCloseController.php b/src/applications/fund/controller/FundInitiativeCloseController.php index 6adddb0d80..97c6de3d97 100644 --- a/src/applications/fund/controller/FundInitiativeCloseController.php +++ b/src/applications/fund/controller/FundInitiativeCloseController.php @@ -25,7 +25,7 @@ final class FundInitiativeCloseController $is_close = !$initiative->isClosed(); if ($request->isFormPost()) { - $type_status = FundInitiativeTransaction::TYPE_STATUS; + $type_status = FundInitiativeStatusTransaction::TRANSACTIONTYPE; if ($is_close) { $new_status = FundInitiative::STATUS_CLOSED; diff --git a/src/applications/fund/controller/FundInitiativeEditController.php b/src/applications/fund/controller/FundInitiativeEditController.php index 6e092d1e05..0576e47330 100644 --- a/src/applications/fund/controller/FundInitiativeEditController.php +++ b/src/applications/fund/controller/FundInitiativeEditController.php @@ -68,10 +68,10 @@ final class FundInitiativeEditController $v_merchant = $request->getStr('merchantPHID'); $v_projects = $request->getArr('projects'); - $type_name = FundInitiativeTransaction::TYPE_NAME; - $type_desc = FundInitiativeTransaction::TYPE_DESCRIPTION; - $type_risk = FundInitiativeTransaction::TYPE_RISKS; - $type_merchant = FundInitiativeTransaction::TYPE_MERCHANT; + $type_name = FundInitiativeNameTransaction::TRANSACTIONTYPE; + $type_desc = FundInitiativeDescriptionTransaction::TRANSACTIONTYPE; + $type_risk = FundInitiativeRisksTransaction::TRANSACTIONTYPE; + $type_merchant = FundInitiativeMerchantTransaction::TRANSACTIONTYPE; $type_view = PhabricatorTransactions::TYPE_VIEW_POLICY; $type_edit = PhabricatorTransactions::TYPE_EDIT_POLICY; diff --git a/src/applications/fund/controller/FundInitiativeViewController.php b/src/applications/fund/controller/FundInitiativeViewController.php index 4960e7aa35..eee79e4df0 100644 --- a/src/applications/fund/controller/FundInitiativeViewController.php +++ b/src/applications/fund/controller/FundInitiativeViewController.php @@ -29,8 +29,8 @@ final class FundInitiativeViewController $initiative->getName()); if ($initiative->isClosed()) { - $status_icon = 'fa-times'; - $status_color = 'bluegrey'; + $status_icon = 'fa-ban'; + $status_color = 'indigo'; } else { $status_icon = 'fa-check'; $status_color = 'bluegrey'; diff --git a/src/applications/fund/editor/FundBackerEditor.php b/src/applications/fund/editor/FundBackerEditor.php index aabd1d8e60..403853863b 100644 --- a/src/applications/fund/editor/FundBackerEditor.php +++ b/src/applications/fund/editor/FundBackerEditor.php @@ -11,67 +11,4 @@ final class FundBackerEditor return pht('Fund Backing'); } - public function getTransactionTypes() { - $types = parent::getTransactionTypes(); - - $types[] = FundBackerTransaction::TYPE_STATUS; - $types[] = FundBackerTransaction::TYPE_REFUND; - - return $types; - } - - protected function getCustomTransactionOldValue( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - switch ($xaction->getTransactionType()) { - case FundBackerTransaction::TYPE_STATUS: - return $object->getStatus(); - case FundBackerTransaction::TYPE_REFUND: - return null; - } - - return parent::getCustomTransactionOldValue($object, $xaction); - } - - protected function getCustomTransactionNewValue( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case FundBackerTransaction::TYPE_STATUS: - case FundBackerTransaction::TYPE_REFUND: - return $xaction->getNewValue(); - } - - return parent::getCustomTransactionNewValue($object, $xaction); - } - - protected function applyCustomInternalTransaction( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case FundBackerTransaction::TYPE_STATUS: - $object->setStatus($xaction->getNewValue()); - return; - case FundBackerTransaction::TYPE_REFUND: - return; - } - - return parent::applyCustomInternalTransaction($object, $xaction); - } - - protected function applyCustomExternalTransaction( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case FundBackerTransaction::TYPE_STATUS: - case FundBackerTransaction::TYPE_REFUND: - return; - } - - return parent::applyCustomExternalTransaction($object, $xaction); - } - } diff --git a/src/applications/fund/editor/FundInitiativeEditor.php b/src/applications/fund/editor/FundInitiativeEditor.php index 40fc6f0174..e5c372fd12 100644 --- a/src/applications/fund/editor/FundInitiativeEditor.php +++ b/src/applications/fund/editor/FundInitiativeEditor.php @@ -11,16 +11,16 @@ final class FundInitiativeEditor return pht('Fund Initiatives'); } + public function getCreateObjectTitle($author, $object) { + return pht('%s created this initiative.', $author); + } + + public function getCreateObjectTitleForFeed($author, $object) { + return pht('%s created %s.', $author, $object); + } + public function getTransactionTypes() { $types = parent::getTransactionTypes(); - - $types[] = FundInitiativeTransaction::TYPE_NAME; - $types[] = FundInitiativeTransaction::TYPE_DESCRIPTION; - $types[] = FundInitiativeTransaction::TYPE_RISKS; - $types[] = FundInitiativeTransaction::TYPE_STATUS; - $types[] = FundInitiativeTransaction::TYPE_BACKER; - $types[] = FundInitiativeTransaction::TYPE_REFUND; - $types[] = FundInitiativeTransaction::TYPE_MERCHANT; $types[] = PhabricatorTransactions::TYPE_VIEW_POLICY; $types[] = PhabricatorTransactions::TYPE_EDIT_POLICY; $types[] = PhabricatorTransactions::TYPE_COMMENT; @@ -28,204 +28,6 @@ final class FundInitiativeEditor return $types; } - protected function getCustomTransactionOldValue( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - switch ($xaction->getTransactionType()) { - case FundInitiativeTransaction::TYPE_NAME: - return $object->getName(); - case FundInitiativeTransaction::TYPE_DESCRIPTION: - return $object->getDescription(); - case FundInitiativeTransaction::TYPE_RISKS: - return $object->getRisks(); - case FundInitiativeTransaction::TYPE_STATUS: - return $object->getStatus(); - case FundInitiativeTransaction::TYPE_BACKER: - case FundInitiativeTransaction::TYPE_REFUND: - return null; - case FundInitiativeTransaction::TYPE_MERCHANT: - return $object->getMerchantPHID(); - } - - return parent::getCustomTransactionOldValue($object, $xaction); - } - - protected function getCustomTransactionNewValue( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - switch ($xaction->getTransactionType()) { - case FundInitiativeTransaction::TYPE_NAME: - case FundInitiativeTransaction::TYPE_DESCRIPTION: - case FundInitiativeTransaction::TYPE_RISKS: - case FundInitiativeTransaction::TYPE_STATUS: - case FundInitiativeTransaction::TYPE_BACKER: - case FundInitiativeTransaction::TYPE_REFUND: - case FundInitiativeTransaction::TYPE_MERCHANT: - return $xaction->getNewValue(); - } - - return parent::getCustomTransactionNewValue($object, $xaction); - } - - protected function applyCustomInternalTransaction( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - $type = $xaction->getTransactionType(); - switch ($type) { - case FundInitiativeTransaction::TYPE_NAME: - $object->setName($xaction->getNewValue()); - return; - case FundInitiativeTransaction::TYPE_DESCRIPTION: - $object->setDescription($xaction->getNewValue()); - return; - case FundInitiativeTransaction::TYPE_RISKS: - $object->setRisks($xaction->getNewValue()); - return; - case FundInitiativeTransaction::TYPE_MERCHANT: - $object->setMerchantPHID($xaction->getNewValue()); - return; - case FundInitiativeTransaction::TYPE_STATUS: - $object->setStatus($xaction->getNewValue()); - return; - case FundInitiativeTransaction::TYPE_BACKER: - case FundInitiativeTransaction::TYPE_REFUND: - $amount = $xaction->getMetadataValue( - FundInitiativeTransaction::PROPERTY_AMOUNT); - $amount = PhortuneCurrency::newFromString($amount); - - if ($type == FundInitiativeTransaction::TYPE_REFUND) { - $total = $object->getTotalAsCurrency()->subtract($amount); - } else { - $total = $object->getTotalAsCurrency()->add($amount); - } - - $object->setTotalAsCurrency($total); - return; - } - - return parent::applyCustomInternalTransaction($object, $xaction); - } - - protected function applyCustomExternalTransaction( - PhabricatorLiskDAO $object, - PhabricatorApplicationTransaction $xaction) { - - $type = $xaction->getTransactionType(); - switch ($type) { - case FundInitiativeTransaction::TYPE_NAME: - case FundInitiativeTransaction::TYPE_DESCRIPTION: - case FundInitiativeTransaction::TYPE_RISKS: - case FundInitiativeTransaction::TYPE_STATUS: - case FundInitiativeTransaction::TYPE_MERCHANT: - return; - case FundInitiativeTransaction::TYPE_BACKER: - case FundInitiativeTransaction::TYPE_REFUND: - $backer = id(new FundBackerQuery()) - ->setViewer($this->requireActor()) - ->withPHIDs(array($xaction->getNewValue())) - ->executeOne(); - if (!$backer) { - throw new Exception(pht('Unable to load %s!', 'FundBacker')); - } - - $subx = array(); - - if ($type == FundInitiativeTransaction::TYPE_BACKER) { - $subx[] = id(new FundBackerTransaction()) - ->setTransactionType(FundBackerTransaction::TYPE_STATUS) - ->setNewValue(FundBacker::STATUS_PURCHASED); - } else { - $amount = $xaction->getMetadataValue( - FundInitiativeTransaction::PROPERTY_AMOUNT); - $subx[] = id(new FundBackerTransaction()) - ->setTransactionType(FundBackerTransaction::TYPE_STATUS) - ->setNewValue($amount); - } - - $editor = id(new FundBackerEditor()) - ->setActor($this->requireActor()) - ->setContentSource($this->getContentSource()) - ->setContinueOnMissingFields(true) - ->setContinueOnNoEffect(true); - - $editor->applyTransactions($backer, $subx); - return; - } - - return parent::applyCustomExternalTransaction($object, $xaction); - } - - protected function validateTransaction( - PhabricatorLiskDAO $object, - $type, - array $xactions) { - - $errors = parent::validateTransaction($object, $type, $xactions); - - switch ($type) { - case FundInitiativeTransaction::TYPE_NAME: - $missing = $this->validateIsEmptyTextField( - $object->getName(), - $xactions); - - if ($missing) { - $error = new PhabricatorApplicationTransactionValidationError( - $type, - pht('Required'), - pht('Initiative name is required.'), - nonempty(last($xactions), null)); - - $error->setIsMissingFieldError(true); - $errors[] = $error; - } - break; - case FundInitiativeTransaction::TYPE_MERCHANT: - $missing = $this->validateIsEmptyTextField( - $object->getName(), - $xactions); - if ($missing) { - $error = new PhabricatorApplicationTransactionValidationError( - $type, - pht('Required'), - pht('Payable merchant is required.'), - nonempty(last($xactions), null)); - - $error->setIsMissingFieldError(true); - $errors[] = $error; - } else if ($xactions) { - $merchant_phid = last($xactions)->getNewValue(); - - // Make sure the actor has permission to edit the merchant they're - // selecting. You aren't allowed to send payments to an account you - // do not control. - $merchants = id(new PhortuneMerchantQuery()) - ->setViewer($this->requireActor()) - ->withPHIDs(array($merchant_phid)) - ->requireCapabilities( - array( - PhabricatorPolicyCapability::CAN_VIEW, - PhabricatorPolicyCapability::CAN_EDIT, - )) - ->execute(); - if (!$merchants) { - $error = new PhabricatorApplicationTransactionValidationError( - $type, - pht('Invalid'), - pht( - 'You must specify a merchant account you control as the '. - 'recipient of funds from this initiative.'), - last($xactions)); - $errors[] = $error; - } - } - break; - } - - return $errors; - } - protected function shouldSendMail( PhabricatorLiskDAO $object, array $xactions) { diff --git a/src/applications/fund/phortune/FundBackerProduct.php b/src/applications/fund/phortune/FundBackerProduct.php index 679a1a41d2..be0dbd9171 100644 --- a/src/applications/fund/phortune/FundBackerProduct.php +++ b/src/applications/fund/phortune/FundBackerProduct.php @@ -105,7 +105,7 @@ final class FundBackerProduct extends PhortuneProductImplementation { $xactions = array(); $xactions[] = id(new FundInitiativeTransaction()) - ->setTransactionType(FundInitiativeTransaction::TYPE_BACKER) + ->setTransactionType(FundInitiativeBackerTransaction::TRANSACTIONTYPE) ->setMetadataValue( FundInitiativeTransaction::PROPERTY_AMOUNT, $backer->getAmountAsCurrency()->serializeForStorage()) @@ -134,7 +134,7 @@ final class FundBackerProduct extends PhortuneProductImplementation { $xactions = array(); $xactions[] = id(new FundInitiativeTransaction()) - ->setTransactionType(FundInitiativeTransaction::TYPE_REFUND) + ->setTransactionType(FundInitiativeRefundTransaction::TRANSACTIONTYPE) ->setMetadataValue( FundInitiativeTransaction::PROPERTY_AMOUNT, $amount->serializeForStorage()) diff --git a/src/applications/fund/storage/FundBackerTransaction.php b/src/applications/fund/storage/FundBackerTransaction.php index 555c7d2966..c24e769eb6 100644 --- a/src/applications/fund/storage/FundBackerTransaction.php +++ b/src/applications/fund/storage/FundBackerTransaction.php @@ -1,10 +1,7 @@ getOldValue(); - $new = $this->getNewValue(); - - $type = $this->getTransactionType(); - switch ($type) { - case self::TYPE_MERCHANT: - if ($old) { - $phids[] = $old; - } - if ($new) { - $phids[] = $new; - } - break; - case self::TYPE_REFUND: - $phids[] = $this->getMetadataValue(self::PROPERTY_BACKER); - break; - } - - return $phids; - } - - public function getTitle() { - $author_phid = $this->getAuthorPHID(); - $object_phid = $this->getObjectPHID(); - - $old = $this->getOldValue(); - $new = $this->getNewValue(); - - $type = $this->getTransactionType(); - switch ($type) { - case self::TYPE_NAME: - if ($old === null) { - return pht( - '%s created this initiative.', - $this->renderHandleLink($author_phid)); - } else { - return pht( - '%s renamed this initiative from "%s" to "%s".', - $this->renderHandleLink($author_phid), - $old, - $new); - } - break; - case self::TYPE_RISKS: - return pht( - '%s edited the risks for this initiative.', - $this->renderHandleLink($author_phid)); - case self::TYPE_DESCRIPTION: - return pht( - '%s edited the description of this initiative.', - $this->renderHandleLink($author_phid)); - case self::TYPE_STATUS: - switch ($new) { - case FundInitiative::STATUS_OPEN: - return pht( - '%s reopened this initiative.', - $this->renderHandleLink($author_phid)); - case FundInitiative::STATUS_CLOSED: - return pht( - '%s closed this initiative.', - $this->renderHandleLink($author_phid)); - } - break; - case self::TYPE_BACKER: - $amount = $this->getMetadataValue(self::PROPERTY_AMOUNT); - $amount = PhortuneCurrency::newFromString($amount); - return pht( - '%s backed this initiative with %s.', - $this->renderHandleLink($author_phid), - $amount->formatForDisplay()); - case self::TYPE_REFUND: - $amount = $this->getMetadataValue(self::PROPERTY_AMOUNT); - $amount = PhortuneCurrency::newFromString($amount); - - $backer_phid = $this->getMetadataValue(self::PROPERTY_BACKER); - - return pht( - '%s refunded %s to %s.', - $this->renderHandleLink($author_phid), - $amount->formatForDisplay(), - $this->renderHandleLink($backer_phid)); - case self::TYPE_MERCHANT: - if ($old === null) { - return pht( - '%s set this initiative to pay to %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($new)); - } else { - return pht( - '%s changed the merchant receiving funds from this '. - 'initiative from %s to %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($old), - $this->renderHandleLink($new)); - } - } - - return parent::getTitle(); - } - - public function getTitleForFeed() { - $author_phid = $this->getAuthorPHID(); - $object_phid = $this->getObjectPHID(); - - $old = $this->getOldValue(); - $new = $this->getNewValue(); - - $type = $this->getTransactionType(); - switch ($type) { - case self::TYPE_NAME: - if ($old === null) { - return pht( - '%s created %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - - } else { - return pht( - '%s renamed %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - } - break; - case self::TYPE_DESCRIPTION: - return pht( - '%s updated the description for %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - case self::TYPE_STATUS: - switch ($new) { - case FundInitiative::STATUS_OPEN: - return pht( - '%s reopened %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - case FundInitiative::STATUS_CLOSED: - return pht( - '%s closed %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid)); - } - break; - case self::TYPE_BACKER: - $amount = $this->getMetadataValue(self::PROPERTY_AMOUNT); - $amount = PhortuneCurrency::newFromString($amount); - return pht( - '%s backed %s with %s.', - $this->renderHandleLink($author_phid), - $this->renderHandleLink($object_phid), - $amount->formatForDisplay()); - case self::TYPE_REFUND: - $amount = $this->getMetadataValue(self::PROPERTY_AMOUNT); - $amount = PhortuneCurrency::newFromString($amount); - - $backer_phid = $this->getMetadataValue(self::PROPERTY_BACKER); - - return pht( - '%s refunded %s to %s for %s.', - $this->renderHandleLink($author_phid), - $amount->formatForDisplay(), - $this->renderHandleLink($backer_phid), - $this->renderHandleLink($object_phid)); - } - - return parent::getTitleForFeed(); + public function getBaseTransactionClass() { + return 'FundInitiativeTransactionType'; } public function getMailTags() { @@ -219,31 +45,4 @@ final class FundInitiativeTransaction return $tags; } - - public function shouldHide() { - $old = $this->getOldValue(); - switch ($this->getTransactionType()) { - case self::TYPE_DESCRIPTION: - case self::TYPE_RISKS: - return ($old === null); - } - return parent::shouldHide(); - } - - public function hasChangeDetails() { - switch ($this->getTransactionType()) { - case self::TYPE_DESCRIPTION: - case self::TYPE_RISKS: - return ($this->getOldValue() !== null); - } - - return parent::hasChangeDetails(); - } - - public function renderChangeDetails(PhabricatorUser $viewer) { - return $this->renderTextCorpusChangeDetails( - $viewer, - $this->getOldValue(), - $this->getNewValue()); - } } diff --git a/src/applications/fund/xaction/FundBackerRefundTransaction.php b/src/applications/fund/xaction/FundBackerRefundTransaction.php new file mode 100644 index 0000000000..0aad952482 --- /dev/null +++ b/src/applications/fund/xaction/FundBackerRefundTransaction.php @@ -0,0 +1,13 @@ +getStatus(); + } + + public function applyInternalEffects($object, $value) { + $object->setStatus($value); + } + + +} diff --git a/src/applications/fund/xaction/FundBackerTransactionType.php b/src/applications/fund/xaction/FundBackerTransactionType.php new file mode 100644 index 0000000000..86ca6703d7 --- /dev/null +++ b/src/applications/fund/xaction/FundBackerTransactionType.php @@ -0,0 +1,4 @@ +getMetadataValue( + FundInitiativeTransaction::PROPERTY_AMOUNT); + $amount = PhortuneCurrency::newFromString($amount); + $total = $object->getTotalAsCurrency()->add($amount); + $object->setTotalAsCurrency($total); + } + + public function applyExternalEffects($object, $value) { + $backer = id(new FundBackerQuery()) + ->setViewer($this->getActor()) + ->withPHIDs(array($value)) + ->executeOne(); + if (!$backer) { + throw new Exception(pht('Unable to load %s!', 'FundBacker')); + } + + $subx = array(); + $subx[] = id(new FundBackerTransaction()) + ->setTransactionType(FundBackerStatusTransaction::TRANSACTIONTYPE) + ->setNewValue(FundBacker::STATUS_PURCHASED); + + $content_source = $this->getEditor()->getContentSource(); + + $editor = id(new FundBackerEditor()) + ->setActor($this->getActor()) + ->setContentSource($content_source) + ->setContinueOnMissingFields(true) + ->setContinueOnNoEffect(true); + + $editor->applyTransactions($backer, $subx); + } + + public function getTitle() { + $amount = $this->getMetadataValue( + FundInitiativeTransaction::PROPERTY_AMOUNT); + $amount = PhortuneCurrency::newFromString($amount); + return pht( + '%s backed this initiative with %s.', + $this->renderAuthor(), + $amount->formatForDisplay()); + } + + public function getTitleForFeed() { + $amount = $this->getMetadataValue( + FundInitiativeTransaction::PROPERTY_AMOUNT); + $amount = PhortuneCurrency::newFromString($amount); + return pht( + '%s backed %s.', + $this->renderAuthor(), + $this->renderObject()); + } + + public function getIcon() { + return 'fa-heart'; + } + + public function getColor() { + return 'red'; + } + + +} diff --git a/src/applications/fund/xaction/FundInitiativeDescriptionTransaction.php b/src/applications/fund/xaction/FundInitiativeDescriptionTransaction.php new file mode 100644 index 0000000000..f32b8499cf --- /dev/null +++ b/src/applications/fund/xaction/FundInitiativeDescriptionTransaction.php @@ -0,0 +1,75 @@ +getDescription(); + } + + public function applyInternalEffects($object, $value) { + $object->setDescription($value); + } + + public function shouldHide() { + $old = $this->getOldValue(); + $new = $this->getNewValue(); + if (!strlen($old) && !strlen($new)) { + return true; + } + return false; + } + + public function getTitle() { + $old = $this->getOldValue(); + $new = $this->getNewValue(); + + if ($old === null) { + return pht( + '%s set the initiative description.', + $this->renderAuthor()); + } else { + return pht( + '%s updated the initiative description.', + $this->renderAuthor()); + } + } + + public function getTitleForFeed() { + return pht( + '%s updated the initiative description for %s.', + $this->renderAuthor(), + $this->renderObject()); + } + + public function hasChangeDetailView() { + return true; + } + + public function getMailDiffSectionHeader() { + return pht('CHANGES TO INITIATIVE DESCRIPTION'); + } + + public function newChangeDetailView() { + $viewer = $this->getViewer(); + + return id(new PhabricatorApplicationTransactionTextDiffDetailView()) + ->setViewer($viewer) + ->setOldText($this->getOldValue()) + ->setNewText($this->getNewValue()); + } + + public function newRemarkupChanges() { + $changes = array(); + + $changes[] = $this->newRemarkupChange() + ->setOldValue($this->getOldValue()) + ->setNewValue($this->getNewValue()); + + return $changes; + } + + +} diff --git a/src/applications/fund/xaction/FundInitiativeMerchantTransaction.php b/src/applications/fund/xaction/FundInitiativeMerchantTransaction.php new file mode 100644 index 0000000000..e2a2597c50 --- /dev/null +++ b/src/applications/fund/xaction/FundInitiativeMerchantTransaction.php @@ -0,0 +1,93 @@ +getMerchantPHID(); + } + + public function applyInternalEffects($object, $value) { + $object->setMerchantPHID($value); + } + + public function getTitle() { + $new = $this->getNewValue(); + $new_merchant = $this->renderHandleList(array($new)); + + $old = $this->getOldValue(); + $old_merchant = $this->renderHandleList(array($old)); + + if ($old) { + return pht( + '%s changed the merchant receiving funds from this '. + 'initiative from %s to %s.', + $this->renderAuthor(), + $old_merchant, + $new_merchant); + } else { + return pht( + '%s set the merchant receiving funds from this '. + 'initiative to %s.', + $this->renderAuthor(), + $new_merchant); + } + } + + public function getTitleForFeed() { + $new = $this->getNewValue(); + $new_merchant = $this->renderHandleList(array($new)); + + $old = $this->getOldValue(); + $old_merchant = $this->renderHandleList(array($old)); + + return pht( + '%s changed the merchant receiving funds from %s '. + 'initiative from %s to %s.', + $this->renderAuthor(), + $this->renderObject(), + $old_merchant, + $new_merchant); + } + + public function validateTransactions($object, array $xactions) { + $errors = array(); + + if ($this->isEmptyTextTransaction($object->getMerchantPHID(), $xactions)) { + $errors[] = $this->newRequiredError( + pht('Initiatives must have a payable merchant.')); + } + + foreach ($xactions as $xaction) { + $merchant_phid = $xaction->getNewValue(); + + // Make sure the actor has permission to edit the merchant they're + // selecting. You aren't allowed to send payments to an account you + // do not control. + $merchants = id(new PhortuneMerchantQuery()) + ->setViewer($this->getActor()) + ->withPHIDs(array($merchant_phid)) + ->requireCapabilities( + array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + )) + ->execute(); + if (!$merchants) { + $errors[] = $this->newInvalidError( + pht('You must specify a merchant account you control as the '. + 'recipient of funds from this initiative.')); + } + } + + return $errors; + } + + public function getIcon() { + return 'fa-bank'; + } + + +} diff --git a/src/applications/fund/xaction/FundInitiativeNameTransaction.php b/src/applications/fund/xaction/FundInitiativeNameTransaction.php new file mode 100644 index 0000000000..5883c32ce2 --- /dev/null +++ b/src/applications/fund/xaction/FundInitiativeNameTransaction.php @@ -0,0 +1,71 @@ +getName(); + } + + public function applyInternalEffects($object, $value) { + $object->setName($value); + } + + public function getTitle() { + $old = $this->getOldValue(); + if (!strlen($old)) { + return pht( + '%s created this initiative.', + $this->renderAuthor()); + } else { + return pht( + '%s renamed this initiative from %s to %s.', + $this->renderAuthor(), + $this->renderOldValue(), + $this->renderNewValue()); + } + } + + public function getTitleForFeed() { + $old = $this->getOldValue(); + if (!strlen($old)) { + return pht( + '%s created initiative %s.', + $this->renderAuthor(), + $this->renderObject()); + } else { + return pht( + '%s renamed %s initiative from %s to %s.', + $this->renderAuthor(), + $this->renderObject(), + $this->renderOldValue(), + $this->renderNewValue()); + } + } + + public function validateTransactions($object, array $xactions) { + $errors = array(); + + if ($this->isEmptyTextTransaction($object->getName(), $xactions)) { + $errors[] = $this->newRequiredError( + pht('Initiatives must have a name.')); + } + + $max_length = $object->getColumnMaximumByteLength('name'); + foreach ($xactions as $xaction) { + $new_value = $xaction->getNewValue(); + $new_length = strlen($new_value); + if ($new_length > $max_length) { + $errors[] = $this->newInvalidError( + pht('The name can be no longer than %s characters.', + new PhutilNumber($max_length))); + } + } + + return $errors; + } + + +} diff --git a/src/applications/fund/xaction/FundInitiativeRefundTransaction.php b/src/applications/fund/xaction/FundInitiativeRefundTransaction.php new file mode 100644 index 0000000000..60bb610a80 --- /dev/null +++ b/src/applications/fund/xaction/FundInitiativeRefundTransaction.php @@ -0,0 +1,77 @@ +getMetadataValue( + FundInitiativeTransaction::PROPERTY_AMOUNT); + $amount = PhortuneCurrency::newFromString($amount); + $total = $object->getTotalAsCurrency()->subtract($amount); + $object->setTotalAsCurrency($total); + } + + public function applyExternalEffects($object, $value) { + $backer = id(new FundBackerQuery()) + ->setViewer($this->getActor()) + ->withPHIDs(array($value)) + ->executeOne(); + if (!$backer) { + throw new Exception(pht('Unable to load %s!', 'FundBacker')); + } + + $subx = array(); + $amount = $this->getMetadataValue( + FundInitiativeTransaction::PROPERTY_AMOUNT); + $subx[] = id(new FundBackerTransaction()) + ->setTransactionType(FundBackerStatusTransaction::TRANSACTIONTYPE) + ->setNewValue($amount); + + $content_source = $this->getEditor()->getContentSource(); + + $editor = id(new FundBackerEditor()) + ->setActor($this->getActor()) + ->setContentSource($content_source) + ->setContinueOnMissingFields(true) + ->setContinueOnNoEffect(true); + + $editor->applyTransactions($backer, $subx); + } + + public function getTitle() { + $amount = $this->getMetadataValue( + FundInitiativeTransaction::PROPERTY_AMOUNT); + $amount = PhortuneCurrency::newFromString($amount); + $backer_phid = $this->getMetadataValue( + FundInitiativeTransaction::PROPERTY_BACKER); + + return pht( + '%s refunded %s to %s.', + $this->renderAuthor(), + $amount->formatForDisplay(), + $this->renderHandleLink($backer_phid)); + } + + public function getTitleForFeed() { + $amount = $this->getMetadataValue( + FundInitiativeTransaction::PROPERTY_AMOUNT); + $amount = PhortuneCurrency::newFromString($amount); + $backer_phid = $this->getMetadataValue( + FundInitiativeTransaction::PROPERTY_BACKER); + + return pht( + '%s refunded %s to %s for %s.', + $this->renderAuthor(), + $amount->formatForDisplay(), + $this->renderHandleLink($backer_phid), + $this->renderObject()); + } + + +} diff --git a/src/applications/fund/xaction/FundInitiativeRisksTransaction.php b/src/applications/fund/xaction/FundInitiativeRisksTransaction.php new file mode 100644 index 0000000000..183f9caa67 --- /dev/null +++ b/src/applications/fund/xaction/FundInitiativeRisksTransaction.php @@ -0,0 +1,80 @@ +getRisks(); + } + + public function applyInternalEffects($object, $value) { + $object->setRisks($value); + } + + public function shouldHide() { + $old = $this->getOldValue(); + $new = $this->getNewValue(); + if (!strlen($old) && !strlen($new)) { + return true; + } + return false; + } + + public function getTitle() { + $old = $this->getOldValue(); + $new = $this->getNewValue(); + + if ($old === null) { + return pht( + '%s set the initiative risks/challenges.', + $this->renderAuthor()); + } else { + return pht( + '%s updated the initiative risks/challenges.', + $this->renderAuthor()); + } + + } + + public function getTitleForFeed() { + return pht( + '%s updated the initiative risks/challenges for %s.', + $this->renderAuthor(), + $this->renderObject()); + } + + public function hasChangeDetailView() { + return true; + } + + public function getMailDiffSectionHeader() { + return pht('CHANGES TO INITIATIVE RISKS/CHALLENGES'); + } + + public function newChangeDetailView() { + $viewer = $this->getViewer(); + + return id(new PhabricatorApplicationTransactionTextDiffDetailView()) + ->setViewer($viewer) + ->setOldText($this->getOldValue()) + ->setNewText($this->getNewValue()); + } + + public function newRemarkupChanges() { + $changes = array(); + + $changes[] = $this->newRemarkupChange() + ->setOldValue($this->getOldValue()) + ->setNewValue($this->getNewValue()); + + return $changes; + } + + public function getIcon() { + return 'fa-ambulance'; + } + + +} diff --git a/src/applications/fund/xaction/FundInitiativeStatusTransaction.php b/src/applications/fund/xaction/FundInitiativeStatusTransaction.php new file mode 100644 index 0000000000..688c8b52c4 --- /dev/null +++ b/src/applications/fund/xaction/FundInitiativeStatusTransaction.php @@ -0,0 +1,51 @@ +getStatus(); + } + + public function applyInternalEffects($object, $value) { + $object->setStatus($value); + } + + public function getTitle() { + if ($this->getNewValue() == FundInitiative::STATUS_CLOSED) { + return pht( + '%s closed this initiative.', + $this->renderAuthor()); + } else { + return pht( + '%s reopened this initiative.', + $this->renderAuthor()); + } + } + + public function getTitleForFeed() { + if ($this->getNewValue() == FundInitiative::STATUS_CLOSED) { + return pht( + '%s closed the initiative %s.', + $this->renderAuthor(), + $this->renderObject()); + } else { + return pht( + '%s reopened the initiative %s.', + $this->renderAuthor(), + $this->renderObject()); + } + } + + public function getIcon() { + if ($this->getNewValue() == FundInitiative::STATUS_CLOSED) { + return 'fa-ban'; + } else { + return 'fa-check'; + } + } + + +} diff --git a/src/applications/fund/xaction/FundInitiativeTransactionType.php b/src/applications/fund/xaction/FundInitiativeTransactionType.php new file mode 100644 index 0000000000..6bcd17f1c7 --- /dev/null +++ b/src/applications/fund/xaction/FundInitiativeTransactionType.php @@ -0,0 +1,4 @@ + Date: Fri, 5 May 2017 11:12:26 -0700 Subject: [PATCH 25/25] Enable Feed stories for Fund Summary: Not sure when these stopped, also fixed mailtag contants. Test Plan: Close an initiative, see story, fund initiative, see story. Reviewers: epriestley Reviewed By: epriestley Subscribers: Korvin Differential Revision: https://secure.phabricator.com/D17835 --- .../fund/storage/FundInitiativeTransaction.php | 12 +++++++++--- .../fund/xaction/FundInitiativeBackerTransaction.php | 5 +++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/applications/fund/storage/FundInitiativeTransaction.php b/src/applications/fund/storage/FundInitiativeTransaction.php index 72e335f0cd..f6071878c5 100644 --- a/src/applications/fund/storage/FundInitiativeTransaction.php +++ b/src/applications/fund/storage/FundInitiativeTransaction.php @@ -26,15 +26,21 @@ final class FundInitiativeTransaction return 'FundInitiativeTransactionType'; } + protected function shouldPublishFeedStory( + PhabricatorLiskDAO $object, + array $xactions) { + return true; + } + public function getMailTags() { $tags = parent::getMailTags(); switch ($this->getTransactionType()) { - case self::TYPE_STATUS: + case FundInitiativeStatusTransaction::TRANSACTIONTYPE: $tags[] = self::MAILTAG_STATUS; break; - case self::TYPE_BACKER: - case self::TYPE_REFUND: + case FundInitiativeBackerTransaction::TRANSACTIONTYPE: + case FundInitiativeRefundTransaction::TRANSACTIONTYPE: $tags[] = self::MAILTAG_BACKER; break; default: diff --git a/src/applications/fund/xaction/FundInitiativeBackerTransaction.php b/src/applications/fund/xaction/FundInitiativeBackerTransaction.php index 94f4230975..72b4b1bd85 100644 --- a/src/applications/fund/xaction/FundInitiativeBackerTransaction.php +++ b/src/applications/fund/xaction/FundInitiativeBackerTransaction.php @@ -57,9 +57,10 @@ final class FundInitiativeBackerTransaction FundInitiativeTransaction::PROPERTY_AMOUNT); $amount = PhortuneCurrency::newFromString($amount); return pht( - '%s backed %s.', + '%s backed %s with %s.', $this->renderAuthor(), - $this->renderObject()); + $this->renderObject(), + $amount->formatForDisplay()); } public function getIcon() {