From 72fc3da41666259c2973fc1a605df92ca9b2bae4 Mon Sep 17 00:00:00 2001 From: Paul Kassianik Date: Wed, 10 Jun 2015 12:21:08 -0700 Subject: [PATCH 01/50] Add a "Date Updated (Oldest First)" sort order to Maniphest Summary: Closes T8484 Test Plan: Create sample tasks then navigate to Maniphest > Advanced Search and choose choose "Date Updated (Oldest First)" in the "Order By" select box. Reviewers: lpriestley, epriestley, #blessed_reviewers Reviewed By: epriestley, #blessed_reviewers Subscribers: epriestley, Korvin Maniphest Tasks: T8484 Differential Revision: https://secure.phabricator.com/D13237 --- src/applications/maniphest/query/ManiphestTaskQuery.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/applications/maniphest/query/ManiphestTaskQuery.php b/src/applications/maniphest/query/ManiphestTaskQuery.php index 956810524d..841a917312 100644 --- a/src/applications/maniphest/query/ManiphestTaskQuery.php +++ b/src/applications/maniphest/query/ManiphestTaskQuery.php @@ -721,9 +721,13 @@ final class ManiphestTaskQuery extends PhabricatorCursorPagedPolicyAwareQuery { ), 'updated' => array( 'vector' => array('updated', 'id'), - 'name' => pht('Date Updated'), + 'name' => pht('Date Updated (Latest First)'), 'aliases' => array(self::ORDER_MODIFIED), ), + 'outdated' => array( + 'vector' => array('-updated', '-id'), + 'name' => pht('Date Updated (Oldest First)'), + ), 'title' => array( 'vector' => array('title', 'id'), 'name' => pht('Title'), @@ -739,6 +743,7 @@ final class ManiphestTaskQuery extends PhabricatorCursorPagedPolicyAwareQuery { array( 'priority', 'updated', + 'outdated', 'newest', 'oldest', 'title', From 5a00b5f6f62e3f8ce85a412ea1d565ee848faa5b Mon Sep 17 00:00:00 2001 From: Joshua Spence Date: Wed, 10 Jun 2015 23:08:57 +1000 Subject: [PATCH 02/50] Garbage collect old notifications Summary: Fixes T8473. Adds garbage collection to the `phabricator_feed.feed_storynotification` table. Test Plan: Reduced the TTL to a really small value and ran the trigger daemon. Saw feed notifications removed from the database. Reviewers: epriestley, #blessed_reviewers Reviewed By: epriestley, #blessed_reviewers Subscribers: epriestley, Korvin Maniphest Tasks: T8473 Differential Revision: https://secure.phabricator.com/D13233 --- src/__phutil_library_map__.php | 2 ++ .../FeedStoryNotificationGarbageCollector.php | 22 +++++++++++++++++++ .../PhabricatorFeedStoryNotification.php | 3 +++ 3 files changed, 27 insertions(+) create mode 100644 src/applications/notification/garbagecollector/FeedStoryNotificationGarbageCollector.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index e0dc41a862..674efa30b1 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -763,6 +763,7 @@ phutil_register_library_map(array( 'FeedPublisherWorker' => 'applications/feed/worker/FeedPublisherWorker.php', 'FeedPushWorker' => 'applications/feed/worker/FeedPushWorker.php', 'FeedQueryConduitAPIMethod' => 'applications/feed/conduit/FeedQueryConduitAPIMethod.php', + 'FeedStoryNotificationGarbageCollector' => 'applications/notification/garbagecollector/FeedStoryNotificationGarbageCollector.php', 'FileAllocateConduitAPIMethod' => 'applications/files/conduit/FileAllocateConduitAPIMethod.php', 'FileConduitAPIMethod' => 'applications/files/conduit/FileConduitAPIMethod.php', 'FileCreateMailReceiver' => 'applications/files/mail/FileCreateMailReceiver.php', @@ -4048,6 +4049,7 @@ phutil_register_library_map(array( 'FeedPublisherWorker' => 'FeedPushWorker', 'FeedPushWorker' => 'PhabricatorWorker', 'FeedQueryConduitAPIMethod' => 'FeedConduitAPIMethod', + 'FeedStoryNotificationGarbageCollector' => 'PhabricatorGarbageCollector', 'FileAllocateConduitAPIMethod' => 'FileConduitAPIMethod', 'FileConduitAPIMethod' => 'ConduitAPIMethod', 'FileCreateMailReceiver' => 'PhabricatorMailReceiver', diff --git a/src/applications/notification/garbagecollector/FeedStoryNotificationGarbageCollector.php b/src/applications/notification/garbagecollector/FeedStoryNotificationGarbageCollector.php new file mode 100644 index 0000000000..5b74237205 --- /dev/null +++ b/src/applications/notification/garbagecollector/FeedStoryNotificationGarbageCollector.php @@ -0,0 +1,22 @@ +establishConnection('w'); + + queryfx( + $conn_w, + 'DELETE FROM %T WHERE chronologicalKey < (%d << 32) + ORDER BY chronologicalKey ASC LIMIT 100', + $table->getTableName(), + time() - $ttl); + + return ($conn_w->getAffectedRows() == 100); + } + +} diff --git a/src/applications/notification/storage/PhabricatorFeedStoryNotification.php b/src/applications/notification/storage/PhabricatorFeedStoryNotification.php index 8f89c987ec..30aec1f281 100644 --- a/src/applications/notification/storage/PhabricatorFeedStoryNotification.php +++ b/src/applications/notification/storage/PhabricatorFeedStoryNotification.php @@ -28,6 +28,9 @@ final class PhabricatorFeedStoryNotification extends PhabricatorFeedDAO { 'key_object' => array( 'columns' => array('primaryObjectPHID'), ), + 'key_chronological' => array( + 'columns' => array('chronologicalKey'), + ), ), ) + parent::getConfiguration(); } From 8d6209b7011336fee24eceeb53f9bb448da3290c Mon Sep 17 00:00:00 2001 From: epriestley Date: Wed, 10 Jun 2015 15:34:02 -0700 Subject: [PATCH 03/50] Don't require users be activated in order to establish Web sessions Summary: Ref T8496. In D13123, the condition for establishing a web session was made too strict: we need to let non-activated users establish web sessions in order to see "you are a bad disabled person" or "your account needs approval" messages. The previous behavior let them in, the new behavior incorrectly locks them out. Test Plan: Enabled login approvals and registered a new account with username/password auth. Reviewers: btrahan Reviewed By: btrahan Subscribers: joshuaspence, epriestley Maniphest Tasks: T8496 Differential Revision: https://secure.phabricator.com/D13239 --- src/applications/people/storage/PhabricatorUser.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/applications/people/storage/PhabricatorUser.php b/src/applications/people/storage/PhabricatorUser.php index 1d1d3316c0..d86f5e380d 100644 --- a/src/applications/people/storage/PhabricatorUser.php +++ b/src/applications/people/storage/PhabricatorUser.php @@ -118,10 +118,6 @@ final class PhabricatorUser } public function canEstablishWebSessions() { - if (!$this->isUserActivated()) { - return false; - } - if ($this->getIsMailingList()) { return false; } From 8a10cfbc9873bf9eff17499cdee83879ab579cf8 Mon Sep 17 00:00:00 2001 From: lkassianik Date: Wed, 10 Jun 2015 15:37:29 -0700 Subject: [PATCH 04/50] Fix missing recurrence end date control Summary: Ref T8472, Fix missing recurrence end date control Test Plan: Create new event, recurrence end date should be available. Reviewers: epriestley, #blessed_reviewers Reviewed By: epriestley, #blessed_reviewers Subscribers: epriestley, Korvin Maniphest Tasks: T8472 Differential Revision: https://secure.phabricator.com/D13241 --- .../controller/PhabricatorCalendarEventEditController.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/applications/calendar/controller/PhabricatorCalendarEventEditController.php b/src/applications/calendar/controller/PhabricatorCalendarEventEditController.php index ccf7cbf0b0..218fe17371 100644 --- a/src/applications/calendar/controller/PhabricatorCalendarEventEditController.php +++ b/src/applications/calendar/controller/PhabricatorCalendarEventEditController.php @@ -17,7 +17,7 @@ final class PhabricatorCalendarEventEditController $viewer = $request->getViewer(); $user_phid = $viewer->getPHID(); $error_name = true; - $error_recurrence_end_date = true; + $error_recurrence_end_date = null; $error_start_date = true; $error_end_date = true; $validation_exception = null; @@ -336,8 +336,7 @@ final class PhabricatorCalendarEventEditController ->setID($recurrence_end_date_id) ->setIsTimeDisabled(true) ->setIsDisabled($recurrence_end_date_value->isDisabled()) - ->setAllowNull(true) - ->isRequired(false); + ->setAllowNull(true); $recurrence_frequency_select = id(new AphrontFormSelectControl()) ->setName('frequency') From 739bdeccabe7ecf6ec93b4598cc262e93e7cedef Mon Sep 17 00:00:00 2001 From: epriestley Date: Wed, 10 Jun 2015 15:52:18 -0700 Subject: [PATCH 05/50] Improve some Spaces behaviors Summary: Ref T8449. Try out some more subtle behaviors: - Make the "Space" control part of the policy control, so the UI shows "Visible To: [Space][Policy]". I think this helps make the role of spaces more clear. It also makes them easier to implement. - Don't show the default space in headers: instead, show nothing. - If the user has access to only one space, pretend spaces don't exist (no edit controls, no header stuff). This might be confusing, but I think most of the time it will all align fairly well with user expectation. Test Plan: - Viewed a list of pastes (saw Space with non-default space, no space with default space, no space with user in only one space). - Viewed a paste (saw Space with non-default space, saw no space with default space, saw no space with user in only one space). - Edited spaces on objects (control as privileged user, no control as locked user). - Created a new paste in a space (got space select as privileged user, no select as locked user). Reviewers: chad, btrahan Reviewed By: btrahan Subscribers: epriestley Maniphest Tasks: T8449 Differential Revision: https://secure.phabricator.com/D13229 --- .../PhabricatorPasteEditController.php | 7 +-- .../people/storage/PhabricatorUser.php | 9 +++ .../query/PhabricatorSpacesNamespaceQuery.php | 11 ++++ .../view/PHUISpacesNamespaceContextView.php | 13 +++++ .../spaces/view/PhabricatorSpacesControl.php | 49 ---------------- ...habricatorApplicationTransactionEditor.php | 35 ++++++++---- .../form/control/AphrontFormPolicyControl.php | 57 +++++++++++++++++++ 7 files changed, 116 insertions(+), 65 deletions(-) delete mode 100644 src/applications/spaces/view/PhabricatorSpacesControl.php diff --git a/src/applications/paste/controller/PhabricatorPasteEditController.php b/src/applications/paste/controller/PhabricatorPasteEditController.php index 7aa28673da..dcc4900951 100644 --- a/src/applications/paste/controller/PhabricatorPasteEditController.php +++ b/src/applications/paste/controller/PhabricatorPasteEditController.php @@ -167,12 +167,6 @@ final class PhabricatorPasteEditController extends PhabricatorPasteController { ->setObject($paste) ->execute(); - $form->appendControl( - id(new PhabricatorSpacesControl()) - ->setObject($paste) - ->setValue($v_space) - ->setName('spacePHID')); - $form->appendChild( id(new AphrontFormPolicyControl()) ->setUser($user) @@ -180,6 +174,7 @@ final class PhabricatorPasteEditController extends PhabricatorPasteController { ->setPolicyObject($paste) ->setPolicies($policies) ->setValue($v_view_policy) + ->setSpacePHID($v_space) ->setName('can_view')); $form->appendChild( diff --git a/src/applications/people/storage/PhabricatorUser.php b/src/applications/people/storage/PhabricatorUser.php index d86f5e380d..aa93485dd2 100644 --- a/src/applications/people/storage/PhabricatorUser.php +++ b/src/applications/people/storage/PhabricatorUser.php @@ -758,6 +758,7 @@ final class PhabricatorUser // TODO: We might let the user switch which space they're "in" later on; // for now just use the global space if one exists. + // If the viewer has access to the default space, use that. $spaces = PhabricatorSpacesNamespaceQuery::getViewerSpaces($this); foreach ($spaces as $space) { if ($space->getIsDefaultNamespace()) { @@ -765,6 +766,14 @@ final class PhabricatorUser } } + // Otherwise, use the space with the lowest ID that they have access to. + // This just tends to keep the default stable and predictable over time, + // so adding a new space won't change behavior for users. + if ($spaces) { + $spaces = msort($spaces, 'getID'); + return head($spaces)->getPHID(); + } + return null; } diff --git a/src/applications/spaces/query/PhabricatorSpacesNamespaceQuery.php b/src/applications/spaces/query/PhabricatorSpacesNamespaceQuery.php index ac02c306e7..77cb8aee5e 100644 --- a/src/applications/spaces/query/PhabricatorSpacesNamespaceQuery.php +++ b/src/applications/spaces/query/PhabricatorSpacesNamespaceQuery.php @@ -90,6 +90,17 @@ final class PhabricatorSpacesNamespaceQuery return (bool)self::getAllSpaces(); } + public static function getViewerSpacesExist(PhabricatorUser $viewer) { + if (!self::getSpacesExist()) { + return false; + } + + // If the viewer has access to only one space, pretend spaces simply don't + // exist. + $spaces = self::getViewerSpaces($viewer); + return (count($spaces) > 1); + } + public static function getAllSpaces() { $cache = PhabricatorCaches::getRequestCache(); $cache_key = self::KEY_ALL; diff --git a/src/applications/spaces/view/PHUISpacesNamespaceContextView.php b/src/applications/spaces/view/PHUISpacesNamespaceContextView.php index ed28f53349..d63ae8e6f4 100644 --- a/src/applications/spaces/view/PHUISpacesNamespaceContextView.php +++ b/src/applications/spaces/view/PHUISpacesNamespaceContextView.php @@ -21,7 +21,20 @@ final class PHUISpacesNamespaceContextView extends AphrontView { return null; } + // If the viewer can't see spaces, pretend they don't exist. $viewer = $this->getUser(); + if (!PhabricatorSpacesNamespaceQuery::getViewerSpacesExist($viewer)) { + return null; + } + + // If this is the default space, don't show a space label. + $default = PhabricatorSpacesNamespaceQuery::getDefaultSpace(); + if ($default) { + if ($default->getPHID() == $space_phid) { + return null; + } + } + return phutil_tag( 'span', array( diff --git a/src/applications/spaces/view/PhabricatorSpacesControl.php b/src/applications/spaces/view/PhabricatorSpacesControl.php deleted file mode 100644 index aa40238c56..0000000000 --- a/src/applications/spaces/view/PhabricatorSpacesControl.php +++ /dev/null @@ -1,49 +0,0 @@ -object = $object; - return $this; - } - - protected function getCustomControlClass() { - return ''; - } - - protected function getOptions() { - $viewer = $this->getUser(); - $viewer_spaces = PhabricatorSpacesNamespaceQuery::getViewerSpaces($viewer); - - $map = mpull($viewer_spaces, 'getNamespaceName', 'getPHID'); - asort($map); - - return $map; - } - - protected function renderInput() { - $viewer = $this->getUser(); - - $this->setLabel(pht('Space')); - - $value = $this->getValue(); - if ($value === null) { - $value = $viewer->getDefaultSpacePHID(); - } - - return AphrontFormSelectControl::renderSelectTag( - $value, - $this->getOptions(), - array( - 'name' => $this->getName(), - )); - } - -} diff --git a/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php b/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php index d89c782900..9602ee6227 100644 --- a/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php +++ b/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php @@ -360,10 +360,13 @@ abstract class PhabricatorApplicationTransactionEditor case PhabricatorTransactions::TYPE_SPACE: $space_phid = $xaction->getNewValue(); if (!strlen($space_phid)) { - // If an install has no Spaces, we might end up with the empty string - // here instead of a strict `null`. Just make this work like callers - // might reasonably expect. - return null; + // If an install has no Spaces or the Spaces controls are not visible + // to the viewer, we might end up with the empty string here instead + // of a strict `null`, because some controller just used `getStr()` + // to read the space PHID from the request. + // Just make this work like callers might reasonably expect so we + // don't need to handle this specially in every EditController. + return $this->getActor()->getDefaultSpacePHID(); } else { return $space_phid; } @@ -2002,14 +2005,15 @@ abstract class PhabricatorApplicationTransactionEditor $transaction_type) { $errors = array(); - $all_spaces = PhabricatorSpacesNamespaceQuery::getAllSpaces(); - $viewer_spaces = PhabricatorSpacesNamespaceQuery::getViewerSpaces( - $this->getActor()); + $actor = $this->getActor(); + + $has_spaces = PhabricatorSpacesNamespaceQuery::getViewerSpacesExist($actor); + $actor_spaces = PhabricatorSpacesNamespaceQuery::getViewerSpaces($actor); foreach ($xactions as $xaction) { $space_phid = $xaction->getNewValue(); if ($space_phid === null) { - if (!$all_spaces) { + if (!$has_spaces) { // The install doesn't have any spaces, so this is fine. continue; } @@ -2026,7 +2030,7 @@ abstract class PhabricatorApplicationTransactionEditor // If the PHID isn't `null`, it needs to be a valid space that the // viewer can see. - if (empty($viewer_spaces[$space_phid])) { + if (empty($actor_spaces[$space_phid])) { $errors[] = new PhabricatorApplicationTransactionValidationError( $transaction_type, pht('Invalid'), @@ -2045,7 +2049,18 @@ abstract class PhabricatorApplicationTransactionEditor PhabricatorLiskDAO $object, array $xactions) { - return clone $object; + $copy = clone $object; + + foreach ($xactions as $xaction) { + switch ($xaction->getTransactionType()) { + case PhabricatorTransactions::TYPE_SPACE: + $space_phid = $this->getTransactionNewValue($object, $xaction); + $copy->setSpacePHID($space_phid); + break; + } + } + + return $copy; } protected function validateAllTransactions( diff --git a/src/view/form/control/AphrontFormPolicyControl.php b/src/view/form/control/AphrontFormPolicyControl.php index 2997969c77..45bff0900e 100644 --- a/src/view/form/control/AphrontFormPolicyControl.php +++ b/src/view/form/control/AphrontFormPolicyControl.php @@ -5,6 +5,7 @@ final class AphrontFormPolicyControl extends AphrontFormControl { private $object; private $capability; private $policies; + private $spacePHID; public function setPolicyObject(PhabricatorPolicyInterface $object) { $this->object = $object; @@ -17,6 +18,15 @@ final class AphrontFormPolicyControl extends AphrontFormControl { return $this; } + public function setSpacePHID($space_phid) { + $this->spacePHID = $space_phid; + return $this; + } + + public function getSpacePHID() { + return $this->spacePHID; + } + public function setCapability($capability) { $this->capability = $capability; @@ -187,11 +197,14 @@ final class AphrontFormPolicyControl extends AphrontFormControl { $selected_icon = idx($selected, 'icon'); $selected_name = idx($selected, 'name'); + $spaces_control = $this->buildSpacesControl(); + return phutil_tag( 'div', array( ), array( + $spaces_control, javelin_tag( 'a', array( @@ -231,4 +244,48 @@ final class AphrontFormPolicyControl extends AphrontFormControl { return 'custom:placeholder'; } + private function buildSpacesControl() { + if ($this->capability != PhabricatorPolicyCapability::CAN_VIEW) { + return null; + } + + if (!($this->object instanceof PhabricatorSpacesInterface)) { + return null; + } + + $viewer = $this->getUser(); + if (!PhabricatorSpacesNamespaceQuery::getViewerSpacesExist($viewer)) { + return null; + } + + $space_phid = $this->getSpacePHID(); + if ($space_phid === null) { + $space_phid = $viewer->getDefaultSpacePHID(); + } + + $select = AphrontFormSelectControl::renderSelectTag( + $space_phid, + $this->getSpaceOptions(), + array( + 'name' => 'spacePHID', + )); + + return $select; + } + + protected function getSpaceOptions() { + $viewer = $this->getUser(); + $viewer_spaces = PhabricatorSpacesNamespaceQuery::getViewerSpaces($viewer); + + $map = array(); + foreach ($viewer_spaces as $space) { + $map[$space->getPHID()] = pht( + 'Space %s: %s', + $space->getMonogram(), + $space->getNamespaceName()); + } + asort($map); + + return $map; + } } From de0e0d995baa8c9b99e6bc3a68b2d0672a394614 Mon Sep 17 00:00:00 2001 From: epriestley Date: Wed, 10 Jun 2015 15:52:49 -0700 Subject: [PATCH 06/50] Support Spaces in Pholio Summary: Ref T8493. Add Spaces support to Pholio. This is straightforward; Pholio has no clone/copy/fork or weird parent/child stuff going on. Test Plan: Created a mock, put it in a space, looked at it as another user, searched for stuff in spaces, viewed Macros. Reviewers: btrahan Reviewed By: btrahan Subscribers: epriestley Maniphest Tasks: T8493 Differential Revision: https://secure.phabricator.com/D13231 --- .../autopatches/20150609.spaces.1.pholio.sql | 2 ++ src/__phutil_library_map__.php | 3 +-- .../query/PhabricatorMacroSearchEngine.php | 5 ++++- .../controller/PholioMockEditController.php | 5 +++++ .../pholio/query/PholioMockSearchEngine.php | 9 +++------ .../pholio/storage/PholioMock.php | 13 ++++++++++++- src/view/phui/PHUIPinboardItemView.php | 19 +++++++++++++++++-- 7 files changed, 44 insertions(+), 12 deletions(-) create mode 100644 resources/sql/autopatches/20150609.spaces.1.pholio.sql diff --git a/resources/sql/autopatches/20150609.spaces.1.pholio.sql b/resources/sql/autopatches/20150609.spaces.1.pholio.sql new file mode 100644 index 0000000000..903afb86da --- /dev/null +++ b/resources/sql/autopatches/20150609.spaces.1.pholio.sql @@ -0,0 +1,2 @@ +ALTER TABLE {$NAMESPACE}_pholio.pholio_mock + ADD spacePHID VARBINARY(64); diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 674efa30b1..eaa7e4fa04 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -2580,7 +2580,6 @@ phutil_register_library_map(array( 'PhabricatorSpacesCapabilityCreateSpaces' => 'applications/spaces/capability/PhabricatorSpacesCapabilityCreateSpaces.php', 'PhabricatorSpacesCapabilityDefaultEdit' => 'applications/spaces/capability/PhabricatorSpacesCapabilityDefaultEdit.php', 'PhabricatorSpacesCapabilityDefaultView' => 'applications/spaces/capability/PhabricatorSpacesCapabilityDefaultView.php', - 'PhabricatorSpacesControl' => 'applications/spaces/view/PhabricatorSpacesControl.php', 'PhabricatorSpacesController' => 'applications/spaces/controller/PhabricatorSpacesController.php', 'PhabricatorSpacesDAO' => 'applications/spaces/storage/PhabricatorSpacesDAO.php', 'PhabricatorSpacesEditController' => 'applications/spaces/controller/PhabricatorSpacesEditController.php', @@ -6091,7 +6090,6 @@ phutil_register_library_map(array( 'PhabricatorSpacesCapabilityCreateSpaces' => 'PhabricatorPolicyCapability', 'PhabricatorSpacesCapabilityDefaultEdit' => 'PhabricatorPolicyCapability', 'PhabricatorSpacesCapabilityDefaultView' => 'PhabricatorPolicyCapability', - 'PhabricatorSpacesControl' => 'AphrontFormControl', 'PhabricatorSpacesController' => 'PhabricatorController', 'PhabricatorSpacesDAO' => 'PhabricatorLiskDAO', 'PhabricatorSpacesEditController' => 'PhabricatorSpacesController', @@ -6418,6 +6416,7 @@ phutil_register_library_map(array( 'PhabricatorApplicationTransactionInterface', 'PhabricatorProjectInterface', 'PhabricatorDestructibleInterface', + 'PhabricatorSpacesInterface', ), 'PholioMockCommentController' => 'PholioController', 'PholioMockEditController' => 'PholioController', diff --git a/src/applications/macro/query/PhabricatorMacroSearchEngine.php b/src/applications/macro/query/PhabricatorMacroSearchEngine.php index 5c69716bbf..9caf1e2f34 100644 --- a/src/applications/macro/query/PhabricatorMacroSearchEngine.php +++ b/src/applications/macro/query/PhabricatorMacroSearchEngine.php @@ -141,7 +141,10 @@ final class PhabricatorMacroSearchEngine foreach ($macros as $macro) { $file = $macro->getFile(); - $item = new PHUIPinboardItemView(); + $item = id(new PHUIPinboardItemView()) + ->setUser($viewer) + ->setObject($macro); + if ($file) { $item->setImageURI($file->getURIForTransform($xform)); list($x, $y) = $xform->getTransformedDimensions($file); diff --git a/src/applications/pholio/controller/PholioMockEditController.php b/src/applications/pholio/controller/PholioMockEditController.php index 3ed2cc0779..728c7b29d6 100644 --- a/src/applications/pholio/controller/PholioMockEditController.php +++ b/src/applications/pholio/controller/PholioMockEditController.php @@ -65,6 +65,7 @@ final class PholioMockEditController extends PholioController { $v_edit = $mock->getEditPolicy(); $v_cc = PhabricatorSubscribersQuery::loadSubscribersForPHID( $mock->getPHID()); + $v_space = $mock->getSpacePHID(); if ($request->isFormPost()) { $xactions = array(); @@ -75,6 +76,7 @@ final class PholioMockEditController extends PholioController { $type_view = PhabricatorTransactions::TYPE_VIEW_POLICY; $type_edit = PhabricatorTransactions::TYPE_EDIT_POLICY; $type_cc = PhabricatorTransactions::TYPE_SUBSCRIBERS; + $type_space = PhabricatorTransactions::TYPE_SPACE; $v_name = $request->getStr('name'); $v_desc = $request->getStr('description'); @@ -83,6 +85,7 @@ final class PholioMockEditController extends PholioController { $v_edit = $request->getStr('can_edit'); $v_cc = $request->getArr('cc'); $v_projects = $request->getArr('projects'); + $v_space = $request->getStr('spacePHID'); $mock_xactions = array(); $mock_xactions[$type_name] = $v_name; @@ -91,6 +94,7 @@ final class PholioMockEditController extends PholioController { $mock_xactions[$type_view] = $v_view; $mock_xactions[$type_edit] = $v_edit; $mock_xactions[$type_cc] = array('=' => $v_cc); + $mock_xactions[$type_space] = $v_space; if (!strlen($request->getStr('name'))) { $e_name = pht('Required'); @@ -350,6 +354,7 @@ final class PholioMockEditController extends PholioController { ->setCapability(PhabricatorPolicyCapability::CAN_VIEW) ->setPolicyObject($mock) ->setPolicies($policies) + ->setSpacePHID($v_space) ->setName('can_view')) ->appendChild( id(new AphrontFormPolicyControl()) diff --git a/src/applications/pholio/query/PholioMockSearchEngine.php b/src/applications/pholio/query/PholioMockSearchEngine.php index 26b22034a7..23c1decad5 100644 --- a/src/applications/pholio/query/PholioMockSearchEngine.php +++ b/src/applications/pholio/query/PholioMockSearchEngine.php @@ -83,12 +83,6 @@ final class PholioMockSearchEngine extends PhabricatorApplicationSearchEngine { return parent::buildSavedQueryFromBuiltin($query_key); } - protected function getRequiredHandlePHIDsForResultList( - array $mocks, - PhabricatorSavedQuery $query) { - return mpull($mocks, 'getAuthorPHID'); - } - protected function renderResultList( array $mocks, PhabricatorSavedQuery $query, @@ -96,6 +90,7 @@ final class PholioMockSearchEngine extends PhabricatorApplicationSearchEngine { assert_instances_of($mocks, 'PholioMock'); $viewer = $this->requireViewer(); + $handles = $viewer->loadHandles(mpull($mocks, 'getAuthorPHID')); $xform = PhabricatorFileTransform::getTransformByKey( PhabricatorFileThumbnailTransform::TRANSFORM_PINBOARD); @@ -109,7 +104,9 @@ final class PholioMockSearchEngine extends PhabricatorApplicationSearchEngine { $header = 'M'.$mock->getID().' '.$mock->getName(); $item = id(new PHUIPinboardItemView()) + ->setUser($viewer) ->setHeader($header) + ->setObject($mock) ->setURI('/M'.$mock->getID()) ->setImageURI($image_uri) ->setImageSize($x, $y) diff --git a/src/applications/pholio/storage/PholioMock.php b/src/applications/pholio/storage/PholioMock.php index d229aa8020..aaebed878e 100644 --- a/src/applications/pholio/storage/PholioMock.php +++ b/src/applications/pholio/storage/PholioMock.php @@ -9,7 +9,8 @@ final class PholioMock extends PholioDAO PhabricatorFlaggableInterface, PhabricatorApplicationTransactionInterface, PhabricatorProjectInterface, - PhabricatorDestructibleInterface { + PhabricatorDestructibleInterface, + PhabricatorSpacesInterface { const MARKUP_FIELD_DESCRIPTION = 'markup:description'; @@ -26,6 +27,7 @@ final class PholioMock extends PholioDAO protected $coverPHID; protected $mailKey; protected $status; + protected $spacePHID; private $images = self::ATTACHABLE; private $allImages = self::ATTACHABLE; @@ -308,4 +310,13 @@ final class PholioMock extends PholioDAO $this->saveTransaction(); } + +/* -( PhabricatorSpacesInterface )----------------------------------------- */ + + + public function getSpacePHID() { + return $this->spacePHID; + } + + } diff --git a/src/view/phui/PHUIPinboardItemView.php b/src/view/phui/PHUIPinboardItemView.php index db03b81def..5bde2aae6e 100644 --- a/src/view/phui/PHUIPinboardItemView.php +++ b/src/view/phui/PHUIPinboardItemView.php @@ -7,7 +7,7 @@ final class PHUIPinboardItemView extends AphrontView { private $header; private $iconBlock = array(); private $disabled; - + private $object; private $imageWidth; private $imageHeight; @@ -42,6 +42,11 @@ final class PHUIPinboardItemView extends AphrontView { return $this; } + public function setObject($object) { + $this->object = $object; + return $this; + } + public function render() { require_celerity_resource('phui-pinboard-view-css'); $header = null; @@ -57,7 +62,17 @@ final class PHUIPinboardItemView extends AphrontView { 'class' => 'phui-pinboard-item-header '. 'sprite-gradient '.$header_color, ), - phutil_tag('a', array('href' => $this->uri), $this->header)); + array( + id(new PHUISpacesNamespaceContextView()) + ->setUser($this->getUser()) + ->setObject($this->object), + phutil_tag( + 'a', + array( + 'href' => $this->uri, + ), + $this->header), + )); } $image = null; From d118800d37943e02b2275f647a046ea4fb1e3164 Mon Sep 17 00:00:00 2001 From: epriestley Date: Wed, 10 Jun 2015 15:53:04 -0700 Subject: [PATCH 07/50] Support Spaces in Maniphest Summary: Ref T8493. Tricks: - "Create Similar Task" and "Create Subtask" should copy the parent's Space. - Normal list view + workboard card view. Test Plan: - Created a task, edited space, etc. - Viewed tasks with different users. - Created a "Similar Task" (saw proper Space). - Created a subtask (saw proper Space). - Viewed workboard. Reviewers: btrahan Reviewed By: btrahan Subscribers: epriestley Maniphest Tasks: T8493 Differential Revision: https://secure.phabricator.com/D13232 --- .../sql/autopatches/20150609.spaces.2.maniphest.sql | 2 ++ src/__phutil_library_map__.php | 1 + .../controller/ManiphestTaskEditController.php | 7 +++++++ src/applications/maniphest/storage/ManiphestTask.php | 12 +++++++++++- .../maniphest/view/ManiphestTaskListView.php | 10 ++++++---- .../project/view/ProjectBoardTaskCard.php | 2 ++ 6 files changed, 29 insertions(+), 5 deletions(-) create mode 100644 resources/sql/autopatches/20150609.spaces.2.maniphest.sql diff --git a/resources/sql/autopatches/20150609.spaces.2.maniphest.sql b/resources/sql/autopatches/20150609.spaces.2.maniphest.sql new file mode 100644 index 0000000000..d46b5e5908 --- /dev/null +++ b/resources/sql/autopatches/20150609.spaces.2.maniphest.sql @@ -0,0 +1,2 @@ +ALTER TABLE {$NAMESPACE}_maniphest.maniphest_task + ADD spacePHID VARBINARY(64); diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index eaa7e4fa04..c389400972 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -4405,6 +4405,7 @@ phutil_register_library_map(array( 'PhabricatorDestructibleInterface', 'PhabricatorApplicationTransactionInterface', 'PhabricatorProjectInterface', + 'PhabricatorSpacesInterface', ), 'ManiphestTaskClosedStatusDatasource' => 'PhabricatorTypeaheadDatasource', 'ManiphestTaskDependedOnByTaskEdgeType' => 'PhabricatorEdgeType', diff --git a/src/applications/maniphest/controller/ManiphestTaskEditController.php b/src/applications/maniphest/controller/ManiphestTaskEditController.php index d9a4e44381..72b75c876f 100644 --- a/src/applications/maniphest/controller/ManiphestTaskEditController.php +++ b/src/applications/maniphest/controller/ManiphestTaskEditController.php @@ -155,12 +155,15 @@ final class ManiphestTaskEditController extends ManiphestController { $aux_fields = $field_list->getFields(); + $v_space = $task->getSpacePHID(); + if ($request->isFormPost()) { $changes = array(); $new_title = $request->getStr('title'); $new_desc = $request->getStr('description'); $new_status = $request->getStr('status'); + $v_space = $request->getStr('spacePHID'); if (!$task->getID()) { $workflow = 'create'; @@ -268,6 +271,7 @@ final class ManiphestTaskEditController extends ManiphestController { } if ($can_edit_policies) { + $changes[PhabricatorTransactions::TYPE_SPACE] = $v_space; $changes[PhabricatorTransactions::TYPE_VIEW_POLICY] = $request->getStr('viewPolicy'); $changes[PhabricatorTransactions::TYPE_EDIT_POLICY] = @@ -477,6 +481,8 @@ final class ManiphestTaskEditController extends ManiphestController { $task->setViewPolicy($template_task->getViewPolicy()); $task->setEditPolicy($template_task->getEditPolicy()); + $v_space = $template_task->getSpacePHID(); + $template_fields = PhabricatorCustomField::getObjectFields( $template_task, PhabricatorCustomField::ROLE_EDIT); @@ -643,6 +649,7 @@ final class ManiphestTaskEditController extends ManiphestController { ->setCapability(PhabricatorPolicyCapability::CAN_VIEW) ->setPolicyObject($task) ->setPolicies($policies) + ->setSpacePHID($v_space) ->setName('viewPolicy')) ->appendChild( id(new AphrontFormPolicyControl()) diff --git a/src/applications/maniphest/storage/ManiphestTask.php b/src/applications/maniphest/storage/ManiphestTask.php index cdf4b4a575..f244a1c918 100644 --- a/src/applications/maniphest/storage/ManiphestTask.php +++ b/src/applications/maniphest/storage/ManiphestTask.php @@ -12,7 +12,8 @@ final class ManiphestTask extends ManiphestDAO PhabricatorCustomFieldInterface, PhabricatorDestructibleInterface, PhabricatorApplicationTransactionInterface, - PhabricatorProjectInterface { + PhabricatorProjectInterface, + PhabricatorSpacesInterface { const MARKUP_FIELD_DESCRIPTION = 'markup:desc'; @@ -35,6 +36,7 @@ final class ManiphestTask extends ManiphestDAO protected $projectPHIDs = array(); protected $ownerOrdering; + protected $spacePHID; private $subscriberPHIDs = self::ATTACHABLE; private $groupByProjectPHID = self::ATTACHABLE; @@ -379,4 +381,12 @@ final class ManiphestTask extends ManiphestDAO return $timeline; } + +/* -( PhabricatorSpacesInterface )----------------------------------------- */ + + + public function getSpacePHID() { + return $this->spacePHID; + } + } diff --git a/src/applications/maniphest/view/ManiphestTaskListView.php b/src/applications/maniphest/view/ManiphestTaskListView.php index 0dca204391..05adced87a 100644 --- a/src/applications/maniphest/view/ManiphestTaskListView.php +++ b/src/applications/maniphest/view/ManiphestTaskListView.php @@ -57,10 +57,12 @@ final class ManiphestTaskListView extends ManiphestView { } foreach ($this->tasks as $task) { - $item = new PHUIObjectItemView(); - $item->setObjectName('T'.$task->getID()); - $item->setHeader($task->getTitle()); - $item->setHref('/T'.$task->getID()); + $item = id(new PHUIObjectItemView()) + ->setUser($this->getUser()) + ->setObject($task) + ->setObjectName('T'.$task->getID()) + ->setHeader($task->getTitle()) + ->setHref('/T'.$task->getID()); if ($task->getOwnerPHID()) { $owner = $handles[$task->getOwnerPHID()]; diff --git a/src/applications/project/view/ProjectBoardTaskCard.php b/src/applications/project/view/ProjectBoardTaskCard.php index a601608ebf..0f4f14694c 100644 --- a/src/applications/project/view/ProjectBoardTaskCard.php +++ b/src/applications/project/view/ProjectBoardTaskCard.php @@ -49,6 +49,8 @@ final class ProjectBoardTaskCard { $bar_color = idx($color_map, $task->getPriority(), 'grey'); $card = id(new PHUIObjectItemView()) + ->setObject($task) + ->setUser($this->getViewer()) ->setObjectName('T'.$task->getID()) ->setHeader($task->getTitle()) ->setGrippable($can_edit) From 814b586f5d3d232d741ddb02256ca6eedfa9a7fc Mon Sep 17 00:00:00 2001 From: epriestley Date: Wed, 10 Jun 2015 15:53:51 -0700 Subject: [PATCH 08/50] Add a "Description" field to Spaces Summary: Ref T8377. - Add a description field. - Add edges so files can be attached. Test Plan: {F492410} Reviewers: btrahan Reviewed By: btrahan Subscribers: epriestley Maniphest Tasks: T8377 Differential Revision: https://secure.phabricator.com/D13235 --- .../autopatches/20150610.spaces.1.desc.sql | 2 + .../autopatches/20150610.spaces.2.edge.sql | 16 ++++++++ src/__phutil_library_map__.php | 2 + .../PhabricatorSpacesEditController.php | 12 ++++++ .../PhabricatorSpacesViewController.php | 14 +++++++ .../PhabricatorSpacesNamespaceEditor.php | 11 ++++++ .../PhabricatorSpacesNamespacePHIDType.php | 7 +++- .../storage/PhabricatorSpacesNamespace.php | 5 ++- .../PhabricatorSpacesNamespaceTransaction.php | 37 +++++++++++++++++++ .../storage/PhabricatorSpacesSchemaSpec.php | 10 +++++ 10 files changed, 113 insertions(+), 3 deletions(-) create mode 100644 resources/sql/autopatches/20150610.spaces.1.desc.sql create mode 100644 resources/sql/autopatches/20150610.spaces.2.edge.sql create mode 100644 src/applications/spaces/storage/PhabricatorSpacesSchemaSpec.php diff --git a/resources/sql/autopatches/20150610.spaces.1.desc.sql b/resources/sql/autopatches/20150610.spaces.1.desc.sql new file mode 100644 index 0000000000..c62cd8aece --- /dev/null +++ b/resources/sql/autopatches/20150610.spaces.1.desc.sql @@ -0,0 +1,2 @@ +ALTER TABLE {$NAMESPACE}_spaces.spaces_namespace + ADD description LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL; diff --git a/resources/sql/autopatches/20150610.spaces.2.edge.sql b/resources/sql/autopatches/20150610.spaces.2.edge.sql new file mode 100644 index 0000000000..bc72ed2225 --- /dev/null +++ b/resources/sql/autopatches/20150610.spaces.2.edge.sql @@ -0,0 +1,16 @@ +CREATE TABLE {$NAMESPACE}_spaces.edge ( + src VARBINARY(64) NOT NULL, + type INT UNSIGNED NOT NULL, + dst VARBINARY(64) NOT NULL, + dateCreated INT UNSIGNED NOT NULL, + seq INT UNSIGNED NOT NULL, + dataID INT UNSIGNED, + PRIMARY KEY (src, type, dst), + KEY `src` (src, type, dateCreated, seq), + UNIQUE KEY `key_dst` (dst, type, src) +) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT}; + +CREATE TABLE {$NAMESPACE}_spaces.edgedata ( + id INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, + data LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT} +) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT}; diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index c389400972..e3ba379280 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -2594,6 +2594,7 @@ phutil_register_library_map(array( 'PhabricatorSpacesNamespaceTransaction' => 'applications/spaces/storage/PhabricatorSpacesNamespaceTransaction.php', 'PhabricatorSpacesNamespaceTransactionQuery' => 'applications/spaces/query/PhabricatorSpacesNamespaceTransactionQuery.php', 'PhabricatorSpacesRemarkupRule' => 'applications/spaces/remarkup/PhabricatorSpacesRemarkupRule.php', + 'PhabricatorSpacesSchemaSpec' => 'applications/spaces/storage/PhabricatorSpacesSchemaSpec.php', 'PhabricatorSpacesTestCase' => 'applications/spaces/__tests__/PhabricatorSpacesTestCase.php', 'PhabricatorSpacesViewController' => 'applications/spaces/controller/PhabricatorSpacesViewController.php', 'PhabricatorStandardCustomField' => 'infrastructure/customfield/standard/PhabricatorStandardCustomField.php', @@ -6110,6 +6111,7 @@ phutil_register_library_map(array( 'PhabricatorSpacesNamespaceTransaction' => 'PhabricatorApplicationTransaction', 'PhabricatorSpacesNamespaceTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhabricatorSpacesRemarkupRule' => 'PhabricatorObjectRemarkupRule', + 'PhabricatorSpacesSchemaSpec' => 'PhabricatorConfigSchemaSpec', 'PhabricatorSpacesTestCase' => 'PhabricatorTestCase', 'PhabricatorSpacesViewController' => 'PhabricatorSpacesController', 'PhabricatorStandardCustomField' => 'PhabricatorCustomField', diff --git a/src/applications/spaces/controller/PhabricatorSpacesEditController.php b/src/applications/spaces/controller/PhabricatorSpacesEditController.php index b64a16ab97..4dfeeed7ed 100644 --- a/src/applications/spaces/controller/PhabricatorSpacesEditController.php +++ b/src/applications/spaces/controller/PhabricatorSpacesEditController.php @@ -54,6 +54,7 @@ final class PhabricatorSpacesEditController $validation_exception = null; $e_name = true; $v_name = $space->getNamespaceName(); + $v_desc = $space->getDescription(); $v_view = $space->getViewPolicy(); $v_edit = $space->getEditPolicy(); @@ -62,10 +63,12 @@ final class PhabricatorSpacesEditController $e_name = null; $v_name = $request->getStr('name'); + $v_desc = $request->getStr('description'); $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_view = PhabricatorTransactions::TYPE_VIEW_POLICY; $type_edit = PhabricatorTransactions::TYPE_EDIT_POLICY; @@ -74,6 +77,10 @@ final class PhabricatorSpacesEditController ->setTransactionType($type_name) ->setNewValue($v_name); + $xactions[] = id(new PhabricatorSpacesNamespaceTransaction()) + ->setTransactionType($type_desc) + ->setNewValue($v_desc); + $xactions[] = id(new PhabricatorSpacesNamespaceTransaction()) ->setTransactionType($type_view) ->setNewValue($v_view); @@ -128,6 +135,11 @@ final class PhabricatorSpacesEditController ->setName('name') ->setValue($v_name) ->setError($e_name)) + ->appendControl( + id(new PhabricatorRemarkupControl()) + ->setLabel(pht('Description')) + ->setName('description') + ->setValue($v_desc)) ->appendChild( id(new AphrontFormPolicyControl()) ->setUser($viewer) diff --git a/src/applications/spaces/controller/PhabricatorSpacesViewController.php b/src/applications/spaces/controller/PhabricatorSpacesViewController.php index 911549234f..46e82627ec 100644 --- a/src/applications/spaces/controller/PhabricatorSpacesViewController.php +++ b/src/applications/spaces/controller/PhabricatorSpacesViewController.php @@ -75,6 +75,20 @@ final class PhabricatorSpacesViewController pht('Editable By'), $descriptions[PhabricatorPolicyCapability::CAN_EDIT]); + $description = $space->getDescription(); + if (strlen($description)) { + $description = PhabricatorMarkupEngine::renderOneObject( + id(new PhabricatorMarkupOneOff())->setContent($description), + 'default', + $viewer); + + $list->addSectionHeader( + pht('Description'), + PHUIPropertyListView::ICON_SUMMARY); + + $list->addTextContent($description); + } + return $list; } diff --git a/src/applications/spaces/editor/PhabricatorSpacesNamespaceEditor.php b/src/applications/spaces/editor/PhabricatorSpacesNamespaceEditor.php index 23b01531e9..3b6c7bb6e6 100644 --- a/src/applications/spaces/editor/PhabricatorSpacesNamespaceEditor.php +++ b/src/applications/spaces/editor/PhabricatorSpacesNamespaceEditor.php @@ -15,6 +15,7 @@ final class PhabricatorSpacesNamespaceEditor $types = parent::getTransactionTypes(); $types[] = PhabricatorSpacesNamespaceTransaction::TYPE_NAME; + $types[] = PhabricatorSpacesNamespaceTransaction::TYPE_DESCRIPTION; $types[] = PhabricatorSpacesNamespaceTransaction::TYPE_DEFAULT; $types[] = PhabricatorTransactions::TYPE_VIEW_POLICY; @@ -34,6 +35,11 @@ final class PhabricatorSpacesNamespaceEditor return null; } return $name; + case PhabricatorSpacesNamespaceTransaction::TYPE_DESCRIPTION: + if ($this->getIsNewObject()) { + return null; + } + return $object->getDescription(); case PhabricatorSpacesNamespaceTransaction::TYPE_DEFAULT: return $object->getIsDefaultNamespace() ? 1 : null; case PhabricatorTransactions::TYPE_VIEW_POLICY: @@ -51,6 +57,7 @@ final class PhabricatorSpacesNamespaceEditor switch ($xaction->getTransactionType()) { case PhabricatorSpacesNamespaceTransaction::TYPE_NAME: + case PhabricatorSpacesNamespaceTransaction::TYPE_DESCRIPTION: case PhabricatorTransactions::TYPE_VIEW_POLICY: case PhabricatorTransactions::TYPE_EDIT_POLICY: return $xaction->getNewValue(); @@ -71,6 +78,9 @@ final class PhabricatorSpacesNamespaceEditor 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; @@ -91,6 +101,7 @@ final class PhabricatorSpacesNamespaceEditor switch ($xaction->getTransactionType()) { case PhabricatorSpacesNamespaceTransaction::TYPE_NAME: + case PhabricatorSpacesNamespaceTransaction::TYPE_DESCRIPTION: case PhabricatorSpacesNamespaceTransaction::TYPE_DEFAULT: case PhabricatorTransactions::TYPE_VIEW_POLICY: case PhabricatorTransactions::TYPE_EDIT_POLICY: diff --git a/src/applications/spaces/phid/PhabricatorSpacesNamespacePHIDType.php b/src/applications/spaces/phid/PhabricatorSpacesNamespacePHIDType.php index 22dfcffac4..710972e8f4 100644 --- a/src/applications/spaces/phid/PhabricatorSpacesNamespacePHIDType.php +++ b/src/applications/spaces/phid/PhabricatorSpacesNamespacePHIDType.php @@ -32,9 +32,12 @@ final class PhabricatorSpacesNamespacePHIDType foreach ($handles as $phid => $handle) { $namespace = $objects[$phid]; - $monogram = $namespace->getMonogram(); - $handle->setName($namespace->getNamespaceName()); + $monogram = $namespace->getMonogram(); + $name = $namespace->getNamespaceName(); + + $handle->setName($name); + $handle->setFullName(pht('%s %s', $monogram, $name)); $handle->setURI('/'.$monogram); } } diff --git a/src/applications/spaces/storage/PhabricatorSpacesNamespace.php b/src/applications/spaces/storage/PhabricatorSpacesNamespace.php index 8271f536cb..5b1098b1f8 100644 --- a/src/applications/spaces/storage/PhabricatorSpacesNamespace.php +++ b/src/applications/spaces/storage/PhabricatorSpacesNamespace.php @@ -11,6 +11,7 @@ final class PhabricatorSpacesNamespace protected $viewPolicy; protected $editPolicy; protected $isDefaultNamespace; + protected $description; public static function initializeNewNamespace(PhabricatorUser $actor) { $app = id(new PhabricatorApplicationQuery()) @@ -26,7 +27,8 @@ final class PhabricatorSpacesNamespace return id(new PhabricatorSpacesNamespace()) ->setIsDefaultNamespace(null) ->setViewPolicy($view_policy) - ->setEditPolicy($edit_policy); + ->setEditPolicy($edit_policy) + ->setDescription(''); } protected function getConfiguration() { @@ -35,6 +37,7 @@ final class PhabricatorSpacesNamespace self::CONFIG_COLUMN_SCHEMA => array( 'namespaceName' => 'text255', 'isDefaultNamespace' => 'bool?', + 'description' => 'text', ), self::CONFIG_KEY_SCHEMA => array( 'key_default' => array( diff --git a/src/applications/spaces/storage/PhabricatorSpacesNamespaceTransaction.php b/src/applications/spaces/storage/PhabricatorSpacesNamespaceTransaction.php index 672cb9d8ad..ef7d8f210f 100644 --- a/src/applications/spaces/storage/PhabricatorSpacesNamespaceTransaction.php +++ b/src/applications/spaces/storage/PhabricatorSpacesNamespaceTransaction.php @@ -5,6 +5,7 @@ final class PhabricatorSpacesNamespaceTransaction const TYPE_NAME = 'spaces:name'; const TYPE_DEFAULT = 'spaces:default'; + const TYPE_DESCRIPTION = 'spaces:description'; public function getApplicationName() { return 'spaces'; @@ -18,6 +19,38 @@ final class PhabricatorSpacesNamespaceTransaction return null; } + public function shouldHide() { + $old = $this->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(); @@ -37,6 +70,10 @@ final class PhabricatorSpacesNamespaceTransaction $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.', diff --git a/src/applications/spaces/storage/PhabricatorSpacesSchemaSpec.php b/src/applications/spaces/storage/PhabricatorSpacesSchemaSpec.php new file mode 100644 index 0000000000..d69772ef7c --- /dev/null +++ b/src/applications/spaces/storage/PhabricatorSpacesSchemaSpec.php @@ -0,0 +1,10 @@ +buildEdgeSchemata(new PhabricatorSpacesNamespace()); + } + +} From a06618f879664afbe4154ac73d08a5d6204cd385 Mon Sep 17 00:00:00 2001 From: epriestley Date: Thu, 11 Jun 2015 05:53:29 -0700 Subject: [PATCH 09/50] Fix an issue where "Send an email to..." rules might be discarded Summary: Fixes T8464. We could lose the additional users from "Send an email..." rules //if// Herald did not apply any other transactions to the task. Test Plan: - Destroyed all Herald rules. - Created a single "Send an email to..." rule. - Created a task. - Saw target get an email. Reviewers: btrahan, chad Reviewed By: chad Subscribers: epriestley Maniphest Tasks: T8464 Differential Revision: https://secure.phabricator.com/D13245 --- .../editor/PhabricatorApplicationTransactionEditor.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php b/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php index 9602ee6227..b4d36b5513 100644 --- a/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php +++ b/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php @@ -936,14 +936,16 @@ abstract class PhabricatorApplicationTransactionEditor $object, $herald_xactions); - $adapter = $this->getHeraldAdapter(); - $this->heraldEmailPHIDs = $adapter->getEmailPHIDs(); - $this->heraldForcedEmailPHIDs = $adapter->getForcedEmailPHIDs(); - // Merge the new transactions into the transaction list: we want to // send email and publish feed stories about them, too. $xactions = array_merge($xactions, $herald_xactions); } + + // If Herald did not generate transactions, we may still need to handle + // "Send an Email" rules. + $adapter = $this->getHeraldAdapter(); + $this->heraldEmailPHIDs = $adapter->getEmailPHIDs(); + $this->heraldForcedEmailPHIDs = $adapter->getForcedEmailPHIDs(); } $this->didApplyTransactions($xactions); From 88e7cd158f285578fa56378c3b09150f0092d98a Mon Sep 17 00:00:00 2001 From: epriestley Date: Thu, 11 Jun 2015 10:13:47 -0700 Subject: [PATCH 10/50] Allow Spaces to be archived Summary: Ref T8377. This adds a standard disable/enable feature to Spaces, with a couple of twists: - You can't create new stuff in an archived space, and you can't move stuff into an archived space. - We don't show results from an archived space by default in ApplicationSearch queries. You can still find these objects if you explicitly search for "Spaces: ". So this is a "put it in a box in the attic" sort of operation, but that seems fairly nice/reasonable. Test Plan: - Archived and activated spaces. - Used ApplicationSearch, which omitted archived objects by default but allowed searches for them, specifically, to succeed. - Tried to create objects into an archived space (this is not allowed). - Edited objects in an archived space (this is OK). Reviewers: btrahan Reviewed By: btrahan Subscribers: epriestley Maniphest Tasks: T8377 Differential Revision: https://secure.phabricator.com/D13238 --- .../autopatches/20150610.spaces.3.archive.sql | 2 + src/__phutil_library_map__.php | 2 + .../people/storage/PhabricatorUser.php | 2 +- .../PhabricatorApplicationSearchEngine.php | 4 + .../PhabricatorSpacesApplication.php | 11 +++ .../PhabricatorSpacesArchiveController.php | 76 +++++++++++++++++++ .../PhabricatorSpacesViewController.php | 26 +++++++ .../PhabricatorSpacesNamespaceEditor.php | 25 +++++- .../PhabricatorSpacesNamespacePHIDType.php | 4 + .../query/PhabricatorSpacesNamespaceQuery.php | 56 +++++++++----- ...PhabricatorSpacesNamespaceSearchEngine.php | 38 +++++++--- .../storage/PhabricatorSpacesNamespace.php | 5 +- .../PhabricatorSpacesNamespaceTransaction.php | 11 +++ .../PhabricatorSpacesNamespaceDatasource.php | 15 +++- ...habricatorApplicationTransactionEditor.php | 20 +++++ src/docs/user/userguide/spaces.diviner | 27 +++++++ ...PhabricatorCursorPagedPolicyAwareQuery.php | 11 +++ .../form/control/AphrontFormPolicyControl.php | 12 ++- 18 files changed, 309 insertions(+), 38 deletions(-) create mode 100644 resources/sql/autopatches/20150610.spaces.3.archive.sql create mode 100644 src/applications/spaces/controller/PhabricatorSpacesArchiveController.php create mode 100644 src/docs/user/userguide/spaces.diviner diff --git a/resources/sql/autopatches/20150610.spaces.3.archive.sql b/resources/sql/autopatches/20150610.spaces.3.archive.sql new file mode 100644 index 0000000000..8dd55959a3 --- /dev/null +++ b/resources/sql/autopatches/20150610.spaces.3.archive.sql @@ -0,0 +1,2 @@ +ALTER TABLE {$NAMESPACE}_spaces.spaces_namespace + ADD isArchived BOOL NOT NULL; diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index e3ba379280..079819f657 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -2577,6 +2577,7 @@ phutil_register_library_map(array( 'PhabricatorSortTableUIExample' => 'applications/uiexample/examples/PhabricatorSortTableUIExample.php', 'PhabricatorSourceCodeView' => 'view/layout/PhabricatorSourceCodeView.php', 'PhabricatorSpacesApplication' => 'applications/spaces/application/PhabricatorSpacesApplication.php', + 'PhabricatorSpacesArchiveController' => 'applications/spaces/controller/PhabricatorSpacesArchiveController.php', 'PhabricatorSpacesCapabilityCreateSpaces' => 'applications/spaces/capability/PhabricatorSpacesCapabilityCreateSpaces.php', 'PhabricatorSpacesCapabilityDefaultEdit' => 'applications/spaces/capability/PhabricatorSpacesCapabilityDefaultEdit.php', 'PhabricatorSpacesCapabilityDefaultView' => 'applications/spaces/capability/PhabricatorSpacesCapabilityDefaultView.php', @@ -6089,6 +6090,7 @@ phutil_register_library_map(array( 'PhabricatorSortTableUIExample' => 'PhabricatorUIExample', 'PhabricatorSourceCodeView' => 'AphrontView', 'PhabricatorSpacesApplication' => 'PhabricatorApplication', + 'PhabricatorSpacesArchiveController' => 'PhabricatorSpacesController', 'PhabricatorSpacesCapabilityCreateSpaces' => 'PhabricatorPolicyCapability', 'PhabricatorSpacesCapabilityDefaultEdit' => 'PhabricatorPolicyCapability', 'PhabricatorSpacesCapabilityDefaultView' => 'PhabricatorPolicyCapability', diff --git a/src/applications/people/storage/PhabricatorUser.php b/src/applications/people/storage/PhabricatorUser.php index aa93485dd2..55ade255a7 100644 --- a/src/applications/people/storage/PhabricatorUser.php +++ b/src/applications/people/storage/PhabricatorUser.php @@ -759,7 +759,7 @@ final class PhabricatorUser // for now just use the global space if one exists. // If the viewer has access to the default space, use that. - $spaces = PhabricatorSpacesNamespaceQuery::getViewerSpaces($this); + $spaces = PhabricatorSpacesNamespaceQuery::getViewerActiveSpaces($this); foreach ($spaces as $space) { if ($space->getIsDefaultNamespace()) { return $space->getPHID(); diff --git a/src/applications/search/engine/PhabricatorApplicationSearchEngine.php b/src/applications/search/engine/PhabricatorApplicationSearchEngine.php index 5d0f79e170..453b965034 100644 --- a/src/applications/search/engine/PhabricatorApplicationSearchEngine.php +++ b/src/applications/search/engine/PhabricatorApplicationSearchEngine.php @@ -149,6 +149,10 @@ abstract class PhabricatorApplicationSearchEngine extends Phobject { if ($object instanceof PhabricatorSpacesInterface) { if (!empty($map['spacePHIDs'])) { $query->withSpacePHIDs($map['spacePHIDs']); + } else { + // If the user doesn't search for objects in specific spaces, we + // default to "all active spaces you have permission to view". + $query->withSpaceIsArchived(false); } } diff --git a/src/applications/spaces/application/PhabricatorSpacesApplication.php b/src/applications/spaces/application/PhabricatorSpacesApplication.php index 380f80569e..0e25120626 100644 --- a/src/applications/spaces/application/PhabricatorSpacesApplication.php +++ b/src/applications/spaces/application/PhabricatorSpacesApplication.php @@ -38,6 +38,15 @@ final class PhabricatorSpacesApplication extends PhabricatorApplication { return true; } + public function getHelpDocumentationArticles(PhabricatorUser $viewer) { + return array( + array( + 'name' => pht('Spaces User Guide'), + 'href' => PhabricatorEnv::getDoclink('Spaces User Guide'), + ), + ); + } + public function getRemarkupRules() { return array( new PhabricatorSpacesRemarkupRule(), @@ -51,6 +60,8 @@ final class PhabricatorSpacesApplication extends PhabricatorApplication { '(?:query/(?P[^/]+)/)?' => 'PhabricatorSpacesListController', 'create/' => 'PhabricatorSpacesEditController', 'edit/(?:(?P\d+)/)?' => 'PhabricatorSpacesEditController', + '(?Pactivate|archive)/(?P\d+)/' + => 'PhabricatorSpacesArchiveController', ), ); } diff --git a/src/applications/spaces/controller/PhabricatorSpacesArchiveController.php b/src/applications/spaces/controller/PhabricatorSpacesArchiveController.php new file mode 100644 index 0000000000..82cf19e9e8 --- /dev/null +++ b/src/applications/spaces/controller/PhabricatorSpacesArchiveController.php @@ -0,0 +1,76 @@ +getUser(); + + $space = id(new PhabricatorSpacesNamespaceQuery()) + ->setViewer($viewer) + ->withIDs(array($request->getURIData('id'))) + ->requireCapabilities( + array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + )) + ->executeOne(); + if (!$space) { + return new Aphront404Response(); + } + + $is_archive = ($request->getURIData('action') == 'archive'); + $cancel_uri = '/'.$space->getMonogram(); + + if ($request->isFormPost()) { + $type_archive = PhabricatorSpacesNamespaceTransaction::TYPE_ARCHIVE; + + $xactions = array(); + $xactions[] = id(new PhabricatorSpacesNamespaceTransaction()) + ->setTransactionType($type_archive) + ->setNewValue($is_archive ? 1 : 0); + + $editor = id(new PhabricatorSpacesNamespaceEditor()) + ->setActor($viewer) + ->setContinueOnNoEffect(true) + ->setContinueOnMissingFields(true) + ->setContentSourceFromRequest($request); + + $editor->applyTransactions($space, $xactions); + + return id(new AphrontRedirectResponse())->setURI($cancel_uri); + } + + $body = array(); + if ($is_archive) { + $title = pht('Archive Space: %s', $space->getNamespaceName()); + $body[] = pht( + 'If you archive this Space, you will no longer be able to create '. + 'new objects inside it.'); + $body[] = pht( + 'Existing objects in this Space will be hidden from query results '. + 'by default.'); + $button = pht('Archive Space'); + } else { + $title = pht('Activate Space: %s', $space->getNamespaceName()); + $body[] = pht( + 'If you activate this space, you will be able to create objects '. + 'inside it again.'); + $body[] = pht( + 'Existing objects will no longer be hidden from query results.'); + $button = pht('Activate Space'); + } + + + $dialog = $this->newDialog() + ->setTitle($title) + ->addCancelButton($cancel_uri) + ->addSubmitButton($button); + + foreach ($body as $paragraph) { + $dialog->appendParagraph($paragraph); + } + + return $dialog; + } +} diff --git a/src/applications/spaces/controller/PhabricatorSpacesViewController.php b/src/applications/spaces/controller/PhabricatorSpacesViewController.php index 46e82627ec..511d853151 100644 --- a/src/applications/spaces/controller/PhabricatorSpacesViewController.php +++ b/src/applications/spaces/controller/PhabricatorSpacesViewController.php @@ -37,6 +37,12 @@ final class PhabricatorSpacesViewController ->setHeader($space->getNamespaceName()) ->setPolicyObject($space); + if ($space->getIsArchived()) { + $header->setStatus('fa-ban', 'red', pht('Archived')); + } else { + $header->setStatus('fa-check', 'bluegrey', pht('Active')); + } + $box = id(new PHUIObjectBoxView()) ->setHeader($header) ->addPropertyList($property_list); @@ -112,6 +118,26 @@ final class PhabricatorSpacesViewController ->setWorkflow(!$can_edit) ->setDisabled(!$can_edit)); + $id = $space->getID(); + + if ($space->getIsArchived()) { + $list->addAction( + id(new PhabricatorActionView()) + ->setName(pht('Activate Space')) + ->setIcon('fa-check') + ->setHref($this->getApplicationURI("activate/{$id}/")) + ->setDisabled(!$can_edit) + ->setWorkflow(true)); + } else { + $list->addAction( + id(new PhabricatorActionView()) + ->setName(pht('Archive Space')) + ->setIcon('fa-ban') + ->setHref($this->getApplicationURI("archive/{$id}/")) + ->setDisabled(!$can_edit) + ->setWorkflow(true)); + } + return $list; } diff --git a/src/applications/spaces/editor/PhabricatorSpacesNamespaceEditor.php b/src/applications/spaces/editor/PhabricatorSpacesNamespaceEditor.php index 3b6c7bb6e6..caa45f28c2 100644 --- a/src/applications/spaces/editor/PhabricatorSpacesNamespaceEditor.php +++ b/src/applications/spaces/editor/PhabricatorSpacesNamespaceEditor.php @@ -17,6 +17,7 @@ final class PhabricatorSpacesNamespaceEditor $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; @@ -40,6 +41,8 @@ final class PhabricatorSpacesNamespaceEditor 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: @@ -61,6 +64,8 @@ final class PhabricatorSpacesNamespaceEditor 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; } @@ -84,6 +89,9 @@ final class PhabricatorSpacesNamespaceEditor 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; @@ -103,6 +111,7 @@ final class PhabricatorSpacesNamespaceEditor 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; @@ -128,13 +137,27 @@ final class PhabricatorSpacesNamespaceEditor $error = new PhabricatorApplicationTransactionValidationError( $type, pht('Required'), - pht('Spaces must have a name.'), + 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; diff --git a/src/applications/spaces/phid/PhabricatorSpacesNamespacePHIDType.php b/src/applications/spaces/phid/PhabricatorSpacesNamespacePHIDType.php index 710972e8f4..6645c7edbd 100644 --- a/src/applications/spaces/phid/PhabricatorSpacesNamespacePHIDType.php +++ b/src/applications/spaces/phid/PhabricatorSpacesNamespacePHIDType.php @@ -39,6 +39,10 @@ final class PhabricatorSpacesNamespacePHIDType $handle->setName($name); $handle->setFullName(pht('%s %s', $monogram, $name)); $handle->setURI('/'.$monogram); + + if ($namespace->getIsArchived()) { + $handle->setStatus(PhabricatorObjectHandle::STATUS_CLOSED); + } } } diff --git a/src/applications/spaces/query/PhabricatorSpacesNamespaceQuery.php b/src/applications/spaces/query/PhabricatorSpacesNamespaceQuery.php index 77cb8aee5e..51ac66130a 100644 --- a/src/applications/spaces/query/PhabricatorSpacesNamespaceQuery.php +++ b/src/applications/spaces/query/PhabricatorSpacesNamespaceQuery.php @@ -9,6 +9,7 @@ final class PhabricatorSpacesNamespaceQuery private $ids; private $phids; private $isDefaultNamespace; + private $isArchived; public function withIDs(array $ids) { $this->ids = $ids; @@ -25,38 +26,32 @@ final class PhabricatorSpacesNamespaceQuery return $this; } + public function withIsArchived($archived) { + $this->isArchived = $archived; + return $this; + } + public function getQueryApplicationClass() { return 'PhabricatorSpacesApplication'; } protected function loadPage() { - $table = new PhabricatorSpacesNamespace(); - $conn_r = $table->establishConnection('r'); - - $rows = queryfx_all( - $conn_r, - 'SELECT * FROM %T %Q %Q %Q', - $table->getTableName(), - $this->buildWhereClause($conn_r), - $this->buildOrderClause($conn_r), - $this->buildLimitClause($conn_r)); - - return $table->loadAllFromArray($rows); + return $this->loadStandardPage(new PhabricatorSpacesNamespace()); } - protected function buildWhereClause(AphrontDatabaseConnection $conn_r) { - $where = array(); + protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { + $where = parent::buildWhereClauseParts($conn); if ($this->ids !== null) { $where[] = qsprintf( - $conn_r, + $conn, 'id IN (%Ld)', $this->ids); } if ($this->phids !== null) { $where[] = qsprintf( - $conn_r, + $conn, 'phid IN (%Ls)', $this->phids); } @@ -64,17 +59,23 @@ final class PhabricatorSpacesNamespaceQuery if ($this->isDefaultNamespace !== null) { if ($this->isDefaultNamespace) { $where[] = qsprintf( - $conn_r, + $conn, 'isDefaultNamespace = 1'); } else { $where[] = qsprintf( - $conn_r, + $conn, 'isDefaultNamespace IS NULL'); } } - $where[] = $this->buildPagingClause($conn_r); - return $this->formatWhereClause($where); + if ($this->isArchived !== null) { + $where[] = qsprintf( + $conn, + 'isArchived = %d', + (int)$this->isArchived); + } + + return $where; } public static function destroySpacesCache() { @@ -156,6 +157,21 @@ final class PhabricatorSpacesNamespaceQuery return $result; } + + public static function getViewerActiveSpaces(PhabricatorUser $viewer) { + $spaces = self::getViewerSpaces($viewer); + + foreach ($spaces as $key => $space) { + if ($space->getIsArchived()) { + unset($spaces[$key]); + } + } + + return $spaces; + } + + + /** * Get the Space PHID for an object, if one exists. * diff --git a/src/applications/spaces/query/PhabricatorSpacesNamespaceSearchEngine.php b/src/applications/spaces/query/PhabricatorSpacesNamespaceSearchEngine.php index 9b4014c3dd..c12ad9e098 100644 --- a/src/applications/spaces/query/PhabricatorSpacesNamespaceSearchEngine.php +++ b/src/applications/spaces/query/PhabricatorSpacesNamespaceSearchEngine.php @@ -11,28 +11,39 @@ final class PhabricatorSpacesNamespaceSearchEngine return pht('Spaces'); } - public function buildSavedQueryFromRequest(AphrontRequest $request) { - $saved = new PhabricatorSavedQuery(); - - return $saved; + public function newQuery() { + return new PhabricatorSpacesNamespaceQuery(); } - public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) { - $query = id(new PhabricatorSpacesNamespaceQuery()); + public function buildCustomSearchFields() { + return array( + id(new PhabricatorSearchThreeStateField()) + ->setLabel(pht('Active')) + ->setKey('active') + ->setOptions( + pht('(Show All)'), + pht('Show Only Active Spaces'), + pht('Hide Active Spaces')), + ); + } + + public function buildQueryFromParameters(array $map) { + $query = $this->newQuery(); + + if ($map['active']) { + $query->withIsArchived(!$map['active']); + } return $query; } - public function buildSearchForm( - AphrontFormView $form, - PhabricatorSavedQuery $saved_query) {} - protected function getURI($path) { return '/spaces/'.$path; } protected function getBuiltinQueryNames() { $names = array( + 'active' => pht('Active Spaces'), 'all' => pht('All Spaces'), ); @@ -40,11 +51,12 @@ final class PhabricatorSpacesNamespaceSearchEngine } public function buildSavedQueryFromBuiltin($query_key) { - $query = $this->newSavedQuery(); $query->setQueryKey($query_key); switch ($query_key) { + case 'active': + return $query->setParameter('active', true); case 'all': return $query; } @@ -72,6 +84,10 @@ final class PhabricatorSpacesNamespaceSearchEngine $item->addIcon('fa-certificate', pht('Default Space')); } + if ($space->getIsArchived()) { + $item->setDisabled(true); + } + $list->addItem($item); } diff --git a/src/applications/spaces/storage/PhabricatorSpacesNamespace.php b/src/applications/spaces/storage/PhabricatorSpacesNamespace.php index 5b1098b1f8..f728d22dfa 100644 --- a/src/applications/spaces/storage/PhabricatorSpacesNamespace.php +++ b/src/applications/spaces/storage/PhabricatorSpacesNamespace.php @@ -12,6 +12,7 @@ final class PhabricatorSpacesNamespace protected $editPolicy; protected $isDefaultNamespace; protected $description; + protected $isArchived; public static function initializeNewNamespace(PhabricatorUser $actor) { $app = id(new PhabricatorApplicationQuery()) @@ -28,7 +29,8 @@ final class PhabricatorSpacesNamespace ->setIsDefaultNamespace(null) ->setViewPolicy($view_policy) ->setEditPolicy($edit_policy) - ->setDescription(''); + ->setDescription('') + ->setIsArchived(0); } protected function getConfiguration() { @@ -38,6 +40,7 @@ final class PhabricatorSpacesNamespace 'namespaceName' => 'text255', 'isDefaultNamespace' => 'bool?', 'description' => 'text', + 'isArchived' => 'bool', ), self::CONFIG_KEY_SCHEMA => array( 'key_default' => array( diff --git a/src/applications/spaces/storage/PhabricatorSpacesNamespaceTransaction.php b/src/applications/spaces/storage/PhabricatorSpacesNamespaceTransaction.php index ef7d8f210f..4c438537f1 100644 --- a/src/applications/spaces/storage/PhabricatorSpacesNamespaceTransaction.php +++ b/src/applications/spaces/storage/PhabricatorSpacesNamespaceTransaction.php @@ -6,6 +6,7 @@ final class PhabricatorSpacesNamespaceTransaction const TYPE_NAME = 'spaces:name'; const TYPE_DEFAULT = 'spaces:default'; const TYPE_DESCRIPTION = 'spaces:description'; + const TYPE_ARCHIVE = 'spaces:archive'; public function getApplicationName() { return 'spaces'; @@ -78,6 +79,16 @@ final class PhabricatorSpacesNamespaceTransaction 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(); diff --git a/src/applications/spaces/typeahead/PhabricatorSpacesNamespaceDatasource.php b/src/applications/spaces/typeahead/PhabricatorSpacesNamespaceDatasource.php index 046e3b0f4f..25951b53af 100644 --- a/src/applications/spaces/typeahead/PhabricatorSpacesNamespaceDatasource.php +++ b/src/applications/spaces/typeahead/PhabricatorSpacesNamespaceDatasource.php @@ -21,9 +21,20 @@ final class PhabricatorSpacesNamespaceDatasource $spaces = $this->executeQuery($query); $results = array(); foreach ($spaces as $space) { - $results[] = id(new PhabricatorTypeaheadResult()) - ->setName($space->getNamespaceName()) + $full_name = pht( + '%s %s', + $space->getMonogram(), + $space->getNamespaceName()); + + $result = id(new PhabricatorTypeaheadResult()) + ->setName($full_name) ->setPHID($space->getPHID()); + + if ($space->getIsArchived()) { + $result->setClosed(pht('Archived')); + } + + $results[] = $result; } return $this->filterResultsAgainstTokens($results); diff --git a/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php b/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php index b4d36b5513..2f36828b8a 100644 --- a/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php +++ b/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php @@ -310,6 +310,7 @@ abstract class PhabricatorApplicationTransactionEditor $space_phid = $default_space->getPHID(); } } + return $space_phid; case PhabricatorTransactions::TYPE_EDGE: $edge_type = $xaction->getMetadataValue('edge:type'); @@ -2011,6 +2012,8 @@ abstract class PhabricatorApplicationTransactionEditor $has_spaces = PhabricatorSpacesNamespaceQuery::getViewerSpacesExist($actor); $actor_spaces = PhabricatorSpacesNamespaceQuery::getViewerSpaces($actor); + $active_spaces = PhabricatorSpacesNamespaceQuery::getViewerActiveSpaces( + $actor); foreach ($xactions as $xaction) { $space_phid = $xaction->getNewValue(); @@ -2040,6 +2043,23 @@ abstract class PhabricatorApplicationTransactionEditor 'You can not shift this object in the selected space, because '. 'the space does not exist or you do not have access to it.'), $xaction); + } else if (empty($active_spaces[$space_phid])) { + + // It's OK to edit objects in an archived space, so just move on if + // we aren't adjusting the value. + $old_space_phid = $this->getTransactionOldValue($object, $xaction); + if ($space_phid == $old_space_phid) { + continue; + } + + $errors[] = new PhabricatorApplicationTransactionValidationError( + $transaction_type, + pht('Archived'), + pht( + 'You can not shift this object into the selected space, because '. + 'the space is archived. Objects can not be created inside (or '. + 'moved into) archived spaces.'), + $xaction); } } diff --git a/src/docs/user/userguide/spaces.diviner b/src/docs/user/userguide/spaces.diviner new file mode 100644 index 0000000000..9026edf86e --- /dev/null +++ b/src/docs/user/userguide/spaces.diviner @@ -0,0 +1,27 @@ +@title Spaces User Guide +@group userguide + +Guide to the Spaces application. + +Overview +======== + +IMPORTANT: Spaces is a prototype application. + +Archiving Spaces +================ + +If you no longer need a Space, you can archive it by choosing +{nav Archive Space} from the detail view. This hides the space and all the +objects in it without deleting any data. + +New objects can't be created into archived spaces, and existing objects can't +be shifted into archived spaces. The UI won't give you options to choose +these spaces when creating or editing objects. + +Additionally, objects (like tasks) in archived spaces won't be shown in most +search result lists by default. If you need to find objects in an archived +space, use the `Spaces` constraint to specifically search for objects in that +space. + +You can reactivate a space later by choosing {nav Activate Space}. diff --git a/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php b/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php index b48e1e5c46..4d0f96bde5 100644 --- a/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php +++ b/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php @@ -25,6 +25,7 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery private $edgeLogicConstraints = array(); private $edgeLogicConstraintsAreValid = false; private $spacePHIDs; + private $spaceIsArchived; protected function getPageCursors(array $page) { return array( @@ -1722,6 +1723,11 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery return $this; } + public function withSpaceIsArchived($archived) { + $this->spaceIsArchived = $archived; + return $this; + } + /** * Constrain the query to include only results in valid Spaces. @@ -1760,6 +1766,11 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery $viewer_spaces = PhabricatorSpacesNamespaceQuery::getViewerSpaces( $viewer); foreach ($viewer_spaces as $viewer_space) { + if ($this->spaceIsArchived !== null) { + if ($viewer_space->getIsArchived() != $this->spaceIsArchived) { + continue; + } + } $phid = $viewer_space->getPHID(); $space_phids[$phid] = $phid; if ($viewer_space->getIsDefaultNamespace()) { diff --git a/src/view/form/control/AphrontFormPolicyControl.php b/src/view/form/control/AphrontFormPolicyControl.php index 45bff0900e..58d06cc5de 100644 --- a/src/view/form/control/AphrontFormPolicyControl.php +++ b/src/view/form/control/AphrontFormPolicyControl.php @@ -265,7 +265,7 @@ final class AphrontFormPolicyControl extends AphrontFormControl { $select = AphrontFormSelectControl::renderSelectTag( $space_phid, - $this->getSpaceOptions(), + $this->getSpaceOptions($space_phid), array( 'name' => 'spacePHID', )); @@ -273,12 +273,20 @@ final class AphrontFormPolicyControl extends AphrontFormControl { return $select; } - protected function getSpaceOptions() { + protected function getSpaceOptions($space_phid) { $viewer = $this->getUser(); $viewer_spaces = PhabricatorSpacesNamespaceQuery::getViewerSpaces($viewer); $map = array(); foreach ($viewer_spaces as $space) { + + // Skip archived spaces, unless the object is already in that space. + if ($space->getIsArchived()) { + if ($space->getPHID() != $space_phid) { + continue; + } + } + $map[$space->getPHID()] = pht( 'Space %s: %s', $space->getMonogram(), From d5668ddeaeb17b939b5e762b615f80065b5a0a53 Mon Sep 17 00:00:00 2001 From: epriestley Date: Thu, 11 Jun 2015 10:14:06 -0700 Subject: [PATCH 11/50] Implement a "Space is any of..." condition in Herald Summary: Ref T8498. Allow Herald rules to act on the Space which contains an object. Test Plan: - Wrote a "Space is any of..." rule, created tasks that matched and failed the rule. - Also created a Pholio rule with the "Space..." condition. Reviewers: btrahan Reviewed By: btrahan Subscribers: epriestley Maniphest Tasks: T8498 Differential Revision: https://secure.phabricator.com/D13242 --- resources/celerity/map.php | 22 +++++++++---------- .../herald/adapter/HeraldAdapter.php | 19 ++++++++++++++++ .../adapter/HeraldManiphestTaskAdapter.php | 1 + .../adapter/HeraldPholioMockAdapter.php | 1 + .../controller/HeraldRuleController.php | 1 + .../js/application/herald/HeraldRuleEditor.js | 1 + 6 files changed, 34 insertions(+), 11 deletions(-) diff --git a/resources/celerity/map.php b/resources/celerity/map.php index c13dd2c0c5..04034037e6 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -371,7 +371,7 @@ return array( 'rsrc/js/application/doorkeeper/behavior-doorkeeper-tag.js' => 'e5822781', 'rsrc/js/application/files/behavior-icon-composer.js' => '8ef9ab58', 'rsrc/js/application/files/behavior-launch-icon-composer.js' => '48086888', - 'rsrc/js/application/herald/HeraldRuleEditor.js' => '271ffdd7', + 'rsrc/js/application/herald/HeraldRuleEditor.js' => 'b2cae298', 'rsrc/js/application/herald/PathTypeahead.js' => 'f7fc67ec', 'rsrc/js/application/herald/herald-rule-editor.js' => '7ebaeed3', 'rsrc/js/application/maniphest/behavior-batch-editor.js' => 'f5d1233b', @@ -527,7 +527,7 @@ return array( 'global-drag-and-drop-css' => '697324ad', 'harbormaster-css' => '49d64eb4', 'herald-css' => '826075fa', - 'herald-rule-editor' => '271ffdd7', + 'herald-rule-editor' => 'b2cae298', 'herald-test-css' => '778b008e', 'homepage-panel-css' => 'e34bf140', 'inline-comment-summary-css' => '51efda3a', @@ -1009,15 +1009,6 @@ return array( 'phabricator-drag-and-drop-file-upload', 'phabricator-draggable-list', ), - '271ffdd7' => array( - 'multirow-row-manager', - 'javelin-install', - 'javelin-util', - 'javelin-dom', - 'javelin-stratcom', - 'javelin-json', - 'phabricator-prefab', - ), '2818f5ce' => array( 'javelin-install', 'javelin-util', @@ -1701,6 +1692,15 @@ return array( 'javelin-uri', 'javelin-request', ), + 'b2cae298' => array( + 'multirow-row-manager', + 'javelin-install', + 'javelin-util', + 'javelin-dom', + 'javelin-stratcom', + 'javelin-json', + 'phabricator-prefab', + ), 'b3a4b884' => array( 'javelin-behavior', 'phabricator-prefab', diff --git a/src/applications/herald/adapter/HeraldAdapter.php b/src/applications/herald/adapter/HeraldAdapter.php index f50bdf4203..a43592c345 100644 --- a/src/applications/herald/adapter/HeraldAdapter.php +++ b/src/applications/herald/adapter/HeraldAdapter.php @@ -44,6 +44,7 @@ abstract class HeraldAdapter { const FIELD_TASK_STATUS = 'taskstatus'; const FIELD_PUSHER_IS_COMMITTER = 'pusher-is-committer'; const FIELD_PATH = 'path'; + const FIELD_SPACE = 'space'; const CONDITION_CONTAINS = 'contains'; const CONDITION_NOT_CONTAINS = '!contains'; @@ -101,6 +102,7 @@ abstract class HeraldAdapter { const VALUE_TASK_STATUS = 'taskstatus'; const VALUE_LEGAL_DOCUMENTS = 'legaldocuments'; const VALUE_APPLICATION_EMAIL = 'applicationemail'; + const VALUE_SPACE = 'space'; private $contentSource; private $isNewObject; @@ -219,6 +221,19 @@ abstract class HeraldAdapter { $value[] = $this->getApplicationEmail()->getPHID(); } return $value; + case self::FIELD_SPACE: + $object = $this->getObject(); + + if (!($object instanceof PhabricatorSpacesInterface)) { + throw new Exception( + pht( + 'Adapter object (of class "%s") does not implement interface '. + '"%s", so the Space field value can not be determined.', + get_class($object), + 'PhabricatorSpacesInterface')); + } + + return PhabricatorSpacesNamespaceQuery::getObjectSpacePHID($object); default: if ($this->isHeraldCustomKey($field_name)) { return $this->getCustomFieldValue($field_name); @@ -400,6 +415,7 @@ abstract class HeraldAdapter { self::FIELD_TASK_STATUS => pht('Task status'), self::FIELD_PUSHER_IS_COMMITTER => pht('Pusher same as committer'), self::FIELD_PATH => pht('Path'), + self::FIELD_SPACE => pht('Space'), ) + $this->getCustomFieldNameMap(); } @@ -453,6 +469,7 @@ abstract class HeraldAdapter { case self::FIELD_PUSHER: case self::FIELD_TASK_PRIORITY: case self::FIELD_TASK_STATUS: + case self::FIELD_SPACE: return array( self::CONDITION_IS_ANY, self::CONDITION_IS_NOT_ANY, @@ -957,6 +974,8 @@ abstract class HeraldAdapter { return self::VALUE_TASK_PRIORITY; case self::FIELD_TASK_STATUS: return self::VALUE_TASK_STATUS; + case self::FIELD_SPACE: + return self::VALUE_SPACE; default: return self::VALUE_USER; } diff --git a/src/applications/herald/adapter/HeraldManiphestTaskAdapter.php b/src/applications/herald/adapter/HeraldManiphestTaskAdapter.php index a84130095a..906981af39 100644 --- a/src/applications/herald/adapter/HeraldManiphestTaskAdapter.php +++ b/src/applications/herald/adapter/HeraldManiphestTaskAdapter.php @@ -73,6 +73,7 @@ final class HeraldManiphestTaskAdapter extends HeraldAdapter { self::FIELD_TASK_STATUS, self::FIELD_IS_NEW_OBJECT, self::FIELD_APPLICATION_EMAIL, + self::FIELD_SPACE, ), parent::getFields()); } diff --git a/src/applications/herald/adapter/HeraldPholioMockAdapter.php b/src/applications/herald/adapter/HeraldPholioMockAdapter.php index e4aab69e95..5c9c78c0ac 100644 --- a/src/applications/herald/adapter/HeraldPholioMockAdapter.php +++ b/src/applications/herald/adapter/HeraldPholioMockAdapter.php @@ -52,6 +52,7 @@ final class HeraldPholioMockAdapter extends HeraldAdapter { self::FIELD_CC, self::FIELD_PROJECTS, self::FIELD_IS_NEW_OBJECT, + self::FIELD_SPACE, ), parent::getFields()); } diff --git a/src/applications/herald/controller/HeraldRuleController.php b/src/applications/herald/controller/HeraldRuleController.php index a2fbe7a108..a956063fdf 100644 --- a/src/applications/herald/controller/HeraldRuleController.php +++ b/src/applications/herald/controller/HeraldRuleController.php @@ -632,6 +632,7 @@ final class HeraldRuleController extends HeraldController { 'email' => new PhabricatorMetaMTAMailableDatasource(), 'userorproject' => new PhabricatorProjectOrUserDatasource(), 'applicationemail' => new PhabricatorMetaMTAApplicationEmailDatasource(), + 'space' => new PhabricatorSpacesNamespaceDatasource(), ); foreach ($sources as $key => $source) { diff --git a/webroot/rsrc/js/application/herald/HeraldRuleEditor.js b/webroot/rsrc/js/application/herald/HeraldRuleEditor.js index e7300528d6..c94dd0d6c0 100644 --- a/webroot/rsrc/js/application/herald/HeraldRuleEditor.js +++ b/webroot/rsrc/js/application/herald/HeraldRuleEditor.js @@ -222,6 +222,7 @@ JX.install('HeraldRuleEditor', { case 'taskstatus': case 'legaldocuments': case 'applicationemail': + case 'space': var tokenizer = this._newTokenizer(type); input = tokenizer[0]; get_fn = tokenizer[1]; From 325f4c863c9d6bd74ec74aa2f445eed9e03f9e47 Mon Sep 17 00:00:00 2001 From: epriestley Date: Thu, 11 Jun 2015 10:14:22 -0700 Subject: [PATCH 12/50] Don't show Space monograms in SpaceContextView Summary: Ref T8449. Get rid of the `S123` stuff in headers, it feels like clutter. Test Plan: Looked at objects in Spaces. Reviewers: btrahan Reviewed By: btrahan Subscribers: epriestley Maniphest Tasks: T8449 Differential Revision: https://secure.phabricator.com/D13243 --- src/applications/phid/view/PHUIHandleView.php | 12 +++++++++++- .../spaces/view/PHUISpacesNamespaceContextView.php | 2 +- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/applications/phid/view/PHUIHandleView.php b/src/applications/phid/view/PHUIHandleView.php index db4b9e43ab..a4b766a991 100644 --- a/src/applications/phid/view/PHUIHandleView.php +++ b/src/applications/phid/view/PHUIHandleView.php @@ -14,6 +14,7 @@ final class PHUIHandleView private $handleList; private $handlePHID; private $asTag; + private $useShortName; public function setHandleList(PhabricatorHandleList $list) { $this->handleList = $list; @@ -30,12 +31,21 @@ final class PHUIHandleView return $this; } + public function setUseShortName($short) { + $this->useShortName = $short; + return $this; + } + public function render() { $handle = $this->handleList[$this->handlePHID]; if ($this->asTag) { return $handle->renderTag(); } else { - return $handle->renderLink(); + if ($this->useShortName) { + return $handle->renderLink($handle->getName()); + } else { + return $handle->renderLink(); + } } } diff --git a/src/applications/spaces/view/PHUISpacesNamespaceContextView.php b/src/applications/spaces/view/PHUISpacesNamespaceContextView.php index d63ae8e6f4..0bb5949b76 100644 --- a/src/applications/spaces/view/PHUISpacesNamespaceContextView.php +++ b/src/applications/spaces/view/PHUISpacesNamespaceContextView.php @@ -41,7 +41,7 @@ final class PHUISpacesNamespaceContextView extends AphrontView { 'class' => 'spaces-name', ), array( - $viewer->renderHandle($space_phid), + $viewer->renderHandle($space_phid)->setUseShortName(true), ' | ', )); } From 6d6211d4417606f96d42f98be5cf05b56bd92403 Mon Sep 17 00:00:00 2001 From: epriestley Date: Thu, 11 Jun 2015 10:15:49 -0700 Subject: [PATCH 13/50] Use ApplicationTransactions in ApplicationEmail Summary: Ref T8498. I want to add Spaces to these, and the logic for getting Spaces right is a bit tricky, so swap these to ApplicationTransactions. One new piece of tech: made it easier for Editors to raise DuplicateKeyException as a normal ValidationException, so callers don't have to handle this case specially. One behavioral change: we no longer require these addresses to be at the `auth.email-domains` domains -- I think this wasn't quite right in the general case. It's OK to require users to have `@mycompany.com` addresses but add `@phabricator.mycompany-infrastructure.com` addresses here if you want. Test Plan: - Tried to create a duplicate email. - Tried to create an empty email. - Tried to create an invalid email. - Created a new email. - Deleted an email. Reviewers: btrahan Reviewed By: btrahan Subscribers: epriestley Maniphest Tasks: T8498 Differential Revision: https://secure.phabricator.com/D13246 --- .../20150611.spaces.1.mailxaction.sql | 19 +++ src/__phutil_library_map__.php | 8 + ...habricatorMetaMTAApplicationEmailPanel.php | 119 +++++++------- ...abricatorMetaMTAApplicationEmailEditor.php | 145 ++++++++++++++++++ ...etaMTAApplicationEmailTransactionQuery.php | 10 ++ .../PhabricatorMetaMTAApplicationEmail.php | 36 ++++- ...atorMetaMTAApplicationEmailTransaction.php | 23 +++ ...habricatorApplicationTransactionEditor.php | 12 ++ 8 files changed, 308 insertions(+), 64 deletions(-) create mode 100644 resources/sql/autopatches/20150611.spaces.1.mailxaction.sql create mode 100644 src/applications/metamta/editor/PhabricatorMetaMTAApplicationEmailEditor.php create mode 100644 src/applications/metamta/query/PhabricatorMetaMTAApplicationEmailTransactionQuery.php create mode 100644 src/applications/metamta/storage/PhabricatorMetaMTAApplicationEmailTransaction.php diff --git a/resources/sql/autopatches/20150611.spaces.1.mailxaction.sql b/resources/sql/autopatches/20150611.spaces.1.mailxaction.sql new file mode 100644 index 0000000000..fe519f48ab --- /dev/null +++ b/resources/sql/autopatches/20150611.spaces.1.mailxaction.sql @@ -0,0 +1,19 @@ +CREATE TABLE {$NAMESPACE}_metamta.metamta_applicationemailtransaction ( + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + phid VARBINARY(64) NOT NULL, + authorPHID VARBINARY(64) NOT NULL, + objectPHID VARBINARY(64) NOT NULL, + viewPolicy VARBINARY(64) NOT NULL, + editPolicy VARBINARY(64) NOT NULL, + commentPHID VARBINARY(64) DEFAULT NULL, + commentVersion INT UNSIGNED NOT NULL, + transactionType VARCHAR(32) COLLATE {$COLLATE_TEXT} NOT NULL, + oldValue LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL, + newValue LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL, + contentSource LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL, + metadata LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL, + dateCreated INT UNSIGNED NOT NULL, + dateModified INT UNSIGNED NOT NULL, + UNIQUE KEY `key_phid` (`phid`), + KEY `key_object` (`objectPHID`) +) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT}; diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 079819f657..ccd860a69a 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -2051,9 +2051,12 @@ phutil_register_library_map(array( 'PhabricatorMetaMTAApplication' => 'applications/metamta/application/PhabricatorMetaMTAApplication.php', 'PhabricatorMetaMTAApplicationEmail' => 'applications/metamta/storage/PhabricatorMetaMTAApplicationEmail.php', 'PhabricatorMetaMTAApplicationEmailDatasource' => 'applications/metamta/typeahead/PhabricatorMetaMTAApplicationEmailDatasource.php', + 'PhabricatorMetaMTAApplicationEmailEditor' => 'applications/metamta/editor/PhabricatorMetaMTAApplicationEmailEditor.php', 'PhabricatorMetaMTAApplicationEmailPHIDType' => 'applications/phid/PhabricatorMetaMTAApplicationEmailPHIDType.php', 'PhabricatorMetaMTAApplicationEmailPanel' => 'applications/metamta/applicationpanel/PhabricatorMetaMTAApplicationEmailPanel.php', 'PhabricatorMetaMTAApplicationEmailQuery' => 'applications/metamta/query/PhabricatorMetaMTAApplicationEmailQuery.php', + 'PhabricatorMetaMTAApplicationEmailTransaction' => 'applications/metamta/storage/PhabricatorMetaMTAApplicationEmailTransaction.php', + 'PhabricatorMetaMTAApplicationEmailTransactionQuery' => 'applications/metamta/query/PhabricatorMetaMTAApplicationEmailTransactionQuery.php', 'PhabricatorMetaMTAAttachment' => 'applications/metamta/storage/PhabricatorMetaMTAAttachment.php', 'PhabricatorMetaMTAConfigOptions' => 'applications/config/option/PhabricatorMetaMTAConfigOptions.php', 'PhabricatorMetaMTAController' => 'applications/metamta/controller/PhabricatorMetaMTAController.php', @@ -5493,11 +5496,16 @@ phutil_register_library_map(array( 'PhabricatorMetaMTAApplicationEmail' => array( 'PhabricatorMetaMTADAO', 'PhabricatorPolicyInterface', + 'PhabricatorApplicationTransactionInterface', + 'PhabricatorDestructibleInterface', ), 'PhabricatorMetaMTAApplicationEmailDatasource' => 'PhabricatorTypeaheadDatasource', + 'PhabricatorMetaMTAApplicationEmailEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorMetaMTAApplicationEmailPHIDType' => 'PhabricatorPHIDType', 'PhabricatorMetaMTAApplicationEmailPanel' => 'PhabricatorApplicationConfigurationPanel', 'PhabricatorMetaMTAApplicationEmailQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', + 'PhabricatorMetaMTAApplicationEmailTransaction' => 'PhabricatorApplicationTransaction', + 'PhabricatorMetaMTAApplicationEmailTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhabricatorMetaMTAConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorMetaMTAController' => 'PhabricatorController', 'PhabricatorMetaMTADAO' => 'PhabricatorLiskDAO', diff --git a/src/applications/metamta/applicationpanel/PhabricatorMetaMTAApplicationEmailPanel.php b/src/applications/metamta/applicationpanel/PhabricatorMetaMTAApplicationEmailPanel.php index 80cb3f0313..e88e2210d8 100644 --- a/src/applications/metamta/applicationpanel/PhabricatorMetaMTAApplicationEmailPanel.php +++ b/src/applications/metamta/applicationpanel/PhabricatorMetaMTAApplicationEmailPanel.php @@ -190,30 +190,6 @@ final class PhabricatorMetaMTAApplicationEmailPanel )); } - private function validateApplicationEmail($email) { - $errors = array(); - $e_email = true; - - if (!strlen($email)) { - $e_email = pht('Required'); - $errors[] = pht('Email is required.'); - } else if (!PhabricatorUserEmail::isValidAddress($email)) { - $e_email = pht('Invalid'); - $errors[] = PhabricatorUserEmail::describeValidAddresses(); - } else if (!PhabricatorUserEmail::isAllowedAddress($email)) { - $e_email = pht('Disallowed'); - $errors[] = PhabricatorUserEmail::describeAllowedAddresses(); - } - $user_emails = id(new PhabricatorUserEmail()) - ->loadAllWhere('address = %s', $email); - if ($user_emails) { - $e_email = pht('Duplicate'); - $errors[] = pht('A user already has this email.'); - } - - return array($e_email, $errors); - } - private function returnNewAddressResponse( AphrontRequest $request, PhutilURI $uri, @@ -265,45 +241,59 @@ final class PhabricatorMetaMTAApplicationEmailPanel $viewer = $request->getUser(); - $e_email = true; - $email = null; - $errors = array(); - $default_user_key = + $config_default = PhabricatorMetaMTAApplicationEmail::CONFIG_DEFAULT_AUTHOR; + + $e_email = true; + $v_email = $email_object->getAddress(); + $v_default = $email_object->getConfigValue($config_default); + + $validation_exception = null; if ($request->isDialogFormPost()) { - $email = trim($request->getStr('email')); - list($e_email, $errors) = $this->validateApplicationEmail($email); - $email_object->setAddress($email); - $default_user = $request->getArr($default_user_key); - $default_user = reset($default_user); - if ($default_user) { - $email_object->setConfigValue($default_user_key, $default_user); - } + $e_email = null; - if (!$errors) { - try { - $email_object->save(); - return id(new AphrontRedirectResponse())->setURI( - $uri->alter('highlight', $email_object->getID())); - } catch (AphrontDuplicateKeyQueryException $ex) { - $e_email = pht('Duplicate'); - $errors[] = pht( - 'Another application is already configured to use this email '. - 'address.'); - } + $v_email = trim($request->getStr('email')); + $v_default = $request->getArr($config_default); + $v_default = nonempty(head($v_default), null); + + $type_address = + PhabricatorMetaMTAApplicationEmailTransaction::TYPE_ADDRESS; + $type_config = + PhabricatorMetaMTAApplicationEmailTransaction::TYPE_CONFIG; + + $key_config = PhabricatorMetaMTAApplicationEmailTransaction::KEY_CONFIG; + + $xactions = array(); + + $xactions[] = id(new PhabricatorMetaMTAApplicationEmailTransaction()) + ->setTransactionType($type_address) + ->setNewValue($v_email); + + $xactions[] = id(new PhabricatorMetaMTAApplicationEmailTransaction()) + ->setTransactionType($type_config) + ->setMetadataValue($key_config, $config_default) + ->setNewValue($v_default); + + $editor = id(new PhabricatorMetaMTAApplicationEmailEditor()) + ->setActor($viewer) + ->setContentSourceFromRequest($request) + ->setContinueOnNoEffect(true); + + try { + $editor->applyTransactions($email_object, $xactions); + + return id(new AphrontRedirectResponse())->setURI( + $uri->alter('highlight', $email_object->getID())); + } catch (PhabricatorApplicationTransactionValidationException $ex) { + $validation_exception = $ex; + $e_email = $ex->getShortMessage($type_address); } } - if ($errors) { - $errors = id(new PHUIInfoView()) - ->setErrors($errors); - } - - $default_user = $email_object->getConfigValue($default_user_key); - if ($default_user) { - $default_user_value = array($default_user); + if ($v_default) { + $v_default = array($v_default); } else { - $default_user_value = array(); + $v_default = array(); } $form = id(new AphrontFormView()) @@ -312,28 +302,29 @@ final class PhabricatorMetaMTAApplicationEmailPanel id(new AphrontFormTextControl()) ->setLabel(pht('Email')) ->setName('email') - ->setValue($email_object->getAddress()) - ->setCaption(PhabricatorUserEmail::describeAllowedAddresses()) + ->setValue($v_email) ->setError($e_email)) ->appendControl( id(new AphrontFormTokenizerControl()) ->setDatasource(new PhabricatorPeopleDatasource()) ->setLabel(pht('Default Author')) - ->setName($default_user_key) + ->setName($config_default) ->setLimit(1) - ->setValue($default_user_value) + ->setValue($v_default) ->setCaption(pht( 'Used if the "From:" address does not map to a known account.'))); + if ($is_new) { $title = pht('New Address'); } else { $title = pht('Edit Address'); } + $dialog = id(new AphrontDialogView()) ->setUser($viewer) ->setWidth(AphrontDialogView::WIDTH_FORM) ->setTitle($title) - ->appendChild($errors) + ->setValidationException($validation_exception) ->appendForm($form) ->addSubmitButton(pht('Save')) ->addCancelButton($uri); @@ -350,7 +341,8 @@ final class PhabricatorMetaMTAApplicationEmailPanel PhutilURI $uri, $email_object_id) { - $viewer = $request->getUser(); + $viewer = $this->getViewer(); + $email_object = id(new PhabricatorMetaMTAApplicationEmailQuery()) ->setViewer($viewer) ->withIDs(array($email_object_id)) @@ -365,7 +357,8 @@ final class PhabricatorMetaMTAApplicationEmailPanel } if ($request->isDialogFormPost()) { - $email_object->delete(); + $engine = new PhabricatorDestructionEngine(); + $engine->destroyObject($email_object); return id(new AphrontRedirectResponse())->setURI($uri); } diff --git a/src/applications/metamta/editor/PhabricatorMetaMTAApplicationEmailEditor.php b/src/applications/metamta/editor/PhabricatorMetaMTAApplicationEmailEditor.php new file mode 100644 index 0000000000..2cbd164a87 --- /dev/null +++ b/src/applications/metamta/editor/PhabricatorMetaMTAApplicationEmailEditor.php @@ -0,0 +1,145 @@ +getTransactionType()) { + case PhabricatorMetaMTAApplicationEmailTransaction::TYPE_ADDRESS: + return $object->getAddress(); + case PhabricatorMetaMTAApplicationEmailTransaction::TYPE_CONFIG: + $key = $xaction->getMetadataValue( + PhabricatorMetaMTAApplicationEmailTransaction::KEY_CONFIG); + return $object->getConfigValue($key); + } + + return parent::getCustomTransactionOldValue($object, $xaction); + } + + protected function getCustomTransactionNewValue( + PhabricatorLiskDAO $object, + PhabricatorApplicationTransaction $xaction) { + + switch ($xaction->getTransactionType()) { + case PhabricatorMetaMTAApplicationEmailTransaction::TYPE_ADDRESS: + case PhabricatorMetaMTAApplicationEmailTransaction::TYPE_CONFIG: + return $xaction->getNewValue(); + } + + return parent::getCustomTransactionNewValue($object, $xaction); + } + + protected function applyCustomInternalTransaction( + PhabricatorLiskDAO $object, + PhabricatorApplicationTransaction $xaction) { + + $new = $xaction->getNewValue(); + + switch ($xaction->getTransactionType()) { + case PhabricatorMetaMTAApplicationEmailTransaction::TYPE_ADDRESS: + $object->setAddress($new); + return; + case PhabricatorMetaMTAApplicationEmailTransaction::TYPE_CONFIG: + $key = $xaction->getMetadataValue( + PhabricatorMetaMTAApplicationEmailTransaction::KEY_CONFIG); + $object->setConfigValue($key, $new); + return; + } + + return parent::applyCustomInternalTransaction($object, $xaction); + } + + protected function applyCustomExternalTransaction( + PhabricatorLiskDAO $object, + PhabricatorApplicationTransaction $xaction) { + + switch ($xaction->getTransactionType()) { + case PhabricatorMetaMTAApplicationEmailTransaction::TYPE_ADDRESS: + case PhabricatorMetaMTAApplicationEmailTransaction::TYPE_CONFIG: + return; + } + + return parent::applyCustomExternalTransaction($object, $xaction); + } + + protected function validateTransaction( + PhabricatorLiskDAO $object, + $type, + array $xactions) { + + $errors = parent::validateTransaction($object, $type, $xactions); + + switch ($type) { + case PhabricatorMetaMTAApplicationEmailTransaction::TYPE_ADDRESS: + foreach ($xactions as $xaction) { + $email = $xaction->getNewValue(); + if (!strlen($email)) { + // We'll deal with this below. + continue; + } + + if (!PhabricatorUserEmail::isValidAddress($email)) { + $errors[] = new PhabricatorApplicationTransactionValidationError( + $type, + pht('Invalid'), + pht('Email address is not formatted properly.')); + } + } + + $missing = $this->validateIsEmptyTextField( + $object->getAddress(), + $xactions); + + if ($missing) { + $error = new PhabricatorApplicationTransactionValidationError( + $type, + pht('Required'), + pht('You must provide an email address.'), + nonempty(last($xactions), null)); + + $error->setIsMissingFieldError(true); + $errors[] = $error; + } + break; + } + + return $errors; + } + + protected function didCatchDuplicateKeyException( + PhabricatorLiskDAO $object, + array $xactions, + Exception $ex) { + + $errors = array(); + $errors[] = new PhabricatorApplicationTransactionValidationError( + PhabricatorMetaMTAApplicationEmailTransaction::TYPE_ADDRESS, + pht('Duplicate'), + pht('This email address is already in use.'), + null); + + throw new PhabricatorApplicationTransactionValidationException($errors); + } + + +} diff --git a/src/applications/metamta/query/PhabricatorMetaMTAApplicationEmailTransactionQuery.php b/src/applications/metamta/query/PhabricatorMetaMTAApplicationEmailTransactionQuery.php new file mode 100644 index 0000000000..4f4f6d11de --- /dev/null +++ b/src/applications/metamta/query/PhabricatorMetaMTAApplicationEmailTransactionQuery.php @@ -0,0 +1,10 @@ +getApplication()->describeAutomaticCapability($capability); } + +/* -( PhabricatorApplicationTransactionInterface )------------------------- */ + + + public function getApplicationTransactionEditor() { + return new PhabricatorMetaMTAApplicationEmailEditor(); + } + + public function getApplicationTransactionObject() { + return $this; + } + + public function getApplicationTransactionTemplate() { + return new PhabricatorMetaMTAApplicationEmailTransaction(); + } + + public function willRenderTimeline( + PhabricatorApplicationTransactionView $timeline, + AphrontRequest $request) { + return $timeline; + } + + +/* -( PhabricatorDestructibleInterface )----------------------------------- */ + + + public function destroyObjectPermanently( + PhabricatorDestructionEngine $engine) { + $this->delete(); + } + } diff --git a/src/applications/metamta/storage/PhabricatorMetaMTAApplicationEmailTransaction.php b/src/applications/metamta/storage/PhabricatorMetaMTAApplicationEmailTransaction.php new file mode 100644 index 0000000000..019adb338d --- /dev/null +++ b/src/applications/metamta/storage/PhabricatorMetaMTAApplicationEmailTransaction.php @@ -0,0 +1,23 @@ +save(); } catch (AphrontDuplicateKeyQueryException $ex) { $object->killTransaction(); + + // This callback has an opportunity to throw a better exception, + // so execution may end here. + $this->didCatchDuplicateKeyException($object, $xactions, $ex); + throw $ex; } @@ -1021,6 +1026,13 @@ abstract class PhabricatorApplicationTransactionEditor return $xactions; } + protected function didCatchDuplicateKeyException( + PhabricatorLiskDAO $object, + array $xactions, + Exception $ex) { + return; + } + public function publishTransactions( PhabricatorLiskDAO $object, array $xactions) { From c71873ed7b31438a4585c5516a259a2d2a89651f Mon Sep 17 00:00:00 2001 From: epriestley Date: Thu, 11 Jun 2015 10:23:20 -0700 Subject: [PATCH 14/50] Fix feed query cursor-based pagination on 32-bit systems Summary: Fixes T8503. On 32-bit systems, these 64-bit integers will be mangled by the '%d' conversion implied by the 'int' type. Test Plan: Somewhat guessing here since I don't have a 32-bit system handy, but this strongly echoes similar issues in the past. Feed works fine locally. Looked at the generated queries. Reviewers: btrahan Reviewed By: btrahan Subscribers: epriestley Maniphest Tasks: T8503 Differential Revision: https://secure.phabricator.com/D13250 --- src/applications/feed/query/PhabricatorFeedQuery.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/applications/feed/query/PhabricatorFeedQuery.php b/src/applications/feed/query/PhabricatorFeedQuery.php index b9c7d099aa..13cfb266ed 100644 --- a/src/applications/feed/query/PhabricatorFeedQuery.php +++ b/src/applications/feed/query/PhabricatorFeedQuery.php @@ -101,7 +101,7 @@ final class PhabricatorFeedQuery 'key' => array( 'table' => $table, 'column' => 'chronologicalKey', - 'type' => 'int', + 'type' => 'string', 'unique' => true, ), ); From 0bc8382dfd970a48143b741d677b576ae9688d05 Mon Sep 17 00:00:00 2001 From: epriestley Date: Thu, 11 Jun 2015 10:23:56 -0700 Subject: [PATCH 15/50] Support Spaces in ApplicationEmail Summary: Ref T8498. Allow ApplicationEmail addresses to be put into spaces: - You can only see and send to addresses in Spaces you have access to. - Objects are created into the same space their address is associated with. Test Plan: - Used `bin/mail receive-test` to send mail to various `xyz-bugs@...` addresses. - Saw objects created in the proper space. Reviewers: btrahan Reviewed By: btrahan Subscribers: epriestley Maniphest Tasks: T8498 Differential Revision: https://secure.phabricator.com/D13247 --- .../autopatches/20150611.spaces.2.appmail.sql | 2 + src/__phutil_library_map__.php | 1 + .../maniphest/storage/ManiphestTask.php | 1 + ...habricatorMetaMTAApplicationEmailPanel.php | 190 ++++++++++-------- ...habricatorMetaMTAApplicationEmailQuery.php | 32 +-- .../PhabricatorMetaMTAApplicationEmail.php | 13 +- .../paste/storage/PhabricatorPaste.php | 3 +- .../pholio/storage/PholioMock.php | 3 +- .../query/PhabricatorSpacesNamespaceQuery.php | 25 +++ ...atorApplicationTransactionReplyHandler.php | 16 ++ .../form/control/AphrontFormPolicyControl.php | 27 +-- 11 files changed, 183 insertions(+), 130 deletions(-) create mode 100644 resources/sql/autopatches/20150611.spaces.2.appmail.sql diff --git a/resources/sql/autopatches/20150611.spaces.2.appmail.sql b/resources/sql/autopatches/20150611.spaces.2.appmail.sql new file mode 100644 index 0000000000..c846e4338f --- /dev/null +++ b/resources/sql/autopatches/20150611.spaces.2.appmail.sql @@ -0,0 +1,2 @@ +ALTER TABLE {$NAMESPACE}_metamta.metamta_applicationemail + ADD spacePHID VARBINARY(64); diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index ccd860a69a..80cf17dcbc 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -5498,6 +5498,7 @@ phutil_register_library_map(array( 'PhabricatorPolicyInterface', 'PhabricatorApplicationTransactionInterface', 'PhabricatorDestructibleInterface', + 'PhabricatorSpacesInterface', ), 'PhabricatorMetaMTAApplicationEmailDatasource' => 'PhabricatorTypeaheadDatasource', 'PhabricatorMetaMTAApplicationEmailEditor' => 'PhabricatorApplicationTransactionEditor', diff --git a/src/applications/maniphest/storage/ManiphestTask.php b/src/applications/maniphest/storage/ManiphestTask.php index f244a1c918..7fbc806bae 100644 --- a/src/applications/maniphest/storage/ManiphestTask.php +++ b/src/applications/maniphest/storage/ManiphestTask.php @@ -58,6 +58,7 @@ final class ManiphestTask extends ManiphestDAO ->setAuthorPHID($actor->getPHID()) ->setViewPolicy($view_policy) ->setEditPolicy($edit_policy) + ->setSpacePHID($actor->getDefaultSpacePHID()) ->attachProjectPHIDs(array()) ->attachSubscriberPHIDs(array()); } diff --git a/src/applications/metamta/applicationpanel/PhabricatorMetaMTAApplicationEmailPanel.php b/src/applications/metamta/applicationpanel/PhabricatorMetaMTAApplicationEmailPanel.php index e88e2210d8..6a3499300b 100644 --- a/src/applications/metamta/applicationpanel/PhabricatorMetaMTAApplicationEmailPanel.php +++ b/src/applications/metamta/applicationpanel/PhabricatorMetaMTAApplicationEmailPanel.php @@ -16,24 +16,7 @@ final class PhabricatorMetaMTAApplicationEmailPanel $viewer = $this->getViewer(); $application = $this->getApplication(); - $addresses = id(new PhabricatorMetaMTAApplicationEmailQuery()) - ->setViewer($viewer) - ->withApplicationPHIDs(array($application->getPHID())) - ->execute(); - - $rows = array(); - foreach ($addresses as $address) { - $rows[] = array( - $address->getAddress(), - ); - } - - $table = id(new AphrontTableView($rows)) - ->setNoDataString(pht('No email addresses configured.')) - ->setHeaders( - array( - pht('Address'), - )); + $table = $this->buildEmailTable($is_edit = false, null); $can_edit = PhabricatorPolicyFilter::hasCapability( $viewer, @@ -91,68 +74,10 @@ final class PhabricatorMetaMTAApplicationEmailPanel return $this->returnDeleteAddressResponse($request, $uri, $delete); } - $emails = id(new PhabricatorMetaMTAApplicationEmailQuery()) - ->setViewer($viewer) - ->withApplicationPHIDs(array($application->getPHID())) - ->execute(); + $table = $this->buildEmailTable( + $is_edit = true, + $request->getInt('id')); - $highlight = $request->getInt('highlight'); - $rowc = array(); - $rows = array(); - foreach ($emails as $email) { - - $button_edit = javelin_tag( - 'a', - array( - 'class' => 'button small grey', - 'href' => $uri->alter('edit', $email->getID()), - 'sigil' => 'workflow', - ), - pht('Edit')); - - $button_remove = javelin_tag( - 'a', - array( - 'class' => 'button small grey', - 'href' => $uri->alter('delete', $email->getID()), - 'sigil' => 'workflow', - ), - pht('Delete')); - - if ($highlight == $email->getID()) { - $rowc[] = 'highlighted'; - } else { - $rowc[] = null; - } - - $rows[] = array( - $email->getAddress(), - $button_edit, - $button_remove, - ); - } - - $table = id(new AphrontTableView($rows)) - ->setNoDataString(pht('No application emails created yet.')); - $table->setHeaders( - array( - pht('Email'), - pht('Edit'), - pht('Delete'), - )); - $table->setColumnClasses( - array( - 'wide', - 'action', - 'action', - )); - $table->setRowClasses($rowc); - $table->setColumnVisibility( - array( - true, - true, - true, - )); $form = id(new AphrontFormView()) ->setUser($viewer); @@ -246,6 +171,8 @@ final class PhabricatorMetaMTAApplicationEmailPanel $e_email = true; $v_email = $email_object->getAddress(); + $e_space = null; + $v_space = $email_object->getSpacePHID(); $v_default = $email_object->getConfigValue($config_default); $validation_exception = null; @@ -253,11 +180,13 @@ final class PhabricatorMetaMTAApplicationEmailPanel $e_email = null; $v_email = trim($request->getStr('email')); + $v_space = $request->getStr('spacePHID'); $v_default = $request->getArr($config_default); $v_default = nonempty(head($v_default), null); $type_address = PhabricatorMetaMTAApplicationEmailTransaction::TYPE_ADDRESS; + $type_space = PhabricatorTransactions::TYPE_SPACE; $type_config = PhabricatorMetaMTAApplicationEmailTransaction::TYPE_CONFIG; @@ -269,6 +198,10 @@ final class PhabricatorMetaMTAApplicationEmailPanel ->setTransactionType($type_address) ->setNewValue($v_email); + $xactions[] = id(new PhabricatorMetaMTAApplicationEmailTransaction()) + ->setTransactionType($type_space) + ->setNewValue($v_space); + $xactions[] = id(new PhabricatorMetaMTAApplicationEmailTransaction()) ->setTransactionType($type_config) ->setMetadataValue($key_config, $config_default) @@ -287,6 +220,7 @@ final class PhabricatorMetaMTAApplicationEmailPanel } catch (PhabricatorApplicationTransactionValidationException $ex) { $validation_exception = $ex; $e_email = $ex->getShortMessage($type_address); + $e_space = $ex->getShortMessage($type_space); } } @@ -303,7 +237,22 @@ final class PhabricatorMetaMTAApplicationEmailPanel ->setLabel(pht('Email')) ->setName('email') ->setValue($v_email) - ->setError($e_email)) + ->setError($e_email)); + + if (PhabricatorSpacesNamespaceQuery::getViewerSpacesExist($viewer)) { + $form->appendControl( + id(new AphrontFormSelectControl()) + ->setLabel(pht('Space')) + ->setName('spacePHID') + ->setValue($v_space) + ->setError($e_space) + ->setOptions( + PhabricatorSpacesNamespaceQuery::getSpaceOptionsForViewer( + $viewer, + $v_space))); + } + + $form ->appendControl( id(new AphrontFormTokenizerControl()) ->setDatasource(new PhabricatorPeopleDatasource()) @@ -374,4 +323,85 @@ final class PhabricatorMetaMTAApplicationEmailPanel return id(new AphrontDialogResponse())->setDialog($dialog); } + private function buildEmailTable($is_edit, $highlight) { + $viewer = $this->getViewer(); + $application = $this->getApplication(); + $uri = new PhutilURI($this->getPanelURI()); + + $emails = id(new PhabricatorMetaMTAApplicationEmailQuery()) + ->setViewer($viewer) + ->withApplicationPHIDs(array($application->getPHID())) + ->execute(); + + $rowc = array(); + $rows = array(); + foreach ($emails as $email) { + + $button_edit = javelin_tag( + 'a', + array( + 'class' => 'button small grey', + 'href' => $uri->alter('edit', $email->getID()), + 'sigil' => 'workflow', + ), + pht('Edit')); + + $button_remove = javelin_tag( + 'a', + array( + 'class' => 'button small grey', + 'href' => $uri->alter('delete', $email->getID()), + 'sigil' => 'workflow', + ), + pht('Delete')); + + if ($highlight == $email->getID()) { + $rowc[] = 'highlighted'; + } else { + $rowc[] = null; + } + + $space_phid = PhabricatorSpacesNamespaceQuery::getObjectSpacePHID($email); + if ($space_phid) { + $email_space = $viewer->renderHandle($space_phid); + } else { + $email_space = null; + } + + $rows[] = array( + $email_space, + $email->getAddress(), + $button_edit, + $button_remove, + ); + } + + $table = id(new AphrontTableView($rows)) + ->setNoDataString(pht('No application emails created yet.')); + $table->setHeaders( + array( + pht('Space'), + pht('Email'), + pht('Edit'), + pht('Delete'), + )); + $table->setColumnClasses( + array( + '', + 'wide', + 'action', + 'action', + )); + $table->setRowClasses($rowc); + $table->setColumnVisibility( + array( + PhabricatorSpacesNamespaceQuery::getViewerSpacesExist($viewer), + true, + $is_edit, + $is_edit, + )); + + return $table; + } + } diff --git a/src/applications/metamta/query/PhabricatorMetaMTAApplicationEmailQuery.php b/src/applications/metamta/query/PhabricatorMetaMTAApplicationEmailQuery.php index b173224914..9c0c5d941a 100644 --- a/src/applications/metamta/query/PhabricatorMetaMTAApplicationEmailQuery.php +++ b/src/applications/metamta/query/PhabricatorMetaMTAApplicationEmailQuery.php @@ -35,19 +35,7 @@ final class PhabricatorMetaMTAApplicationEmailQuery } protected function loadPage() { - $table = new PhabricatorMetaMTAApplicationEmail(); - $conn_r = $table->establishConnection('r'); - - $data = queryfx_all( - $conn_r, - 'SELECT * FROM %T appemail %Q %Q %Q %Q', - $table->getTableName(), - $this->buildWhereClause($conn_r), - $this->buildApplicationSearchGroupClause($conn_r), - $this->buildOrderClause($conn_r), - $this->buildLimitClause($conn_r)); - - return $table->loadAllFromArray($data); + return $this->loadStandardPage(new PhabricatorMetaMTAApplicationEmail()); } protected function willFilterPage(array $app_emails) { @@ -71,47 +59,45 @@ final class PhabricatorMetaMTAApplicationEmailQuery return $app_emails; } - protected function buildWhereClause(AphrontDatabaseConnection $conn_r) { - $where = array(); + protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { + $where = parent::buildWhereClauseParts($conn); if ($this->addresses !== null) { $where[] = qsprintf( - $conn_r, + $conn, 'appemail.address IN (%Ls)', $this->addresses); } if ($this->addressPrefix !== null) { $where[] = qsprintf( - $conn_r, + $conn, 'appemail.address LIKE %>', $this->addressPrefix); } if ($this->applicationPHIDs !== null) { $where[] = qsprintf( - $conn_r, + $conn, 'appemail.applicationPHID IN (%Ls)', $this->applicationPHIDs); } if ($this->phids !== null) { $where[] = qsprintf( - $conn_r, + $conn, 'appemail.phid IN (%Ls)', $this->phids); } if ($this->ids !== null) { $where[] = qsprintf( - $conn_r, + $conn, 'appemail.id IN (%Ld)', $this->ids); } - $where[] = $this->buildPagingClause($conn_r); - - return $this->formatWhereClause($where); + return $where; } protected function getPrimaryTableAlias() { diff --git a/src/applications/metamta/storage/PhabricatorMetaMTAApplicationEmail.php b/src/applications/metamta/storage/PhabricatorMetaMTAApplicationEmail.php index bb693c8d98..fb70b377a7 100644 --- a/src/applications/metamta/storage/PhabricatorMetaMTAApplicationEmail.php +++ b/src/applications/metamta/storage/PhabricatorMetaMTAApplicationEmail.php @@ -5,11 +5,13 @@ final class PhabricatorMetaMTAApplicationEmail implements PhabricatorPolicyInterface, PhabricatorApplicationTransactionInterface, - PhabricatorDestructibleInterface { + PhabricatorDestructibleInterface, + PhabricatorSpacesInterface { protected $applicationPHID; protected $address; protected $configData; + protected $spacePHID; private $application = self::ATTACHABLE; @@ -43,6 +45,7 @@ final class PhabricatorMetaMTAApplicationEmail public static function initializeNewAppEmail(PhabricatorUser $actor) { return id(new PhabricatorMetaMTAApplicationEmail()) + ->setSpacePHID($actor->getDefaultSpacePHID()) ->setConfigData(array()); } @@ -143,4 +146,12 @@ final class PhabricatorMetaMTAApplicationEmail $this->delete(); } + +/* -( PhabricatorSpacesInterface )----------------------------------------- */ + + + public function getSpacePHID() { + return $this->spacePHID; + } + } diff --git a/src/applications/paste/storage/PhabricatorPaste.php b/src/applications/paste/storage/PhabricatorPaste.php index da129b8cf4..661701ba09 100644 --- a/src/applications/paste/storage/PhabricatorPaste.php +++ b/src/applications/paste/storage/PhabricatorPaste.php @@ -38,7 +38,8 @@ final class PhabricatorPaste extends PhabricatorPasteDAO ->setTitle('') ->setAuthorPHID($actor->getPHID()) ->setViewPolicy($view_policy) - ->setEditPolicy($edit_policy); + ->setEditPolicy($edit_policy) + ->setSpacePHID($actor->getDefaultSpacePHID()); } public function getURI() { diff --git a/src/applications/pholio/storage/PholioMock.php b/src/applications/pholio/storage/PholioMock.php index aaebed878e..22c1015704 100644 --- a/src/applications/pholio/storage/PholioMock.php +++ b/src/applications/pholio/storage/PholioMock.php @@ -48,7 +48,8 @@ final class PholioMock extends PholioDAO ->attachImages(array()) ->setStatus(self::STATUS_OPEN) ->setViewPolicy($view_policy) - ->setEditPolicy($edit_policy); + ->setEditPolicy($edit_policy) + ->setSpacePHID($actor->getDefaultSpacePHID()); } public function getMonogram() { diff --git a/src/applications/spaces/query/PhabricatorSpacesNamespaceQuery.php b/src/applications/spaces/query/PhabricatorSpacesNamespaceQuery.php index 51ac66130a..65ac146bd0 100644 --- a/src/applications/spaces/query/PhabricatorSpacesNamespaceQuery.php +++ b/src/applications/spaces/query/PhabricatorSpacesNamespaceQuery.php @@ -170,6 +170,31 @@ final class PhabricatorSpacesNamespaceQuery return $spaces; } + public static function getSpaceOptionsForViewer( + PhabricatorUser $viewer, + $space_phid) { + + $viewer_spaces = self::getViewerSpaces($viewer); + + $map = array(); + foreach ($viewer_spaces as $space) { + + // Skip archived spaces, unless the object is already in that space. + if ($space->getIsArchived()) { + if ($space->getPHID() != $space_phid) { + continue; + } + } + + $map[$space->getPHID()] = pht( + 'Space %s: %s', + $space->getMonogram(), + $space->getNamespaceName()); + } + asort($map); + + return $map; + } /** diff --git a/src/applications/transactions/replyhandler/PhabricatorApplicationTransactionReplyHandler.php b/src/applications/transactions/replyhandler/PhabricatorApplicationTransactionReplyHandler.php index 14e27edc73..82f3eca2cc 100644 --- a/src/applications/transactions/replyhandler/PhabricatorApplicationTransactionReplyHandler.php +++ b/src/applications/transactions/replyhandler/PhabricatorApplicationTransactionReplyHandler.php @@ -56,6 +56,22 @@ abstract class PhabricatorApplicationTransactionReplyHandler final protected function receiveEmail(PhabricatorMetaMTAReceivedMail $mail) { $viewer = $this->getActor(); $object = $this->getMailReceiver(); + $app_email = $this->getApplicationEmail(); + + $is_new = !$object->getID(); + + // If this is a new object which implements the Spaces interface and was + // created by sending mail to an ApplicationEmail address, put the object + // in the same Space the address is in. + if ($is_new) { + if ($object instanceof PhabricatorSpacesInterface) { + if ($app_email) { + $space_phid = PhabricatorSpacesNamespaceQuery::getObjectSpacePHID( + $app_email); + $object->setSpacePHID($space_phid); + } + } + } $body_data = $mail->parseBody(); $body = $body_data['body']; diff --git a/src/view/form/control/AphrontFormPolicyControl.php b/src/view/form/control/AphrontFormPolicyControl.php index 58d06cc5de..46dde71826 100644 --- a/src/view/form/control/AphrontFormPolicyControl.php +++ b/src/view/form/control/AphrontFormPolicyControl.php @@ -265,7 +265,9 @@ final class AphrontFormPolicyControl extends AphrontFormControl { $select = AphrontFormSelectControl::renderSelectTag( $space_phid, - $this->getSpaceOptions($space_phid), + PhabricatorSpacesNamespaceQuery::getSpaceOptionsForViewer( + $viewer, + $space_phid), array( 'name' => 'spacePHID', )); @@ -273,27 +275,4 @@ final class AphrontFormPolicyControl extends AphrontFormControl { return $select; } - protected function getSpaceOptions($space_phid) { - $viewer = $this->getUser(); - $viewer_spaces = PhabricatorSpacesNamespaceQuery::getViewerSpaces($viewer); - - $map = array(); - foreach ($viewer_spaces as $space) { - - // Skip archived spaces, unless the object is already in that space. - if ($space->getIsArchived()) { - if ($space->getPHID() != $space_phid) { - continue; - } - } - - $map[$space->getPHID()] = pht( - 'Space %s: %s', - $space->getMonogram(), - $space->getNamespaceName()); - } - asort($map); - - return $map; - } } From b978f576be7582475186f431076165f34685a866 Mon Sep 17 00:00:00 2001 From: epriestley Date: Thu, 11 Jun 2015 10:24:25 -0700 Subject: [PATCH 16/50] Add some documentation for Spaces Summary: Ref T8449. Flesh out the documentation a bit. Test Plan: Reading. Reviewers: btrahan Reviewed By: btrahan Subscribers: epriestley Maniphest Tasks: T8449 Differential Revision: https://secure.phabricator.com/D13248 --- src/docs/user/userguide/spaces.diviner | 142 +++++++++++++++++++++++++ 1 file changed, 142 insertions(+) diff --git a/src/docs/user/userguide/spaces.diviner b/src/docs/user/userguide/spaces.diviner index 9026edf86e..907e079736 100644 --- a/src/docs/user/userguide/spaces.diviner +++ b/src/docs/user/userguide/spaces.diviner @@ -8,6 +8,99 @@ Overview IMPORTANT: Spaces is a prototype application. +The Spaces application makes it easier to manage large groups of objects which +share the same access policy. For example: + + - An organization might make a Space for a project in order to satisfy a + contractual obligation to limit access, even internally. + - An open source organization might make a Space for work related to + internal governance, to separate private and public discussions. + - A contracting company might make Spaces for clients, to separate them from + one another. + - A company might create a Space for consultants, to give them limited + access to only the resources they need to do their work. + - An ambitious manager might create a Space to hide her team's work from her + enemies at the company, that she might use the element of surprise to later + expand her domain. + +Phabricator's access control policies are generally powerful enough to handle +these use cases on their own, but applying the same policy to a large group +of objects requires a lot of effort and is error-prone. + +Spaces build on top of policies and make it easier and more reliable to +configure, review, and manage groups of objects with similar policies. + + +Creating Spaces +================= + +Spaces are optional, and are inactive by default. You don't need to configure +them if you don't plan to use them. You can always set them up later. + +To activate Spaces, you need to create at least two spaces. Create spaces from +the web UI, by navigating to {nav Spaces > Create Space}. By default, only +administrators can create new Spaces, but you can configure this in the +{nav Applications} application. + +The first Space you create will be a special "default" Space, and all existing +objects will be shifted into this space as soon as you create it. Spaces you +create later will be normal spaces, and begin with no objects inside them. + +Create the first space (you may want to name it something like "Default" or +"Global" or "Public", depending on the nature of your organization), then +create a second Space. Usually, the second space will be something like +"Secret Plans" and have a more restrictive "Visible To" policy. + + +Using Spaces +============ + +Once you've created at least two spaces, you can begin using them. + +Application UIs will change for users who can see at least two Spaces, opening +up new controls which let them work with spaces. They will now be able to +choose which space to create new objects into, be able to move objects between +spaces, and be able to search for objects in a specific space or set of spaces. + +In list and detail views, objects will show which space they're in if they're +in a non-default space. + +Users with access to only one space won't see these controls, even if many +spaces exist. This simplifies the UI for users with limited access. + + +Space Policies +============== + +Briefly, Spaces affect policies like this: + + - Spaces apply their view policy to all objects inside the space. + - Space policies are absolute, and stronger than all other policies. A + user who can not see a Space can **never** see objects inside the space. + - Normal policies are still checked: spaces can only reduce access. + +When you create a Space, you choose a view policy for that space by using the +**Visible To** control. This policy controls both who can see the space, and +who can see objects inside the space. + +Spaces apply their view policy to all objects inside the space: if you can't +see a space, you can never see objects inside it. This policy check is absolute +and stronger than all other policy rules, including policy exceptions. + +For example, a user can never see a task in a space they can't see, even if +they are an admin and the author and owner of the task, and subscribed to the +task and the view and edit policies are set to "All Users", and they created +the Space originally and the moon is full and they are pure of heart and +possessed of the noblest purpose. Spaces are impenetrable. + +Even if a user satisfies the view policy for a space, they must still pass the +view policy on the object: the space check is a new check in addition to any +check on the object, and can only limit access. + +The edit poilcy for a space only affects the Space itself, and is not applied +to objects inside the space. + + Archiving Spaces ================ @@ -25,3 +118,52 @@ space, use the `Spaces` constraint to specifically search for objects in that space. You can reactivate a space later by choosing {nav Activate Space}. + + +Application Email +================= + +After activating Spaces, you can choose a Space when configuring inbound email +addresses in {nav Applications}. + +Spaces affect policies for application email just like they do for other +objects: to see or use the address, you must be able to see the space which +contains it. + +Objects created from inbound email will be created in the Space the email is +associated with. + + +Limitations and Caveats +======================= + +Some information is shared between spaces, so they do not completely isolate +users from other activity on the install. This section discusses limitations +of the isolation model. Most of these limitations are intrinsic to the policy +model Phabricator uses. + +**Shared IDs**: Spaces do not have unique object IDs: there is only one `T1`, +not a separate one in each space. It can be moved between spaces, but `T1` +always refers to the same object. In most cases, this makes working with +spaces simpler and easier. + +However, because IDs are shared, users in any space can look at object IDs to +determine how many objects exist in other spaces, even if they can't see those +objects. If a user creates a new task and sees that it is `T5000`, they can +know that there are 4,999 other tasks they don't have permission to see. + +**Globally Unique Values**: Some values (like usernames, email addresses, +project hashtags, repository callsigns, and application emails) must be +globally unique. + +As with normal policies, users may be able to determine that a `#yolo` project +exists, even if they can't see it: they can try to create a project using the +`#yolo` hashtag, and will receive an error if it is a duplicate. + +**User Accounts**: Spaces do not apply to users, and can not hide the existence +of user accounts. + +For example, if you are a contracting company and have Coke and Pepsi as +clients, the CEO of Coke and the CEO of Pepsi will each be able to see that the +other has an account on the install, even if all the work you are doing for +them is separated into "Coke" and "Pepsi" spaces. From 4faef88376f2c139d4507015a721f6ccf698d996 Mon Sep 17 00:00:00 2001 From: epriestley Date: Thu, 11 Jun 2015 10:24:39 -0700 Subject: [PATCH 17/50] Support Spaces in Maniphest batch editor Summary: Ref T8498. This editor is an artifact of the Old World at this point, but it still works fine. Test Plan: Moved tasks between spaces using the batch editor. Reviewers: btrahan Reviewed By: btrahan Subscribers: epriestley Maniphest Tasks: T8498 Differential Revision: https://secure.phabricator.com/D13249 --- resources/celerity/map.php | 20 +++++++++---------- .../ManiphestBatchEditController.php | 19 ++++++++++++++++++ .../maniphest/behavior-batch-editor.js | 10 +++++++++- 3 files changed, 38 insertions(+), 11 deletions(-) diff --git a/resources/celerity/map.php b/resources/celerity/map.php index 04034037e6..48478682fe 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -374,7 +374,7 @@ return array( 'rsrc/js/application/herald/HeraldRuleEditor.js' => 'b2cae298', 'rsrc/js/application/herald/PathTypeahead.js' => 'f7fc67ec', 'rsrc/js/application/herald/herald-rule-editor.js' => '7ebaeed3', - 'rsrc/js/application/maniphest/behavior-batch-editor.js' => 'f5d1233b', + 'rsrc/js/application/maniphest/behavior-batch-editor.js' => '782ab6e7', 'rsrc/js/application/maniphest/behavior-batch-selector.js' => '7b98d7c5', 'rsrc/js/application/maniphest/behavior-line-chart.js' => '88f0c5b3', 'rsrc/js/application/maniphest/behavior-list-edit.js' => 'a9f88de2', @@ -587,7 +587,7 @@ return array( 'javelin-behavior-lightbox-attachments' => 'f8ba29d7', 'javelin-behavior-line-chart' => '88f0c5b3', 'javelin-behavior-load-blame' => '42126667', - 'javelin-behavior-maniphest-batch-editor' => 'f5d1233b', + 'javelin-behavior-maniphest-batch-editor' => '782ab6e7', 'javelin-behavior-maniphest-batch-selector' => '7b98d7c5', 'javelin-behavior-maniphest-list-editor' => 'a9f88de2', 'javelin-behavior-maniphest-subpriority-editor' => '84845b5b', @@ -1385,6 +1385,14 @@ return array( 'javelin-util', 'phabricator-busy', ), + '782ab6e7' => array( + 'javelin-behavior', + 'javelin-dom', + 'javelin-util', + 'phabricator-prefab', + 'multirow-row-manager', + 'javelin-json', + ), '7927a7d3' => array( 'javelin-behavior', 'javelin-quicksand', @@ -1967,14 +1975,6 @@ return array( 'javelin-request', 'phabricator-keyboard-shortcut', ), - 'f5d1233b' => array( - 'javelin-behavior', - 'javelin-dom', - 'javelin-util', - 'phabricator-prefab', - 'multirow-row-manager', - 'javelin-json', - ), 'f6555212' => array( 'javelin-install', 'javelin-reactornode', diff --git a/src/applications/maniphest/controller/ManiphestBatchEditController.php b/src/applications/maniphest/controller/ManiphestBatchEditController.php index a4bf77ef14..2859eaae57 100644 --- a/src/applications/maniphest/controller/ManiphestBatchEditController.php +++ b/src/applications/maniphest/controller/ManiphestBatchEditController.php @@ -88,6 +88,8 @@ final class ManiphestBatchEditController extends ManiphestController { $mailable_source->setViewer($viewer); $owner_source = new ManiphestAssigneeDatasource(); $owner_source->setViewer($viewer); + $spaces_source = id(new PhabricatorSpacesNamespaceDatasource()) + ->setViewer($viewer); require_celerity_resource('maniphest-batch-editor'); Javelin::initBehavior( @@ -112,6 +114,12 @@ final class ManiphestBatchEditController extends ManiphestController { 'placeholder' => $mailable_source->getPlaceholderText(), 'browseURI' => $mailable_source->getBrowseURI(), ), + 'spaces' => array( + 'src' => $spaces_source->getDatasourceURI(), + 'placeholder' => $spaces_source->getPlaceholderText(), + 'browseURI' => $spaces_source->getBrowseURI(), + 'limit' => 1, + ), ), 'input' => 'batch-form-actions', 'priorityMap' => ManiphestTaskPriority::getTaskPriorityMap(), @@ -201,6 +209,7 @@ final class ManiphestBatchEditController extends ManiphestController { 'remove_project' => PhabricatorTransactions::TYPE_EDGE, 'add_ccs' => PhabricatorTransactions::TYPE_SUBSCRIBERS, 'remove_ccs' => PhabricatorTransactions::TYPE_SUBSCRIBERS, + 'space' => PhabricatorTransactions::TYPE_SPACE, ); $edge_edit_types = array( @@ -246,6 +255,10 @@ final class ManiphestBatchEditController extends ManiphestController { case PhabricatorTransactions::TYPE_SUBSCRIBERS: $current = $task->getSubscriberPHIDs(); break; + case PhabricatorTransactions::TYPE_SPACE: + $current = PhabricatorSpacesNamespaceQuery::getObjectSpacePHID( + $task); + break; } } @@ -260,6 +273,12 @@ final class ManiphestBatchEditController extends ManiphestController { continue 2; } break; + case PhabricatorTransactions::TYPE_SPACE: + if (empty($value)) { + continue 2; + } + $value = head($value); + break; case ManiphestTransaction::TYPE_OWNER: if (empty($value)) { continue 2; diff --git a/webroot/rsrc/js/application/maniphest/behavior-batch-editor.js b/webroot/rsrc/js/application/maniphest/behavior-batch-editor.js index 5cf568ce2c..ad2cf32d9e 100644 --- a/webroot/rsrc/js/application/maniphest/behavior-batch-editor.js +++ b/webroot/rsrc/js/application/maniphest/behavior-batch-editor.js @@ -24,12 +24,14 @@ JX.behavior('maniphest-batch-editor', function(config) { 'add_comment': 'Comment', 'assign': 'Assign', 'add_ccs' : 'Add CCs', - 'remove_ccs' : 'Remove CCs' + 'remove_ccs' : 'Remove CCs', + 'space': 'Shift to Space' }); var proj_tokenizer = build_tokenizer(config.sources.project); var owner_tokenizer = build_tokenizer(config.sources.owner); var cc_tokenizer = build_tokenizer(config.sources.cc); + var space_tokenizer = build_tokenizer(config.sources.spaces); var priority_select = JX.Prefab.renderSelect(config.priorityMap); var status_select = JX.Prefab.renderSelect(config.statusMap); @@ -60,6 +62,12 @@ JX.behavior('maniphest-batch-editor', function(config) { return JX.keys(owner_tokenizer.object.getTokens()); }; break; + case 'space': + JX.DOM.setContent(cell, space_tokenizer.template); + vfunc = function() { + return JX.keys(space_tokenizer.object.getTokens()); + }; + break; case 'add_comment': JX.DOM.setContent(cell, comment_input); vfunc = function() { From 643b90008f9f20fc79c0f4ba818092c65b31ead4 Mon Sep 17 00:00:00 2001 From: lkassianik Date: Thu, 11 Jun 2015 10:57:11 -0700 Subject: [PATCH 18/50] Fix query frequency unit and change time preference from input to dropdown. Summary: Ref T8362, Fix query frequency unit and change time preference from input to dropdown. Test Plan: Change user time preference in Date Time Settings panel, open feed, observe new time stamps. Reviewers: #blessed_reviewers, epriestley Reviewed By: #blessed_reviewers, epriestley Subscribers: epriestley, Korvin Maniphest Tasks: T8362 Differential Revision: https://secure.phabricator.com/D13236 --- .../storage/PhabricatorCalendarEvent.php | 2 +- .../PhabricatorDateTimeSettingsPanel.php | 19 +++++-------------- 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/src/applications/calendar/storage/PhabricatorCalendarEvent.php b/src/applications/calendar/storage/PhabricatorCalendarEvent.php index ea6c6a48ef..f12bf9a9c3 100644 --- a/src/applications/calendar/storage/PhabricatorCalendarEvent.php +++ b/src/applications/calendar/storage/PhabricatorCalendarEvent.php @@ -316,7 +316,7 @@ final class PhabricatorCalendarEvent extends PhabricatorCalendarDAO case 'monthly': return 'month'; case 'yearly': - return 'yearly'; + return 'year'; default: return 'day'; } diff --git a/src/applications/settings/panel/PhabricatorDateTimeSettingsPanel.php b/src/applications/settings/panel/PhabricatorDateTimeSettingsPanel.php index 5fbf825d22..45f9f3fa01 100644 --- a/src/applications/settings/panel/PhabricatorDateTimeSettingsPanel.php +++ b/src/applications/settings/panel/PhabricatorDateTimeSettingsPanel.php @@ -58,23 +58,14 @@ final class PhabricatorDateTimeSettingsPanel extends PhabricatorSettingsPanel { ->setName('timezone') ->setOptions($timezone_id_map) ->setValue($user->getTimezoneIdentifier())) - ->appendRemarkupInstructions( - pht( - "**Custom Date and Time Formats**\n\n". - "You can specify custom formats which will be used when ". - "rendering dates and times of day. Examples:\n\n". - "| Format | Example | Notes |\n". - "| ------ | -------- | ----- |\n". - "| `g:i A` | 2:34 PM | Default 12-hour time. |\n". - "| `G.i a` | 02.34 pm | Alternate 12-hour time. |\n". - "| `H:i` | 14:34 | 24-hour time. |\n". - "\n\n". - "You can find a [[%s | full reference in the PHP manual]].", - 'http://www.php.net/manual/en/function.date.php')) ->appendChild( - id(new AphrontFormTextControl()) + id(new AphrontFormSelectControl()) ->setLabel(pht('Time-of-Day Format')) ->setName($pref_time) + ->setOptions(array( + 'g:i A' => pht('12-hour (2:34 PM)'), + 'H:i' => pht('24-hour (14:34)'), + )) ->setCaption( pht('Format used when rendering a time of day.')) ->setValue($preferences->getPreference($pref_time))) From 52f8756c3c7c0db13515e96f73784428e4ae12b5 Mon Sep 17 00:00:00 2001 From: epriestley Date: Thu, 11 Jun 2015 13:25:30 -0700 Subject: [PATCH 19/50] Add a "template" parameter to application default policies Summary: Ref T5681. Ref T6860. This doesn't do anything interesting on its own, just makes the next diff smaller. In the next diff, policies become aware of the types of objects they're acting on. We need to specify which object type all the "Default View/Edit" settings are for so they get the right rules. For example, a rule like "Allow task author" is OK for "View Policy" on a task, and also OK for "Default View Policy" on ManiphestApplication. But it's not OK for "Can Create Tasks" on ManiphestApplication. So annotate all the "template"/"default" policies with their types. The next diff will use these to let you select appropriate rules for the given object type. Test Plan: - Used `grep` to find these. - This change has no effect. Reviewers: btrahan Reviewed By: btrahan Subscribers: epriestley Maniphest Tasks: T5681, T6860 Differential Revision: https://secure.phabricator.com/D13251 --- src/applications/base/PhabricatorApplication.php | 5 +++++ .../application/PhabricatorCountdownApplication.php | 1 + .../PhabricatorDifferentialApplication.php | 1 + .../application/PhabricatorDiffusionApplication.php | 9 +++++++-- .../application/PhabricatorDrydockApplication.php | 5 ++++- .../application/PhabricatorFilesApplication.php | 1 + .../fund/application/PhabricatorFundApplication.php | 1 + .../application/PhabricatorLegalpadApplication.php | 8 ++++++-- .../application/PhabricatorManiphestApplication.php | 2 ++ .../application/PhabricatorNuanceApplication.php | 2 ++ .../application/PhabricatorPasteApplication.php | 2 ++ .../application/PhabricatorPholioApplication.php | 8 ++++++-- .../application/PhabricatorProjectApplication.php | 12 ++++++------ .../application/PhabricatorSlowvoteApplication.php | 1 + .../application/PhabricatorSpacesApplication.php | 2 ++ 15 files changed, 47 insertions(+), 13 deletions(-) diff --git a/src/applications/base/PhabricatorApplication.php b/src/applications/base/PhabricatorApplication.php index 4c176641b0..a021b5f1c6 100644 --- a/src/applications/base/PhabricatorApplication.php +++ b/src/applications/base/PhabricatorApplication.php @@ -582,6 +582,11 @@ abstract class PhabricatorApplication implements PhabricatorPolicyInterface { } } + public function getCapabilityTemplatePHIDType($capability) { + $spec = $this->getCustomCapabilitySpecification($capability); + return idx($spec, 'template'); + } + public function getApplicationSearchDocumentTypes() { return array(); } diff --git a/src/applications/countdown/application/PhabricatorCountdownApplication.php b/src/applications/countdown/application/PhabricatorCountdownApplication.php index 5c00661bd0..24e796a4a6 100644 --- a/src/applications/countdown/application/PhabricatorCountdownApplication.php +++ b/src/applications/countdown/application/PhabricatorCountdownApplication.php @@ -52,6 +52,7 @@ final class PhabricatorCountdownApplication extends PhabricatorApplication { return array( PhabricatorCountdownDefaultViewCapability::CAPABILITY => array( 'caption' => pht('Default view policy for new countdowns.'), + 'template' => PhabricatorCountdownCountdownPHIDType::TYPECONST, ), ); } diff --git a/src/applications/differential/application/PhabricatorDifferentialApplication.php b/src/applications/differential/application/PhabricatorDifferentialApplication.php index 7bbe133427..d73236668a 100644 --- a/src/applications/differential/application/PhabricatorDifferentialApplication.php +++ b/src/applications/differential/application/PhabricatorDifferentialApplication.php @@ -186,6 +186,7 @@ final class PhabricatorDifferentialApplication extends PhabricatorApplication { return array( DifferentialDefaultViewCapability::CAPABILITY => array( 'caption' => pht('Default view policy for newly created revisions.'), + 'template' => DifferentialRevisionPHIDType::TYPECONST, ), ); } diff --git a/src/applications/diffusion/application/PhabricatorDiffusionApplication.php b/src/applications/diffusion/application/PhabricatorDiffusionApplication.php index 0f44db3d13..271efc2a53 100644 --- a/src/applications/diffusion/application/PhabricatorDiffusionApplication.php +++ b/src/applications/diffusion/application/PhabricatorDiffusionApplication.php @@ -140,11 +140,16 @@ final class PhabricatorDiffusionApplication extends PhabricatorApplication { protected function getCustomCapabilities() { return array( - DiffusionDefaultViewCapability::CAPABILITY => array(), + DiffusionDefaultViewCapability::CAPABILITY => array( + 'template' => PhabricatorRepositoryRepositoryPHIDType::TYPECONST, + ), DiffusionDefaultEditCapability::CAPABILITY => array( 'default' => PhabricatorPolicies::POLICY_ADMIN, + 'template' => PhabricatorRepositoryRepositoryPHIDType::TYPECONST, + ), + DiffusionDefaultPushCapability::CAPABILITY => array( + 'template' => PhabricatorRepositoryRepositoryPHIDType::TYPECONST, ), - DiffusionDefaultPushCapability::CAPABILITY => array(), DiffusionCreateRepositoriesCapability::CAPABILITY => array( 'default' => PhabricatorPolicies::POLICY_ADMIN, ), diff --git a/src/applications/drydock/application/PhabricatorDrydockApplication.php b/src/applications/drydock/application/PhabricatorDrydockApplication.php index b2c758b563..6e7b0fcfdc 100644 --- a/src/applications/drydock/application/PhabricatorDrydockApplication.php +++ b/src/applications/drydock/application/PhabricatorDrydockApplication.php @@ -72,9 +72,12 @@ final class PhabricatorDrydockApplication extends PhabricatorApplication { protected function getCustomCapabilities() { return array( - DrydockDefaultViewCapability::CAPABILITY => array(), + DrydockDefaultViewCapability::CAPABILITY => array( + 'template' => DrydockBlueprintPHIDType::TYPECONST, + ), DrydockDefaultEditCapability::CAPABILITY => array( 'default' => PhabricatorPolicies::POLICY_ADMIN, + 'template' => DrydockBlueprintPHIDType::TYPECONST, ), DrydockCreateBlueprintsCapability::CAPABILITY => array( 'default' => PhabricatorPolicies::POLICY_ADMIN, diff --git a/src/applications/files/application/PhabricatorFilesApplication.php b/src/applications/files/application/PhabricatorFilesApplication.php index b80a8e1ae4..1714719f8e 100644 --- a/src/applications/files/application/PhabricatorFilesApplication.php +++ b/src/applications/files/application/PhabricatorFilesApplication.php @@ -60,6 +60,7 @@ final class PhabricatorFilesApplication extends PhabricatorApplication { return array( FilesDefaultViewCapability::CAPABILITY => array( 'caption' => pht('Default view policy for newly created files.'), + 'template' => PhabricatorFileFilePHIDType::TYPECONST, ), ); } diff --git a/src/applications/fund/application/PhabricatorFundApplication.php b/src/applications/fund/application/PhabricatorFundApplication.php index 57997a1611..ed36cc783b 100644 --- a/src/applications/fund/application/PhabricatorFundApplication.php +++ b/src/applications/fund/application/PhabricatorFundApplication.php @@ -55,6 +55,7 @@ final class PhabricatorFundApplication extends PhabricatorApplication { return array( FundDefaultViewCapability::CAPABILITY => array( 'caption' => pht('Default view policy for newly created initiatives.'), + 'tempate' => FundInitiativePHIDType::TYPECONST, ), FundCreateInitiativesCapability::CAPABILITY => array( 'default' => PhabricatorPolicies::POLICY_ADMIN, diff --git a/src/applications/legalpad/application/PhabricatorLegalpadApplication.php b/src/applications/legalpad/application/PhabricatorLegalpadApplication.php index d7f7e0ceeb..e1394e0507 100644 --- a/src/applications/legalpad/application/PhabricatorLegalpadApplication.php +++ b/src/applications/legalpad/application/PhabricatorLegalpadApplication.php @@ -75,8 +75,12 @@ final class PhabricatorLegalpadApplication extends PhabricatorApplication { protected function getCustomCapabilities() { return array( LegalpadCreateDocumentsCapability::CAPABILITY => array(), - LegalpadDefaultViewCapability::CAPABILITY => array(), - LegalpadDefaultEditCapability::CAPABILITY => array(), + LegalpadDefaultViewCapability::CAPABILITY => array( + 'template' => PhabricatorLegalpadDocumentPHIDType::TYPECONST, + ), + LegalpadDefaultEditCapability::CAPABILITY => array( + 'template' => PhabricatorLegalpadDocumentPHIDType::TYPECONST, + ), ); } diff --git a/src/applications/maniphest/application/PhabricatorManiphestApplication.php b/src/applications/maniphest/application/PhabricatorManiphestApplication.php index 3937d6be7f..3debdb44ca 100644 --- a/src/applications/maniphest/application/PhabricatorManiphestApplication.php +++ b/src/applications/maniphest/application/PhabricatorManiphestApplication.php @@ -131,9 +131,11 @@ final class PhabricatorManiphestApplication extends PhabricatorApplication { return array( ManiphestDefaultViewCapability::CAPABILITY => array( 'caption' => pht('Default view policy for newly created tasks.'), + 'template' => ManiphestTaskPHIDType::TYPECONST, ), ManiphestDefaultEditCapability::CAPABILITY => array( 'caption' => pht('Default edit policy for newly created tasks.'), + 'template' => ManiphestTaskPHIDType::TYPECONST, ), ManiphestEditStatusCapability::CAPABILITY => array(), ManiphestEditAssignCapability::CAPABILITY => array(), diff --git a/src/applications/nuance/application/PhabricatorNuanceApplication.php b/src/applications/nuance/application/PhabricatorNuanceApplication.php index be297f4026..20c58f841c 100644 --- a/src/applications/nuance/application/PhabricatorNuanceApplication.php +++ b/src/applications/nuance/application/PhabricatorNuanceApplication.php @@ -72,9 +72,11 @@ final class PhabricatorNuanceApplication extends PhabricatorApplication { return array( NuanceSourceDefaultViewCapability::CAPABILITY => array( 'caption' => pht('Default view policy for newly created sources.'), + 'template' => NuanceSourcePHIDType::TYPECONST, ), NuanceSourceDefaultEditCapability::CAPABILITY => array( 'caption' => pht('Default edit policy for newly created sources.'), + 'template' => NuanceSourcePHIDType::TYPECONST, ), NuanceSourceManageCapability::CAPABILITY => array(), ); diff --git a/src/applications/paste/application/PhabricatorPasteApplication.php b/src/applications/paste/application/PhabricatorPasteApplication.php index c0afe865bf..f9cd03dd74 100644 --- a/src/applications/paste/application/PhabricatorPasteApplication.php +++ b/src/applications/paste/application/PhabricatorPasteApplication.php @@ -64,9 +64,11 @@ final class PhabricatorPasteApplication extends PhabricatorApplication { return array( PasteDefaultViewCapability::CAPABILITY => array( 'caption' => pht('Default view policy for newly created pastes.'), + 'template' => PhabricatorPastePastePHIDType::TYPECONST, ), PasteDefaultEditCapability::CAPABILITY => array( 'caption' => pht('Default edit policy for newly created pastes.'), + 'template' => PhabricatorPastePastePHIDType::TYPECONST, ), ); } diff --git a/src/applications/pholio/application/PhabricatorPholioApplication.php b/src/applications/pholio/application/PhabricatorPholioApplication.php index 801a2de4e8..52309ba078 100644 --- a/src/applications/pholio/application/PhabricatorPholioApplication.php +++ b/src/applications/pholio/application/PhabricatorPholioApplication.php @@ -71,8 +71,12 @@ final class PhabricatorPholioApplication extends PhabricatorApplication { protected function getCustomCapabilities() { return array( - PholioDefaultViewCapability::CAPABILITY => array(), - PholioDefaultEditCapability::CAPABILITY => array(), + PholioDefaultViewCapability::CAPABILITY => array( + 'template' => PholioMockPHIDType::TYPECONST, + ), + PholioDefaultEditCapability::CAPABILITY => array( + 'template' => PholioMockPHIDType::TYPECONST, + ), ); } diff --git a/src/applications/project/application/PhabricatorProjectApplication.php b/src/applications/project/application/PhabricatorProjectApplication.php index e7e4f623f9..adf6378e2a 100644 --- a/src/applications/project/application/PhabricatorProjectApplication.php +++ b/src/applications/project/application/PhabricatorProjectApplication.php @@ -119,16 +119,16 @@ final class PhabricatorProjectApplication extends PhabricatorApplication { 'default' => PhabricatorPolicies::POLICY_ADMIN, ), ProjectDefaultViewCapability::CAPABILITY => array( - 'caption' => pht( - 'Default view policy for newly created projects.'), + 'caption' => pht('Default view policy for newly created projects.'), + 'template' => PhabricatorProjectProjectPHIDType::TYPECONST, ), ProjectDefaultEditCapability::CAPABILITY => array( - 'caption' => pht( - 'Default edit policy for newly created projects.'), + 'caption' => pht('Default edit policy for newly created projects.'), + 'template' => PhabricatorProjectProjectPHIDType::TYPECONST, ), ProjectDefaultJoinCapability::CAPABILITY => array( - 'caption' => pht( - 'Default join policy for newly created projects.'), + 'caption' => pht('Default join policy for newly created projects.'), + 'template' => PhabricatorProjectProjectPHIDType::TYPECONST, ), ); } diff --git a/src/applications/slowvote/application/PhabricatorSlowvoteApplication.php b/src/applications/slowvote/application/PhabricatorSlowvoteApplication.php index fa3acfd779..40791659b1 100644 --- a/src/applications/slowvote/application/PhabricatorSlowvoteApplication.php +++ b/src/applications/slowvote/application/PhabricatorSlowvoteApplication.php @@ -64,6 +64,7 @@ final class PhabricatorSlowvoteApplication extends PhabricatorApplication { return array( PhabricatorSlowvoteDefaultViewCapability::CAPABILITY => array( 'caption' => pht('Default view policy for new polls.'), + 'template' => PhabricatorSlowvotePollPHIDType::TYPECONST, ), ); } diff --git a/src/applications/spaces/application/PhabricatorSpacesApplication.php b/src/applications/spaces/application/PhabricatorSpacesApplication.php index 0e25120626..7942caf919 100644 --- a/src/applications/spaces/application/PhabricatorSpacesApplication.php +++ b/src/applications/spaces/application/PhabricatorSpacesApplication.php @@ -73,10 +73,12 @@ final class PhabricatorSpacesApplication extends PhabricatorApplication { ), PhabricatorSpacesCapabilityDefaultView::CAPABILITY => array( 'caption' => pht('Default view policy for newly created spaces.'), + 'template' => PhabricatorSpacesNamespacePHIDType::TYPECONST, ), PhabricatorSpacesCapabilityDefaultEdit::CAPABILITY => array( 'caption' => pht('Default edit policy for newly created spaces.'), 'default' => PhabricatorPolicies::POLICY_ADMIN, + 'template' => PhabricatorSpacesNamespacePHIDType::TYPECONST, ), ); } From 92e868c2fef9350983f8d03555087cea4872584b Mon Sep 17 00:00:00 2001 From: Joshua Spence Date: Fri, 12 Jun 2015 17:32:00 +1000 Subject: [PATCH 20/50] Disable the "Edit Project" button for users without edit permissions Summary: Self-explanatory. Test Plan: Viewed the project page as a user without edit permissions and saw the link greyed out. Reviewers: epriestley, #blessed_reviewers Reviewed By: epriestley, #blessed_reviewers Subscribers: epriestley, Korvin Differential Revision: https://secure.phabricator.com/D13255 --- .../project/controller/PhabricatorProjectProfileController.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/applications/project/controller/PhabricatorProjectProfileController.php b/src/applications/project/controller/PhabricatorProjectProfileController.php index cb8fe9e87f..2420297c2f 100644 --- a/src/applications/project/controller/PhabricatorProjectProfileController.php +++ b/src/applications/project/controller/PhabricatorProjectProfileController.php @@ -91,7 +91,8 @@ final class PhabricatorProjectProfileController id(new PhabricatorActionView()) ->setName(pht('Edit Details')) ->setIcon('fa-pencil') - ->setHref($this->getApplicationURI("details/{$id}/"))); + ->setHref($this->getApplicationURI("details/{$id}/")) + ->setDisabled(!$can_edit)); $view->addAction( id(new PhabricatorActionView()) From 034debede68b091bb97bd587fe5db64e074f604b Mon Sep 17 00:00:00 2001 From: Jamison Lofthouse Date: Fri, 12 Jun 2015 13:46:36 -0700 Subject: [PATCH 21/50] Fix typo in Spaces documentation Summary: Fixed typo of the word "policy" Test Plan: Google: "define policy" and see spelling Reviewers: #blessed_reviewers, epriestley Reviewed By: #blessed_reviewers, epriestley Subscribers: epriestley, Korvin Projects: #spaces Differential Revision: https://secure.phabricator.com/D13263 --- src/docs/user/userguide/spaces.diviner | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/docs/user/userguide/spaces.diviner b/src/docs/user/userguide/spaces.diviner index 907e079736..230fa2ddc5 100644 --- a/src/docs/user/userguide/spaces.diviner +++ b/src/docs/user/userguide/spaces.diviner @@ -97,7 +97,7 @@ Even if a user satisfies the view policy for a space, they must still pass the view policy on the object: the space check is a new check in addition to any check on the object, and can only limit access. -The edit poilcy for a space only affects the Space itself, and is not applied +The edit policy for a space only affects the Space itself, and is not applied to objects inside the space. From ee8de4a9ec550adc6424a0e05c5f26a6cccd1922 Mon Sep 17 00:00:00 2001 From: epriestley Date: Sat, 13 Jun 2015 06:53:36 -0700 Subject: [PATCH 22/50] Fix an issue with `{M13}` and Spaces Fixes T8529. These elements now need a viewer/object to render Spaces. Auditors: btrahan --- src/applications/pholio/remarkup/PholioRemarkupRule.php | 3 +++ src/applications/pholio/view/PholioMockEmbedView.php | 2 ++ 2 files changed, 5 insertions(+) diff --git a/src/applications/pholio/remarkup/PholioRemarkupRule.php b/src/applications/pholio/remarkup/PholioRemarkupRule.php index 2b1ca0f876..00025b6326 100644 --- a/src/applications/pholio/remarkup/PholioRemarkupRule.php +++ b/src/applications/pholio/remarkup/PholioRemarkupRule.php @@ -64,7 +64,10 @@ final class PholioRemarkupRule extends PhabricatorObjectRemarkupRule { PhabricatorObjectHandle $handle, $options) { + $viewer = $this->getEngine()->getConfig('viewer'); + $embed_mock = id(new PholioMockEmbedView()) + ->setUser($viewer) ->setMock($object); if (strlen($options)) { diff --git a/src/applications/pholio/view/PholioMockEmbedView.php b/src/applications/pholio/view/PholioMockEmbedView.php index 3429cfd569..88f2f2ac55 100644 --- a/src/applications/pholio/view/PholioMockEmbedView.php +++ b/src/applications/pholio/view/PholioMockEmbedView.php @@ -47,6 +47,8 @@ final class PholioMockEmbedView extends AphrontView { list($x, $y) = $xform->getTransformedDimensions($thumbfile); $item = id(new PHUIPinboardItemView()) + ->setUser($this->getUser()) + ->setObject($mock) ->setHeader($header) ->setURI($uri) ->setImageURI($thumbnail) From 7f98a8575d0a587a46d177bcce8a87f8fc2ef401 Mon Sep 17 00:00:00 2001 From: epriestley Date: Sat, 13 Jun 2015 15:44:03 -0700 Subject: [PATCH 23/50] Allow different policy rules for different types of objects Summary: Ref T5681. Policy rules can now select objects they can apply to, so a rule like "task author" only shows up where it makes sense (when defining task policies). This will let us define rules like "members of thread" in Conpherence, "subscribers", etc., to make custom policies more flexible. Notes: - Per D13251, we need to do a little work to get the right options for policies like "Maniphest > Default View Policy". This should allow "task" policies. - This implements a "task author" policy as a simple example. - The `willApplyRule()` signature now accepts `$objects` to support bulk-loading things like subscribers. Test Plan: - Defined a task to be "visible to: task author", verified author could see it and other users could not. - `var_dump()`'d willApplyRule() inputs, verified they were correct (exactly the objects which use the rule). - Set `default view policy` to a task-specific policy. - Verified that other policies like "Can Use Bulk Editor" don't have these options. Reviewers: btrahan Reviewed By: btrahan Subscribers: epriestley Maniphest Tasks: T5681 Differential Revision: https://secure.phabricator.com/D13252 --- resources/celerity/map.php | 22 ++++---- src/__phutil_library_map__.php | 2 + .../base/PhabricatorApplication.php | 6 +++ .../ManiphestTaskAuthorPolicyRule.php | 31 +++++++++++ .../PhabricatorApplicationEditController.php | 12 +++-- .../PhabricatorPolicyApplication.php | 10 +++- .../PhabricatorPolicyEditController.php | 40 +++++++++++++- .../policy/filter/PhabricatorPolicyFilter.php | 53 ++++++++++++++----- .../PhabricatorAdministratorsPolicyRule.php | 5 +- ...PhabricatorLegalpadSignaturePolicyRule.php | 13 ++++- .../rule/PhabricatorLunarPhasePolicyRule.php | 6 ++- .../policy/rule/PhabricatorPolicyRule.php | 20 ++++++- .../rule/PhabricatorProjectsPolicyRule.php | 13 ++++- .../rule/PhabricatorUsersPolicyRule.php | 7 ++- .../form/control/AphrontFormPolicyControl.php | 19 +++++++ .../policy/behavior-policy-control.js | 2 +- 16 files changed, 220 insertions(+), 41 deletions(-) create mode 100644 src/applications/maniphest/policyrule/ManiphestTaskAuthorPolicyRule.php diff --git a/resources/celerity/map.php b/resources/celerity/map.php index 48478682fe..1d78bcbc69 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -391,7 +391,7 @@ return array( 'rsrc/js/application/phortune/behavior-stripe-payment-form.js' => '3f5d6dbf', 'rsrc/js/application/phortune/behavior-test-payment-form.js' => 'fc91ab6c', 'rsrc/js/application/phortune/phortune-credit-card-form.js' => '2290aeef', - 'rsrc/js/application/policy/behavior-policy-control.js' => '9a340b3d', + 'rsrc/js/application/policy/behavior-policy-control.js' => '7d470398', 'rsrc/js/application/policy/behavior-policy-rule-editor.js' => '5e9f347c', 'rsrc/js/application/ponder/behavior-votebox.js' => '4e9b766b', 'rsrc/js/application/projects/behavior-project-boards.js' => 'ba4fa35c', @@ -624,7 +624,7 @@ return array( 'javelin-behavior-pholio-mock-view' => 'fbe497e7', 'javelin-behavior-phui-dropdown-menu' => '54733475', 'javelin-behavior-phui-object-box-tabs' => '2bfa2836', - 'javelin-behavior-policy-control' => '9a340b3d', + 'javelin-behavior-policy-control' => '7d470398', 'javelin-behavior-policy-rule-editor' => '5e9f347c', 'javelin-behavior-ponder-votebox' => '4e9b766b', 'javelin-behavior-project-boards' => 'ba4fa35c', @@ -1413,6 +1413,15 @@ return array( 'javelin-request', 'javelin-router', ), + '7d470398' => array( + 'javelin-behavior', + 'javelin-dom', + 'javelin-util', + 'phuix-dropdown-menu', + 'phuix-action-list-view', + 'phuix-action-view', + 'javelin-workflow', + ), '7e41274a' => array( 'javelin-install', ), @@ -1575,15 +1584,6 @@ return array( 'javelin-behavior-device', 'phabricator-title', ), - '9a340b3d' => array( - 'javelin-behavior', - 'javelin-dom', - 'javelin-util', - 'phuix-dropdown-menu', - 'phuix-action-list-view', - 'phuix-action-view', - 'javelin-workflow', - ), '9f36c42d' => array( 'javelin-behavior', 'javelin-stratcom', diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 80cf17dcbc..70eb4103fc 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1051,6 +1051,7 @@ phutil_register_library_map(array( 'ManiphestStatusEmailCommand' => 'applications/maniphest/command/ManiphestStatusEmailCommand.php', 'ManiphestSubpriorityController' => 'applications/maniphest/controller/ManiphestSubpriorityController.php', 'ManiphestTask' => 'applications/maniphest/storage/ManiphestTask.php', + 'ManiphestTaskAuthorPolicyRule' => 'applications/maniphest/policyrule/ManiphestTaskAuthorPolicyRule.php', 'ManiphestTaskClosedStatusDatasource' => 'applications/maniphest/typeahead/ManiphestTaskClosedStatusDatasource.php', 'ManiphestTaskDependedOnByTaskEdgeType' => 'applications/maniphest/edge/ManiphestTaskDependedOnByTaskEdgeType.php', 'ManiphestTaskDependsOnTaskEdgeType' => 'applications/maniphest/edge/ManiphestTaskDependsOnTaskEdgeType.php', @@ -4412,6 +4413,7 @@ phutil_register_library_map(array( 'PhabricatorProjectInterface', 'PhabricatorSpacesInterface', ), + 'ManiphestTaskAuthorPolicyRule' => 'PhabricatorPolicyRule', 'ManiphestTaskClosedStatusDatasource' => 'PhabricatorTypeaheadDatasource', 'ManiphestTaskDependedOnByTaskEdgeType' => 'PhabricatorEdgeType', 'ManiphestTaskDependsOnTaskEdgeType' => 'PhabricatorEdgeType', diff --git a/src/applications/base/PhabricatorApplication.php b/src/applications/base/PhabricatorApplication.php index a021b5f1c6..0e49bad23d 100644 --- a/src/applications/base/PhabricatorApplication.php +++ b/src/applications/base/PhabricatorApplication.php @@ -583,6 +583,12 @@ abstract class PhabricatorApplication implements PhabricatorPolicyInterface { } public function getCapabilityTemplatePHIDType($capability) { + switch ($capability) { + case PhabricatorPolicyCapability::CAN_VIEW: + case PhabricatorPolicyCapability::CAN_EDIT: + return null; + } + $spec = $this->getCustomCapabilitySpecification($capability); return idx($spec, 'template'); } diff --git a/src/applications/maniphest/policyrule/ManiphestTaskAuthorPolicyRule.php b/src/applications/maniphest/policyrule/ManiphestTaskAuthorPolicyRule.php new file mode 100644 index 0000000000..18502545c6 --- /dev/null +++ b/src/applications/maniphest/policyrule/ManiphestTaskAuthorPolicyRule.php @@ -0,0 +1,31 @@ +getPHID(); + if (!$viewer_phid) { + return false; + } + + return ($object->getAuthorPHID() == $viewer_phid); + } + + public function getValueControlType() { + return self::CONTROL_TYPE_NONE; + } + +} diff --git a/src/applications/meta/controller/PhabricatorApplicationEditController.php b/src/applications/meta/controller/PhabricatorApplicationEditController.php index dffb46c6a1..104fdb5b01 100644 --- a/src/applications/meta/controller/PhabricatorApplicationEditController.php +++ b/src/applications/meta/controller/PhabricatorApplicationEditController.php @@ -124,8 +124,7 @@ final class PhabricatorApplicationEditController ->setValue(idx($descriptions, $capability)) ->setCaption($caption)); } else { - $form->appendChild( - id(new AphrontFormPolicyControl()) + $control = id(new AphrontFormPolicyControl()) ->setUser($user) ->setDisabled($locked) ->setCapability($capability) @@ -133,7 +132,14 @@ final class PhabricatorApplicationEditController ->setPolicies($policies) ->setLabel($label) ->setName('policy:'.$capability) - ->setCaption($caption)); + ->setCaption($caption); + + $template = $application->getCapabilityTemplatePHIDType($capability); + if ($template) { + $control->setTemplatePHIDType($template); + } + + $form->appendControl($control); } } diff --git a/src/applications/policy/application/PhabricatorPolicyApplication.php b/src/applications/policy/application/PhabricatorPolicyApplication.php index cefccd2cb5..8aaf8eb1bf 100644 --- a/src/applications/policy/application/PhabricatorPolicyApplication.php +++ b/src/applications/policy/application/PhabricatorPolicyApplication.php @@ -19,7 +19,15 @@ final class PhabricatorPolicyApplication extends PhabricatorApplication { '/policy/' => array( 'explain/(?P[^/]+)/(?P[^/]+)/' => 'PhabricatorPolicyExplainController', - 'edit/(?:(?P[^/]+)/)?' => 'PhabricatorPolicyEditController', + 'edit/'. + '(?:'. + 'object/(?P[^/]+)'. + '|'. + 'type/(?P[^/]+)'. + '|'. + 'template/(?P[^/]+)'. + ')/'. + '(?:(?P[^/]+)/)?' => 'PhabricatorPolicyEditController', ), ); } diff --git a/src/applications/policy/controller/PhabricatorPolicyEditController.php b/src/applications/policy/controller/PhabricatorPolicyEditController.php index 80b04e4ea7..30c9836557 100644 --- a/src/applications/policy/controller/PhabricatorPolicyEditController.php +++ b/src/applications/policy/controller/PhabricatorPolicyEditController.php @@ -4,8 +4,37 @@ final class PhabricatorPolicyEditController extends PhabricatorPolicyController { public function handleRequest(AphrontRequest $request) { - $request = $this->getRequest(); - $viewer = $request->getUser(); + $viewer = $this->getViewer(); + + // TODO: This doesn't do anything yet, but sets up template policies; see + // T6860. + $is_template = false; + + $object_phid = $request->getURIData('objectPHID'); + if ($object_phid) { + $object = id(new PhabricatorObjectQuery()) + ->setViewer($viewer) + ->withPHIDs(array($object_phid)) + ->executeOne(); + if (!$object) { + return new Aphront404Response(); + } + } else { + $object_type = $request->getURIData('objectType'); + if (!$object_type) { + $object_type = $request->getURIData('templateType'); + $is_template = true; + } + + $phid_types = PhabricatorPHIDType::getAllInstalledTypes($viewer); + if (empty($phid_types[$object_type])) { + return new Aphront404Response(); + } + $object = $phid_types[$object_type]->newObject(); + if (!$object) { + return new Aphront404Response(); + } + } $action_options = array( PhabricatorPolicy::ACTION_ALLOW => pht('Allow'), @@ -15,6 +44,13 @@ final class PhabricatorPolicyEditController $rules = id(new PhutilSymbolLoader()) ->setAncestorClass('PhabricatorPolicyRule') ->loadObjects(); + + foreach ($rules as $key => $rule) { + if (!$rule->canApplyToObject($object)) { + unset($rules[$key]); + } + } + $rules = msort($rules, 'getRuleOrder'); $default_rule = array( diff --git a/src/applications/policy/filter/PhabricatorPolicyFilter.php b/src/applications/policy/filter/PhabricatorPolicyFilter.php index 46cb9352f7..36c73006a0 100644 --- a/src/applications/policy/filter/PhabricatorPolicyFilter.php +++ b/src/applications/policy/filter/PhabricatorPolicyFilter.php @@ -149,13 +149,13 @@ final class PhabricatorPolicyFilter { } if ($type == PhabricatorPolicyPHIDTypePolicy::TYPECONST) { - $need_policies[$policy] = $policy; + $need_policies[$policy][] = $object; } } } if ($need_policies) { - $this->loadCustomPolicies(array_keys($need_policies)); + $this->loadCustomPolicies($need_policies); } // If we need projects, check if any of the projects we need are also the @@ -500,7 +500,7 @@ final class PhabricatorPolicyFilter { $this->rejectObject($object, $policy, $capability); } } else if ($type == PhabricatorPolicyPHIDTypePolicy::TYPECONST) { - if ($this->checkCustomPolicy($policy)) { + if ($this->checkCustomPolicy($policy, $object)) { return true; } else { $this->rejectObject($object, $policy, $capability); @@ -573,30 +573,47 @@ final class PhabricatorPolicyFilter { throw $exception; } - private function loadCustomPolicies(array $phids) { + private function loadCustomPolicies(array $map) { $viewer = $this->viewer; $viewer_phid = $viewer->getPHID(); $custom_policies = id(new PhabricatorPolicyQuery()) ->setViewer($viewer) - ->withPHIDs($phids) + ->withPHIDs(array_keys($map)) ->execute(); $custom_policies = mpull($custom_policies, null, 'getPHID'); - $classes = array(); $values = array(); - foreach ($custom_policies as $policy) { + $objects = array(); + foreach ($custom_policies as $policy_phid => $policy) { foreach ($policy->getCustomRuleClasses() as $class) { $classes[$class] = $class; $values[$class][] = $policy->getCustomRuleValues($class); + + foreach (idx($map, $policy_phid, array()) as $object) { + $objects[$class][] = $object; + } } } foreach ($classes as $class => $ignored) { - $object = newv($class, array()); - $object->willApplyRules($viewer, array_mergev($values[$class])); - $classes[$class] = $object; + $rule_object = newv($class, array()); + + // Filter out any objects which the rule can't apply to. + $target_objects = idx($objects, $class, array()); + foreach ($target_objects as $key => $target_object) { + if (!$rule_object->canApplyToObject($target_object)) { + unset($target_objects[$key]); + } + } + + $rule_object->willApplyRules( + $viewer, + array_mergev($values[$class]), + $target_objects); + + $classes[$class] = $rule_object; } foreach ($custom_policies as $policy) { @@ -610,7 +627,10 @@ final class PhabricatorPolicyFilter { $this->customPolicies[$viewer->getPHID()] += $custom_policies; } - private function checkCustomPolicy($policy_phid) { + private function checkCustomPolicy( + $policy_phid, + PhabricatorPolicyInterface $object) { + $viewer = $this->viewer; $viewer_phid = $viewer->getPHID(); @@ -623,14 +643,19 @@ final class PhabricatorPolicyFilter { $objects = $policy->getRuleObjects(); $action = null; foreach ($policy->getRules() as $rule) { - $object = idx($objects, idx($rule, 'rule')); - if (!$object) { + $rule_object = idx($objects, idx($rule, 'rule')); + if (!$rule_object) { // Reject, this policy has a bogus rule. return false; } + if (!$rule_object->canApplyToObject($object)) { + // Reject, this policy rule can't be applied to the given object. + return false; + } + // If the user matches this rule, use this action. - if ($object->applyRule($viewer, idx($rule, 'value'))) { + if ($rule_object->applyRule($viewer, idx($rule, 'value'), $object)) { $action = idx($rule, 'action'); break; } diff --git a/src/applications/policy/rule/PhabricatorAdministratorsPolicyRule.php b/src/applications/policy/rule/PhabricatorAdministratorsPolicyRule.php index f232cb3008..b6e450adde 100644 --- a/src/applications/policy/rule/PhabricatorAdministratorsPolicyRule.php +++ b/src/applications/policy/rule/PhabricatorAdministratorsPolicyRule.php @@ -6,7 +6,10 @@ final class PhabricatorAdministratorsPolicyRule extends PhabricatorPolicyRule { return pht('administrators'); } - public function applyRule(PhabricatorUser $viewer, $value) { + public function applyRule( + PhabricatorUser $viewer, + $value, + PhabricatorPolicyInterface $object) { return $viewer->getIsAdmin(); } diff --git a/src/applications/policy/rule/PhabricatorLegalpadSignaturePolicyRule.php b/src/applications/policy/rule/PhabricatorLegalpadSignaturePolicyRule.php index 9797d5ef80..3aa7ef8d9c 100644 --- a/src/applications/policy/rule/PhabricatorLegalpadSignaturePolicyRule.php +++ b/src/applications/policy/rule/PhabricatorLegalpadSignaturePolicyRule.php @@ -9,7 +9,11 @@ final class PhabricatorLegalpadSignaturePolicyRule return pht('signers of legalpad documents'); } - public function willApplyRules(PhabricatorUser $viewer, array $values) { + public function willApplyRules( + PhabricatorUser $viewer, + array $values, + array $objects) { + $values = array_unique(array_filter(array_mergev($values))); if (!$values) { return; @@ -26,12 +30,17 @@ final class PhabricatorLegalpadSignaturePolicyRule $this->signatures = mpull($documents, 'getPHID', 'getPHID'); } - public function applyRule(PhabricatorUser $viewer, $value) { + public function applyRule( + PhabricatorUser $viewer, + $value, + PhabricatorPolicyInterface $object) { + foreach ($value as $document_phid) { if (!isset($this->signatures[$document_phid])) { return false; } } + return true; } diff --git a/src/applications/policy/rule/PhabricatorLunarPhasePolicyRule.php b/src/applications/policy/rule/PhabricatorLunarPhasePolicyRule.php index 24f8f26138..a3336a7971 100644 --- a/src/applications/policy/rule/PhabricatorLunarPhasePolicyRule.php +++ b/src/applications/policy/rule/PhabricatorLunarPhasePolicyRule.php @@ -11,7 +11,11 @@ final class PhabricatorLunarPhasePolicyRule extends PhabricatorPolicyRule { return pht('when the moon'); } - public function applyRule(PhabricatorUser $viewer, $value) { + public function applyRule( + PhabricatorUser $viewer, + $value, + PhabricatorPolicyInterface $object) { + $moon = new PhutilLunarPhase(PhabricatorTime::getNow()); switch ($value) { diff --git a/src/applications/policy/rule/PhabricatorPolicyRule.php b/src/applications/policy/rule/PhabricatorPolicyRule.php index eaa04e1e9e..e0ac96ec2b 100644 --- a/src/applications/policy/rule/PhabricatorPolicyRule.php +++ b/src/applications/policy/rule/PhabricatorPolicyRule.php @@ -8,9 +8,15 @@ abstract class PhabricatorPolicyRule { const CONTROL_TYPE_NONE = 'none'; abstract public function getRuleDescription(); - abstract public function applyRule(PhabricatorUser $viewer, $value); + abstract public function applyRule( + PhabricatorUser $viewer, + $value, + PhabricatorPolicyInterface $object); - public function willApplyRules(PhabricatorUser $viewer, array $values) { + public function willApplyRules( + PhabricatorUser $viewer, + array $values, + array $objects) { return; } @@ -22,6 +28,16 @@ abstract class PhabricatorPolicyRule { return null; } + /** + * Return `true` if this rule can be applied to the given object. + * + * Some policy rules may only operation on certain kinds of objects. For + * example, a "task author" rule + */ + public function canApplyToObject(PhabricatorPolicyInterface $object) { + return true; + } + protected function getDatasourceTemplate( PhabricatorTypeaheadDatasource $datasource) { return array( diff --git a/src/applications/policy/rule/PhabricatorProjectsPolicyRule.php b/src/applications/policy/rule/PhabricatorProjectsPolicyRule.php index eca97ce37d..c3fbfd4f7e 100644 --- a/src/applications/policy/rule/PhabricatorProjectsPolicyRule.php +++ b/src/applications/policy/rule/PhabricatorProjectsPolicyRule.php @@ -8,7 +8,11 @@ final class PhabricatorProjectsPolicyRule extends PhabricatorPolicyRule { return pht('members of projects'); } - public function willApplyRules(PhabricatorUser $viewer, array $values) { + public function willApplyRules( + PhabricatorUser $viewer, + array $values, + array $objects) { + $values = array_unique(array_filter(array_mergev($values))); if (!$values) { return; @@ -24,12 +28,17 @@ final class PhabricatorProjectsPolicyRule extends PhabricatorPolicyRule { } } - public function applyRule(PhabricatorUser $viewer, $value) { + public function applyRule( + PhabricatorUser $viewer, + $value, + PhabricatorPolicyInterface $object) { + foreach ($value as $project_phid) { if (isset($this->memberships[$viewer->getPHID()][$project_phid])) { return true; } } + return false; } diff --git a/src/applications/policy/rule/PhabricatorUsersPolicyRule.php b/src/applications/policy/rule/PhabricatorUsersPolicyRule.php index c60e43abb6..aa75027cb1 100644 --- a/src/applications/policy/rule/PhabricatorUsersPolicyRule.php +++ b/src/applications/policy/rule/PhabricatorUsersPolicyRule.php @@ -6,12 +6,17 @@ final class PhabricatorUsersPolicyRule extends PhabricatorPolicyRule { return pht('users'); } - public function applyRule(PhabricatorUser $viewer, $value) { + public function applyRule( + PhabricatorUser $viewer, + $value, + PhabricatorPolicyInterface $object) { + foreach ($value as $phid) { if ($phid == $viewer->getPHID()) { return true; } } + return false; } diff --git a/src/view/form/control/AphrontFormPolicyControl.php b/src/view/form/control/AphrontFormPolicyControl.php index 46dde71826..40caba33d7 100644 --- a/src/view/form/control/AphrontFormPolicyControl.php +++ b/src/view/form/control/AphrontFormPolicyControl.php @@ -6,6 +6,7 @@ final class AphrontFormPolicyControl extends AphrontFormControl { private $capability; private $policies; private $spacePHID; + private $templatePHIDType; public function setPolicyObject(PhabricatorPolicyInterface $object) { $this->object = $object; @@ -27,6 +28,11 @@ final class AphrontFormPolicyControl extends AphrontFormControl { return $this->spacePHID; } + public function setTemplatePHIDType($type) { + $this->templatePHIDType = $type; + return $this; + } + public function setCapability($capability) { $this->capability = $capability; @@ -178,6 +184,18 @@ final class AphrontFormPolicyControl extends AphrontFormControl { } + if ($this->templatePHIDType) { + $context_path = 'template/'.$this->templatePHIDType.'/'; + } else { + $object_phid = $this->object->getPHID(); + if ($object_phid) { + $context_path = 'object/'.$object_phid.'/'; + } else { + $object_type = phid_get_type($this->object->generatePHID()); + $context_path = 'type/'.$object_type.'/'; + } + } + Javelin::initBehavior( 'policy-control', array( @@ -190,6 +208,7 @@ final class AphrontFormPolicyControl extends AphrontFormControl { 'labels' => $labels, 'value' => $this->getValue(), 'capability' => $this->capability, + 'editURI' => '/policy/edit/'.$context_path, 'customPlaceholder' => $this->getCustomPolicyPlaceholder(), )); diff --git a/webroot/rsrc/js/application/policy/behavior-policy-control.js b/webroot/rsrc/js/application/policy/behavior-policy-control.js index ddbe9f17ec..ea66761191 100644 --- a/webroot/rsrc/js/application/policy/behavior-policy-control.js +++ b/webroot/rsrc/js/application/policy/behavior-policy-control.js @@ -101,7 +101,7 @@ JX.behavior('policy-control', function(config) { * Get the workflow URI to create or edit a policy with a given PHID. */ var get_custom_uri = function(phid, capability) { - var uri = '/policy/edit/'; + var uri = config.editURI; if (phid != config.customPlaceholder) { uri += phid + '/'; } From 466755476aedde9a1ebaaf786781d722f1c126d1 Mon Sep 17 00:00:00 2001 From: epriestley Date: Sat, 13 Jun 2015 15:44:38 -0700 Subject: [PATCH 24/50] Allow PolicyRules to serve as "Object Policies" Summary: Ref T5681. Ref T8488. This allows policy rules to provide "Object Policies", which are similar to the global/basic policies: - They show up directly in the dropdown (you don't have to create a custom rule). - They don't need to create or load anything in the database. To implement one, you just add a couple methods on an existing PolicyRule that let Phabricator know it can work as an object policy rule. {F494764} These rules only show up where they make sense. For example, the "Task Author" rule is only available in Maniphest, and in "Default View Policy" / "Default Edit Policy" of the Application config. This should make T8488 easier by letting us set the default policies to "Members of Thread", without having to create a dedicated custom policy for every thread. Test Plan: - Set tasks to "Task Author" policy. - Tried to view them as other users. - Viewed transaction change strings. - Viewed policy errors. - Set them as default policies. - Verified they don't leak into other policy controls. Reviewers: btrahan Reviewed By: btrahan Subscribers: epriestley Maniphest Tasks: T5681, T8488 Differential Revision: https://secure.phabricator.com/D13257 --- .../ManiphestTaskAuthorPolicyRule.php | 12 ++ .../PhabricatorApplicationEditController.php | 14 +++ .../constants/PhabricatorPolicyType.php | 10 +- .../policy/filter/PhabricatorPolicyFilter.php | 67 +++++++++++ .../policy/query/PhabricatorPolicyQuery.php | 113 +++++++++++++++++- .../policy/rule/PhabricatorPolicyRule.php | 37 ++++++ .../policy/storage/PhabricatorPolicy.php | 19 +++ .../PhabricatorApplicationTransaction.php | 4 +- .../form/control/AphrontFormPolicyControl.php | 32 ++++- 9 files changed, 300 insertions(+), 8 deletions(-) diff --git a/src/applications/maniphest/policyrule/ManiphestTaskAuthorPolicyRule.php b/src/applications/maniphest/policyrule/ManiphestTaskAuthorPolicyRule.php index 18502545c6..04a39ff71c 100644 --- a/src/applications/maniphest/policyrule/ManiphestTaskAuthorPolicyRule.php +++ b/src/applications/maniphest/policyrule/ManiphestTaskAuthorPolicyRule.php @@ -3,6 +3,18 @@ final class ManiphestTaskAuthorPolicyRule extends PhabricatorPolicyRule { + public function getObjectPolicyKey() { + return 'maniphest.author'; + } + + public function getObjectPolicyName() { + return pht('Task Author'); + } + + public function getPolicyExplanation() { + return pht('The author of this task can take this action.'); + } + public function getRuleDescription() { return pht('task author'); } diff --git a/src/applications/meta/controller/PhabricatorApplicationEditController.php b/src/applications/meta/controller/PhabricatorApplicationEditController.php index 104fdb5b01..ba82b30053 100644 --- a/src/applications/meta/controller/PhabricatorApplicationEditController.php +++ b/src/applications/meta/controller/PhabricatorApplicationEditController.php @@ -136,6 +136,20 @@ final class PhabricatorApplicationEditController $template = $application->getCapabilityTemplatePHIDType($capability); if ($template) { + $phid_types = PhabricatorPHIDType::getAllTypes(); + $phid_type = idx($phid_types, $template); + if ($phid_type) { + $template_object = $phid_type->newObject(); + if ($template_object) { + $template_policies = id(new PhabricatorPolicyQuery()) + ->setViewer($user) + ->setObject($template_object) + ->execute(); + $control->setPolicies($template_policies); + $control->setTemplateObject($template_object); + } + } + $control->setTemplatePHIDType($template); } diff --git a/src/applications/policy/constants/PhabricatorPolicyType.php b/src/applications/policy/constants/PhabricatorPolicyType.php index 51e8cb4c4d..b5ce8f4b29 100644 --- a/src/applications/policy/constants/PhabricatorPolicyType.php +++ b/src/applications/policy/constants/PhabricatorPolicyType.php @@ -3,6 +3,7 @@ final class PhabricatorPolicyType extends PhabricatorPolicyConstants { const TYPE_GLOBAL = 'global'; + const TYPE_OBJECT = 'object'; const TYPE_USER = 'user'; const TYPE_CUSTOM = 'custom'; const TYPE_PROJECT = 'project'; @@ -11,9 +12,10 @@ final class PhabricatorPolicyType extends PhabricatorPolicyConstants { public static function getPolicyTypeOrder($type) { static $map = array( self::TYPE_GLOBAL => 0, - self::TYPE_USER => 1, - self::TYPE_CUSTOM => 2, - self::TYPE_PROJECT => 3, + self::TYPE_OBJECT => 1, + self::TYPE_USER => 2, + self::TYPE_CUSTOM => 3, + self::TYPE_PROJECT => 4, self::TYPE_MASKED => 9, ); return idx($map, $type, 9); @@ -23,6 +25,8 @@ final class PhabricatorPolicyType extends PhabricatorPolicyConstants { switch ($type) { case self::TYPE_GLOBAL: return pht('Basic Policies'); + case self::TYPE_OBJECT: + return pht('Object Policies'); case self::TYPE_USER: return pht('User Policies'); case self::TYPE_CUSTOM: diff --git a/src/applications/policy/filter/PhabricatorPolicyFilter.php b/src/applications/policy/filter/PhabricatorPolicyFilter.php index 36c73006a0..561a9d8e0a 100644 --- a/src/applications/policy/filter/PhabricatorPolicyFilter.php +++ b/src/applications/policy/filter/PhabricatorPolicyFilter.php @@ -8,6 +8,7 @@ final class PhabricatorPolicyFilter { private $raisePolicyExceptions; private $userProjects; private $customPolicies = array(); + private $objectPolicies = array(); private $forcedPolicy; public static function mustRetainCapability( @@ -131,6 +132,7 @@ final class PhabricatorPolicyFilter { $need_projects = array(); $need_policies = array(); + $need_objpolicies = array(); foreach ($objects as $key => $object) { $object_capabilities = $object->getCapabilities(); foreach ($capabilities as $capability) { @@ -143,17 +145,29 @@ final class PhabricatorPolicyFilter { } $policy = $this->getObjectPolicy($object, $capability); + + if (PhabricatorPolicyQuery::isObjectPolicy($policy)) { + $need_objpolicies[$policy][] = $object; + continue; + } + $type = phid_get_type($policy); if ($type == PhabricatorProjectProjectPHIDType::TYPECONST) { $need_projects[$policy] = $policy; + continue; } if ($type == PhabricatorPolicyPHIDTypePolicy::TYPECONST) { $need_policies[$policy][] = $object; + continue; } } } + if ($need_objpolicies) { + $this->loadObjectPolicies($need_objpolicies); + } + if ($need_policies) { $this->loadCustomPolicies($need_policies); } @@ -486,6 +500,15 @@ final class PhabricatorPolicyFilter { $this->rejectObject($object, $policy, $capability); break; default: + if (PhabricatorPolicyQuery::isObjectPolicy($policy)) { + if ($this->checkObjectPolicy($policy, $object)) { + return true; + } else { + $this->rejectObject($object, $policy, $capability); + break; + } + } + $type = phid_get_type($policy); if ($type == PhabricatorProjectProjectPHIDType::TYPECONST) { if (!empty($this->userProjects[$viewer->getPHID()][$policy])) { @@ -573,6 +596,32 @@ final class PhabricatorPolicyFilter { throw $exception; } + private function loadObjectPolicies(array $map) { + $viewer = $this->viewer; + $viewer_phid = $viewer->getPHID(); + + $rules = PhabricatorPolicyQuery::getObjectPolicyRules(null); + + $results = array(); + foreach ($map as $key => $object_list) { + $rule = idx($rules, $key); + if (!$rule) { + continue; + } + + foreach ($object_list as $object_key => $object) { + if (!$rule->canApplyToObject($object)) { + unset($object_list[$object_key]); + } + } + + $rule->willApplyRules($viewer, array(), $object_list); + $results[$key] = $rule; + } + + $this->objectPolicies[$viewer_phid] = $results; + } + private function loadCustomPolicies(array $map) { $viewer = $this->viewer; $viewer_phid = $viewer->getPHID(); @@ -627,6 +676,24 @@ final class PhabricatorPolicyFilter { $this->customPolicies[$viewer->getPHID()] += $custom_policies; } + private function checkObjectPolicy( + $policy_phid, + PhabricatorPolicyInterface $object) { + $viewer = $this->viewer; + $viewer_phid = $viewer->getPHID(); + + $rule = idx($this->objectPolicies[$viewer_phid], $policy_phid); + if (!$rule) { + return false; + } + + if (!$rule->canApplyToObject($object)) { + return false; + } + + return $rule->applyRule($viewer, null, $object); + } + private function checkCustomPolicy( $policy_phid, PhabricatorPolicyInterface $object) { diff --git a/src/applications/policy/query/PhabricatorPolicyQuery.php b/src/applications/policy/query/PhabricatorPolicyQuery.php index 6a5c2219df..d0cf78b917 100644 --- a/src/applications/policy/query/PhabricatorPolicyQuery.php +++ b/src/applications/policy/query/PhabricatorPolicyQuery.php @@ -6,6 +6,8 @@ final class PhabricatorPolicyQuery private $object; private $phids; + const OBJECT_POLICY_PREFIX = 'obj.'; + public function setObject(PhabricatorPolicyInterface $object) { $this->object = $object; return $this; @@ -71,7 +73,15 @@ final class PhabricatorPolicyQuery $results = array(); // First, load global policies. - foreach ($this->getGlobalPolicies() as $phid => $policy) { + foreach (self::getGlobalPolicies() as $phid => $policy) { + if (isset($phids[$phid])) { + $results[$phid] = $policy; + unset($phids[$phid]); + } + } + + // Now, load object policies. + foreach (self::getObjectPolicies($this->object) as $phid => $policy) { if (isset($phids[$phid])) { $results[$phid] = $policy; unset($phids[$phid]); @@ -212,7 +222,7 @@ final class PhabricatorPolicyQuery // option unless the object already has a "Public" policy. In this case we // retain the policy but enforce it as though it was "All Users". $show_public = PhabricatorEnv::getEnvConfig('policy.allow-public'); - foreach ($this->getGlobalPolicies() as $phid => $policy) { + foreach (self::getGlobalPolicies() as $phid => $policy) { if ($phid == PhabricatorPolicies::POLICY_PUBLIC) { if (!$show_public) { continue; @@ -221,6 +231,10 @@ final class PhabricatorPolicyQuery $phids[] = $phid; } + foreach (self::getObjectPolicies($this->object) as $phid => $policy) { + $phids[] = $phid; + } + return $phids; } @@ -234,4 +248,99 @@ final class PhabricatorPolicyQuery return 'PhabricatorPolicyApplication'; } + public static function isSpecialPolicy($identifier) { + if (self::isObjectPolicy($identifier)) { + return true; + } + + if (self::isGlobalPolicy($identifier)) { + return true; + } + + return false; + } + + +/* -( Object Policies )---------------------------------------------------- */ + + + public static function isObjectPolicy($identifier) { + $prefix = self::OBJECT_POLICY_PREFIX; + return !strncmp($identifier, $prefix, strlen($prefix)); + } + + public static function getObjectPolicy($identifier) { + if (!self::isObjectPolicy($identifier)) { + return null; + } + + $policies = self::getObjectPolicies(null); + return idx($policies, $identifier); + } + + public static function getObjectPolicyRule($identifier) { + if (!self::isObjectPolicy($identifier)) { + return null; + } + + $rules = self::getObjectPolicyRules(null); + return idx($rules, $identifier); + } + + public static function getObjectPolicies($object) { + $rule_map = self::getObjectPolicyRules($object); + + $results = array(); + foreach ($rule_map as $key => $rule) { + $results[$key] = id(new PhabricatorPolicy()) + ->setType(PhabricatorPolicyType::TYPE_OBJECT) + ->setPHID($key) + ->setIcon($rule->getObjectPolicyIcon()) + ->setName($rule->getObjectPolicyName()) + ->setShortName($rule->getObjectPolicyShortName()) + ->makeEphemeral(); + } + + return $results; + } + + public static function getObjectPolicyRules($object) { + $rules = id(new PhutilSymbolLoader()) + ->setAncestorClass('PhabricatorPolicyRule') + ->loadObjects(); + + $results = array(); + foreach ($rules as $rule) { + $key = $rule->getObjectPolicyKey(); + if (!$key) { + continue; + } + + $full_key = self::OBJECT_POLICY_PREFIX.$key; + if (isset($results[$full_key])) { + throw new Exception( + pht( + 'Two policy rules (of classes "%s" and "%s") define the same '. + 'object policy key ("%s"), but each object policy rule must use '. + 'a unique key.', + get_class($rule), + get_class($results[$full_key]), + $key)); + } + + $results[$full_key] = $rule; + } + + if ($object !== null) { + foreach ($results as $key => $rule) { + if (!$rule->canApplyToObject($object)) { + unset($results[$key]); + } + } + } + + return $results; + } + + } diff --git a/src/applications/policy/rule/PhabricatorPolicyRule.php b/src/applications/policy/rule/PhabricatorPolicyRule.php index e0ac96ec2b..4499ea459e 100644 --- a/src/applications/policy/rule/PhabricatorPolicyRule.php +++ b/src/applications/policy/rule/PhabricatorPolicyRule.php @@ -1,5 +1,8 @@ getObjectPolicyName(); + } + + public function getObjectPolicyIcon() { + return 'fa-cube'; + } + + public function getPolicyExplanation() { + throw new PhutilMethodNotImplementedException(); + } + } diff --git a/src/applications/policy/storage/PhabricatorPolicy.php b/src/applications/policy/storage/PhabricatorPolicy.php index c83d09ab5d..e01e0dd416 100644 --- a/src/applications/policy/storage/PhabricatorPolicy.php +++ b/src/applications/policy/storage/PhabricatorPolicy.php @@ -54,6 +54,11 @@ final class PhabricatorPolicy return PhabricatorPolicyQuery::getGlobalPolicy($policy_identifier); } + $policy = PhabricatorPolicyQuery::getObjectPolicy($policy_identifier); + if ($policy) { + return $policy; + } + if (!$handle) { throw new Exception( pht( @@ -158,7 +163,16 @@ final class PhabricatorPolicy return $this->workflow; } + public function setIcon($icon) { + $this->icon = $icon; + return $this; + } + public function getIcon() { + if ($this->icon) { + return $this->icon; + } + switch ($this->getType()) { case PhabricatorPolicyType::TYPE_GLOBAL: static $map = array( @@ -204,6 +218,11 @@ final class PhabricatorPolicy PhabricatorUser $viewer, $policy) { + $rule = PhabricatorPolicyQuery::getObjectPolicyRule($policy); + if ($rule) { + return $rule->getPolicyExplanation(); + } + switch ($policy) { case PhabricatorPolicies::POLICY_PUBLIC: return pht('This object is public.'); diff --git a/src/applications/transactions/storage/PhabricatorApplicationTransaction.php b/src/applications/transactions/storage/PhabricatorApplicationTransaction.php index 7439c8728e..e8811da760 100644 --- a/src/applications/transactions/storage/PhabricatorApplicationTransaction.php +++ b/src/applications/transactions/storage/PhabricatorApplicationTransaction.php @@ -243,10 +243,10 @@ abstract class PhabricatorApplicationTransaction case PhabricatorTransactions::TYPE_EDIT_POLICY: case PhabricatorTransactions::TYPE_VIEW_POLICY: case PhabricatorTransactions::TYPE_JOIN_POLICY: - if (!PhabricatorPolicyQuery::isGlobalPolicy($old)) { + if (!PhabricatorPolicyQuery::isSpecialPolicy($old)) { $phids[] = array($old); } - if (!PhabricatorPolicyQuery::isGlobalPolicy($new)) { + if (!PhabricatorPolicyQuery::isSpecialPolicy($new)) { $phids[] = array($new); } break; diff --git a/src/view/form/control/AphrontFormPolicyControl.php b/src/view/form/control/AphrontFormPolicyControl.php index 40caba33d7..7c4fefcac6 100644 --- a/src/view/form/control/AphrontFormPolicyControl.php +++ b/src/view/form/control/AphrontFormPolicyControl.php @@ -7,6 +7,7 @@ final class AphrontFormPolicyControl extends AphrontFormControl { private $policies; private $spacePHID; private $templatePHIDType; + private $templateObject; public function setPolicyObject(PhabricatorPolicyInterface $object) { $this->object = $object; @@ -33,6 +34,11 @@ final class AphrontFormPolicyControl extends AphrontFormControl { return $this; } + public function setTemplateObject($object) { + $this->templateObject = $object; + return $this; + } + public function setCapability($capability) { $this->capability = $capability; @@ -64,9 +70,31 @@ final class AphrontFormPolicyControl extends AphrontFormControl { protected function getOptions() { $capability = $this->capability; + $policies = $this->policies; + + // Exclude object policies which don't make sense here. This primarily + // filters object policies associated from template capabilities (like + // "Default Task View Policy" being set to "Task Author") so they aren't + // made available on non-template capabilities (like "Can Bulk Edit"). + foreach ($policies as $key => $policy) { + if ($policy->getType() != PhabricatorPolicyType::TYPE_OBJECT) { + continue; + } + + $rule = PhabricatorPolicyQuery::getObjectPolicyRule($policy->getPHID()); + if (!$rule) { + continue; + } + + $target = nonempty($this->templateObject, $this->object); + if (!$rule->canApplyToObject($target)) { + unset($policies[$key]); + continue; + } + } $options = array(); - foreach ($this->policies as $policy) { + foreach ($policies as $policy) { if ($policy->getPHID() == PhabricatorPolicies::POLICY_PUBLIC) { // Never expose "Public" for capabilities which don't support it. $capobj = PhabricatorPolicyCapability::getCapabilityByKey($capability); @@ -74,6 +102,7 @@ final class AphrontFormPolicyControl extends AphrontFormControl { continue; } } + $policy_short_name = id(new PhutilUTF8StringTruncator()) ->setMaximumGlyphs(28) ->truncateString($policy->getName()); @@ -122,6 +151,7 @@ final class AphrontFormPolicyControl extends AphrontFormControl { $options, array( PhabricatorPolicyType::TYPE_GLOBAL, + PhabricatorPolicyType::TYPE_OBJECT, PhabricatorPolicyType::TYPE_USER, PhabricatorPolicyType::TYPE_CUSTOM, PhabricatorPolicyType::TYPE_PROJECT, From 893c7a26c196ecbe619233b8816ca87044e5779e Mon Sep 17 00:00:00 2001 From: epriestley Date: Sat, 13 Jun 2015 15:44:56 -0700 Subject: [PATCH 25/50] Add a "Thread Members" object policy and some unit tests Summary: Ref T8488. Ref T5681. Now you can just use `id(new ConpherenceThreadMembersPolicyRule())->getObjectPolicyFullKey()` as a policy. Added tests for TaskAuthor + ThreadMembers. Test Plan: - Ran tests. - Set a thread policy to "Members of thread'. Reviewers: btrahan Reviewed By: btrahan Subscribers: epriestley Maniphest Tasks: T5681, T8488 Differential Revision: https://secure.phabricator.com/D13258 --- src/__phutil_library_map__.php | 2 + .../ConpherenceThreadMembersPolicyRule.php | 42 +++++++++++++ .../PhabricatorPolicyDataTestCase.php | 59 +++++++++++++++++++ .../policy/query/PhabricatorPolicyQuery.php | 2 +- .../policy/rule/PhabricatorPolicyRule.php | 14 +++++ 5 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 src/applications/conpherence/policyrule/ConpherenceThreadMembersPolicyRule.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 70eb4103fc..63e0916c34 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -256,6 +256,7 @@ phutil_register_library_map(array( 'ConpherenceThreadIndexer' => 'applications/conpherence/search/ConpherenceThreadIndexer.php', 'ConpherenceThreadListView' => 'applications/conpherence/view/ConpherenceThreadListView.php', 'ConpherenceThreadMailReceiver' => 'applications/conpherence/mail/ConpherenceThreadMailReceiver.php', + 'ConpherenceThreadMembersPolicyRule' => 'applications/conpherence/policyrule/ConpherenceThreadMembersPolicyRule.php', 'ConpherenceThreadQuery' => 'applications/conpherence/query/ConpherenceThreadQuery.php', 'ConpherenceThreadRemarkupRule' => 'applications/conpherence/remarkup/ConpherenceThreadRemarkupRule.php', 'ConpherenceThreadSearchEngine' => 'applications/conpherence/query/ConpherenceThreadSearchEngine.php', @@ -3542,6 +3543,7 @@ phutil_register_library_map(array( 'ConpherenceThreadIndexer' => 'PhabricatorSearchDocumentIndexer', 'ConpherenceThreadListView' => 'AphrontView', 'ConpherenceThreadMailReceiver' => 'PhabricatorObjectMailReceiver', + 'ConpherenceThreadMembersPolicyRule' => 'PhabricatorPolicyRule', 'ConpherenceThreadQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'ConpherenceThreadRemarkupRule' => 'PhabricatorObjectRemarkupRule', 'ConpherenceThreadSearchEngine' => 'PhabricatorApplicationSearchEngine', diff --git a/src/applications/conpherence/policyrule/ConpherenceThreadMembersPolicyRule.php b/src/applications/conpherence/policyrule/ConpherenceThreadMembersPolicyRule.php new file mode 100644 index 0000000000..658ee42bdb --- /dev/null +++ b/src/applications/conpherence/policyrule/ConpherenceThreadMembersPolicyRule.php @@ -0,0 +1,42 @@ +getPHID(); + if (!$viewer_phid) { + return false; + } + + return (bool)$object->getParticipantIfExists($viewer_phid); + } + + public function getValueControlType() { + return self::CONTROL_TYPE_NONE; + } + +} diff --git a/src/applications/policy/__tests__/PhabricatorPolicyDataTestCase.php b/src/applications/policy/__tests__/PhabricatorPolicyDataTestCase.php index e9e9d21e0b..2348ba13b1 100644 --- a/src/applications/policy/__tests__/PhabricatorPolicyDataTestCase.php +++ b/src/applications/policy/__tests__/PhabricatorPolicyDataTestCase.php @@ -150,4 +150,63 @@ final class PhabricatorPolicyDataTestCase extends PhabricatorTestCase { unset($time_b); } + public function testObjectPolicyRuleTaskAuthor() { + $author = $this->generateNewTestUser(); + $viewer = $this->generateNewTestUser(); + + $rule = new ManiphestTaskAuthorPolicyRule(); + + $task = ManiphestTask::initializeNewTask($author); + $task->setViewPolicy($rule->getObjectPolicyFullKey()); + $task->save(); + + $this->assertTrue( + PhabricatorPolicyFilter::hasCapability( + $author, + $task, + PhabricatorPolicyCapability::CAN_VIEW)); + + $this->assertFalse( + PhabricatorPolicyFilter::hasCapability( + $viewer, + $task, + PhabricatorPolicyCapability::CAN_VIEW)); + } + + public function testObjectPolicyRuleThreadMembers() { + $author = $this->generateNewTestUser(); + $viewer = $this->generateNewTestUser(); + + $rule = new ConpherenceThreadMembersPolicyRule(); + + $thread = ConpherenceThread::initializeNewRoom($author); + $thread->setViewPolicy($rule->getObjectPolicyFullKey()); + $thread->save(); + + $this->assertFalse( + PhabricatorPolicyFilter::hasCapability( + $author, + $thread, + PhabricatorPolicyCapability::CAN_VIEW)); + + $this->assertFalse( + PhabricatorPolicyFilter::hasCapability( + $viewer, + $thread, + PhabricatorPolicyCapability::CAN_VIEW)); + + $participant = id(new ConpherenceParticipant()) + ->setParticipantPHID($viewer->getPHID()) + ->setConpherencePHID($thread->getPHID()); + + $thread->attachParticipants(array($viewer->getPHID() => $participant)); + + $this->assertTrue( + PhabricatorPolicyFilter::hasCapability( + $viewer, + $thread, + PhabricatorPolicyCapability::CAN_VIEW)); + } + + } diff --git a/src/applications/policy/query/PhabricatorPolicyQuery.php b/src/applications/policy/query/PhabricatorPolicyQuery.php index d0cf78b917..496c704b71 100644 --- a/src/applications/policy/query/PhabricatorPolicyQuery.php +++ b/src/applications/policy/query/PhabricatorPolicyQuery.php @@ -316,7 +316,7 @@ final class PhabricatorPolicyQuery continue; } - $full_key = self::OBJECT_POLICY_PREFIX.$key; + $full_key = $rule->getObjectPolicyFullKey(); if (isset($results[$full_key])) { throw new Exception( pht( diff --git a/src/applications/policy/rule/PhabricatorPolicyRule.php b/src/applications/policy/rule/PhabricatorPolicyRule.php index 4499ea459e..919c511bb7 100644 --- a/src/applications/policy/rule/PhabricatorPolicyRule.php +++ b/src/applications/policy/rule/PhabricatorPolicyRule.php @@ -114,6 +114,20 @@ abstract class PhabricatorPolicyRule { return null; } + public function getObjectPolicyFullKey() { + $key = $this->getObjectPolicyKey(); + + if (!$key) { + throw new Exception( + pht( + 'This policy rule (of class "%s") does not have an associated '. + 'object policy key.', + get_class($this))); + } + + return PhabricatorPolicyQuery::OBJECT_POLICY_PREFIX.$key; + } + public function getObjectPolicyName() { throw new PhutilMethodNotImplementedException(); } From 3de3a72dd8c7cba6cff715ad7a40d8acb7b40007 Mon Sep 17 00:00:00 2001 From: epriestley Date: Sat, 13 Jun 2015 15:45:17 -0700 Subject: [PATCH 26/50] Add a "Subscribers" object policy Summary: Ref T5681. Getting this to work correctly is a bit tricky, mostly because of the policy checks we do prior to applying an edit. I think I came up with a mostly-reasonable approach, although it's a little bit gross. It uses `spl_object_hash()` so it shouldn't be able to do anything bad/dangerous (the hints are strictly bound to the hinted object, which is a clone that we destroy moments later). Test Plan: - Added + ran a unit test. - Created a task with a "Subscribers" policy with me as a subscriber (without the hint stuff, this isn't possible: since you aren't a subscriber *yet*, you get a "you won't be able to see it" error). - Unsubscribed from a task with a "Subscribers" policy, was immediately unable to see it. - Created a task with a "subscribers" policy and a project subscriber with/without me as a member (error / success, respectively). Reviewers: btrahan Reviewed By: btrahan Subscribers: epriestley Maniphest Tasks: T5681 Differential Revision: https://secure.phabricator.com/D13259 --- src/__phutil_library_map__.php | 2 + .../PhabricatorPolicyDataTestCase.php | 27 ++++ .../policy/rule/PhabricatorPolicyRule.php | 50 ++++++++ ...atorSubscriptionsSubscribersPolicyRule.php | 121 ++++++++++++++++++ ...habricatorApplicationTransactionEditor.php | 13 ++ 5 files changed, 213 insertions(+) create mode 100644 src/applications/subscriptions/policyrule/PhabricatorSubscriptionsSubscribersPolicyRule.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 63e0916c34..530101ae40 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -2645,6 +2645,7 @@ phutil_register_library_map(array( 'PhabricatorSubscriptionsEditor' => 'applications/subscriptions/editor/PhabricatorSubscriptionsEditor.php', 'PhabricatorSubscriptionsListController' => 'applications/subscriptions/controller/PhabricatorSubscriptionsListController.php', 'PhabricatorSubscriptionsSubscribeEmailCommand' => 'applications/subscriptions/command/PhabricatorSubscriptionsSubscribeEmailCommand.php', + 'PhabricatorSubscriptionsSubscribersPolicyRule' => 'applications/subscriptions/policyrule/PhabricatorSubscriptionsSubscribersPolicyRule.php', 'PhabricatorSubscriptionsTransactionController' => 'applications/subscriptions/controller/PhabricatorSubscriptionsTransactionController.php', 'PhabricatorSubscriptionsUIEventListener' => 'applications/subscriptions/events/PhabricatorSubscriptionsUIEventListener.php', 'PhabricatorSubscriptionsUnsubscribeEmailCommand' => 'applications/subscriptions/command/PhabricatorSubscriptionsUnsubscribeEmailCommand.php', @@ -6166,6 +6167,7 @@ phutil_register_library_map(array( 'PhabricatorSubscriptionsEditor' => 'PhabricatorEditor', 'PhabricatorSubscriptionsListController' => 'PhabricatorController', 'PhabricatorSubscriptionsSubscribeEmailCommand' => 'MetaMTAEmailTransactionCommand', + 'PhabricatorSubscriptionsSubscribersPolicyRule' => 'PhabricatorPolicyRule', 'PhabricatorSubscriptionsTransactionController' => 'PhabricatorController', 'PhabricatorSubscriptionsUIEventListener' => 'PhabricatorEventListener', 'PhabricatorSubscriptionsUnsubscribeEmailCommand' => 'MetaMTAEmailTransactionCommand', diff --git a/src/applications/policy/__tests__/PhabricatorPolicyDataTestCase.php b/src/applications/policy/__tests__/PhabricatorPolicyDataTestCase.php index 2348ba13b1..f68eae2b49 100644 --- a/src/applications/policy/__tests__/PhabricatorPolicyDataTestCase.php +++ b/src/applications/policy/__tests__/PhabricatorPolicyDataTestCase.php @@ -208,5 +208,32 @@ final class PhabricatorPolicyDataTestCase extends PhabricatorTestCase { PhabricatorPolicyCapability::CAN_VIEW)); } + public function testObjectPolicyRuleSubscribers() { + $author = $this->generateNewTestUser(); + + $rule = new PhabricatorSubscriptionsSubscribersPolicyRule(); + + $task = ManiphestTask::initializeNewTask($author); + $task->setViewPolicy($rule->getObjectPolicyFullKey()); + $task->save(); + + $this->assertFalse( + PhabricatorPolicyFilter::hasCapability( + $author, + $task, + PhabricatorPolicyCapability::CAN_VIEW)); + + id(new PhabricatorSubscriptionsEditor()) + ->setActor($author) + ->setObject($task) + ->subscribeExplicit(array($author->getPHID())) + ->save(); + + $this->assertTrue( + PhabricatorPolicyFilter::hasCapability( + $author, + $task, + PhabricatorPolicyCapability::CAN_VIEW)); + } } diff --git a/src/applications/policy/rule/PhabricatorPolicyRule.php b/src/applications/policy/rule/PhabricatorPolicyRule.php index 919c511bb7..c4e47da827 100644 --- a/src/applications/policy/rule/PhabricatorPolicyRule.php +++ b/src/applications/policy/rule/PhabricatorPolicyRule.php @@ -97,6 +97,56 @@ abstract class PhabricatorPolicyRule { } +/* -( Transaction Hints )-------------------------------------------------- */ + + + /** + * Tell policy rules about upcoming transaction effects. + * + * Before transaction effects are applied, we try to stop users from making + * edits which will lock them out of objects. We can't do this perfectly, + * since they can set a policy to "the moon is full" moments before it wanes, + * but we try to prevent as many mistakes as possible. + * + * Some policy rules depend on complex checks against object state which + * we can't set up ahead of time. For example, subscriptions require database + * writes. + * + * In cases like this, instead of doing writes, you can pass a hint about an + * object to a policy rule. The rule can then look for hints and use them in + * rendering a verdict about whether the user will be able to see the object + * or not after applying the policy change. + * + * @param PhabricatorPolicyInterface Object to pass a hint about. + * @param PhabricatorPolicyRule Rule to pass hint to. + * @param wild Hint. + * @return void + */ + public static function passTransactionHintToRule( + PhabricatorPolicyInterface $object, + PhabricatorPolicyRule $rule, + $hint) { + + $cache = PhabricatorCaches::getRequestCache(); + $cache->setKey(self::getObjectPolicyCacheKey($object, $rule), $hint); + } + + protected function getTransactionHint( + PhabricatorPolicyInterface $object) { + + $cache = PhabricatorCaches::getRequestCache(); + return $cache->getKey(self::getObjectPolicyCacheKey($object, $this)); + } + + private static function getObjectPolicyCacheKey( + PhabricatorPolicyInterface $object, + PhabricatorPolicyRule $rule) { + $hash = spl_object_hash($object); + $rule = get_class($rule); + return 'policycache.'.$hash.'.'.$rule; + } + + /* -( Implementing Object Policies )--------------------------------------- */ diff --git a/src/applications/subscriptions/policyrule/PhabricatorSubscriptionsSubscribersPolicyRule.php b/src/applications/subscriptions/policyrule/PhabricatorSubscriptionsSubscribersPolicyRule.php new file mode 100644 index 0000000000..7da35f3703 --- /dev/null +++ b/src/applications/subscriptions/policyrule/PhabricatorSubscriptionsSubscribersPolicyRule.php @@ -0,0 +1,121 @@ +getPHID(); + if (!$viewer_phid) { + return; + } + + if (empty($this->subscribed[$viewer_phid])) { + $this->subscribed[$viewer_phid] = array(); + } + + // Load the project PHIDs the user is a member of. + if (!isset($this->sourcePHIDs[$viewer_phid])) { + $source_phids = PhabricatorEdgeQuery::loadDestinationPHIDs( + $viewer_phid, + PhabricatorProjectMemberOfProjectEdgeType::EDGECONST); + $source_phids[] = $viewer_phid; + $this->sourcePHIDs[$viewer_phid] = $source_phids; + } + + // Look for transaction hints. + foreach ($objects as $key => $object) { + $cache = $this->getTransactionHint($object); + if ($cache === null) { + // We don't have a hint for this object, so we'll deal with it below. + continue; + } + + // We have a hint, so use that as the source of truth. + unset($objects[$key]); + + foreach ($this->sourcePHIDs[$viewer_phid] as $source_phid) { + if (isset($cache[$source_phid])) { + $this->subscribed[$viewer_phid][$object->getPHID()] = true; + break; + } + } + } + + $phids = mpull($objects, 'getPHID'); + if (!$phids) { + return; + } + + $edge_query = id(new PhabricatorEdgeQuery()) + ->withSourcePHIDs($this->sourcePHIDs[$viewer_phid]) + ->withEdgeTypes( + array( + PhabricatorSubscribedToObjectEdgeType::EDGECONST, + )) + ->withDestinationPHIDs($phids); + + $edge_query->execute(); + + $subscribed = $edge_query->getDestinationPHIDs(); + if (!$subscribed) { + return; + } + + $this->subscribed[$viewer_phid] += array_fill_keys($subscribed, true); + } + + public function applyRule( + PhabricatorUser $viewer, + $value, + PhabricatorPolicyInterface $object) { + + $viewer_phid = $viewer->getPHID(); + if (!$viewer_phid) { + return false; + } + + if ($object->isAutomaticallySubscribed($viewer_phid)) { + return true; + } + + $subscribed = idx($this->subscribed, $viewer_phid); + return isset($subscribed[$object->getPHID()]); + } + + public function getValueControlType() { + return self::CONTROL_TYPE_NONE; + } + +} diff --git a/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php b/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php index a6f93ff761..6bf88b4e25 100644 --- a/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php +++ b/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php @@ -2087,6 +2087,19 @@ abstract class PhabricatorApplicationTransactionEditor foreach ($xactions as $xaction) { switch ($xaction->getTransactionType()) { + case PhabricatorTransactions::TYPE_SUBSCRIBERS: + $clone_xaction = clone $xaction; + $clone_xaction->setOldValue(array_values($this->subscribers)); + $clone_xaction->setNewValue( + $this->getPHIDTransactionNewValue( + $clone_xaction)); + + PhabricatorPolicyRule::passTransactionHintToRule( + $copy, + new PhabricatorSubscriptionsSubscribersPolicyRule(), + array_fuse($clone_xaction->getNewValue())); + + break; case PhabricatorTransactions::TYPE_SPACE: $space_phid = $this->getTransactionNewValue($object, $xaction); $copy->setSpacePHID($space_phid); From e74f027f0ac233fdd08e94b2296b526b9ebcf233 Mon Sep 17 00:00:00 2001 From: Paul Kassianik Date: Sat, 13 Jun 2015 19:44:28 -0700 Subject: [PATCH 27/50] Clarifiying Documentation Links Summary: Fixes T8487. Test Plan: Verify that links are clear at Diviner > Phabricator Contributor Docs > Using the Phabricator OAuth Server. Reviewers: lpriestley, #blessed_reviewers, epriestley Reviewed By: #blessed_reviewers, epriestley Subscribers: epriestley, Korvin Maniphest Tasks: T8487 Differential Revision: https://secure.phabricator.com/D13240 --- src/docs/contributor/using_oauthserver.diviner | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/docs/contributor/using_oauthserver.diviner b/src/docs/contributor/using_oauthserver.diviner index ff6f33a0c1..b09f595a5a 100644 --- a/src/docs/contributor/using_oauthserver.diviner +++ b/src/docs/contributor/using_oauthserver.diviner @@ -35,13 +35,13 @@ clients that implement OAuth 2.0. = Setup - Creating a Client = -# Visit https://phabricator.example.com/oauthserver/client/create/ +# Visit {nav Your Local Install > OAuth Server > Create Application} # Fill out the form # Profit = Obtaining an Authorization Code = -POST or GET https://phabricator.example.com/oauthserver/auth/ with the +POST or GET `https://phabricator.example.com/oauthserver/auth/` with the following parameters: - Required - **client_id** - the id of the newly registered client. @@ -76,7 +76,7 @@ and include the pertinent error information. = Obtaining an Access Token = -POST or GET https://phabricator.example.com/oauthserver/token/ +POST or GET `https://phabricator.example.com/oauthserver/token/` with the following parameters: - Required - **client_id** - the id of the client @@ -101,7 +101,7 @@ message. Simply include a query param with the key of "access_token" and the value as the earlier obtained access token. For example: -https://phabricator.example.com/api/user.whoami?access_token=ykc7ly7vtibj334oga4fnfbuvnwz4ocp +```https://phabricator.example.com/api/user.whoami?access_token=ykc7ly7vtibj334oga4fnfbuvnwz4ocp``` If the token has expired or is otherwise invalid, the client will receive an error indicating as such. In these cases, the client should re-initiate From addcef962b936e0b5ecf20508ca98db7aaa6c927 Mon Sep 17 00:00:00 2001 From: Joshua Spence Date: Sun, 14 Jun 2015 14:11:22 +1000 Subject: [PATCH 28/50] Publish books with the most-open policy Summary: Ref T4558. When publishing a new Diviner book, use the most-open policy instead of `PhabricatorPolicies::POLICY_USER`. Test Plan: Ran `diviner generate` in a directory which didn't have published Diviner documentation. Reviewers: #blessed_reviewers, epriestley Reviewed By: #blessed_reviewers, epriestley Subscribers: epriestley, Korvin Maniphest Tasks: T4558 Differential Revision: https://secure.phabricator.com/D13254 --- src/applications/diviner/publisher/DivinerLivePublisher.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/applications/diviner/publisher/DivinerLivePublisher.php b/src/applications/diviner/publisher/DivinerLivePublisher.php index 1bad2dcb8e..f2dfaa0a31 100644 --- a/src/applications/diviner/publisher/DivinerLivePublisher.php +++ b/src/applications/diviner/publisher/DivinerLivePublisher.php @@ -12,7 +12,7 @@ final class DivinerLivePublisher extends DivinerPublisher { if (!$book) { $book = id(new DivinerLiveBook()) ->setName($book_name) - ->setViewPolicy(PhabricatorPolicies::POLICY_USER) + ->setViewPolicy(PhabricatorPolicies::getMostOpenPolicy()) ->save(); } From ea7397f7e4f96e99b4025d774881d050b9ddc1e6 Mon Sep 17 00:00:00 2001 From: Joshua Spence Date: Sun, 14 Jun 2015 14:11:55 +1000 Subject: [PATCH 29/50] Rename PassphraseCredentialType subclasses for consistency Summary: Ref T5655. Test Plan: `arc unit` + `grep` Reviewers: #blessed_reviewers, epriestley Reviewed By: #blessed_reviewers, epriestley Subscribers: epriestley, Korvin Maniphest Tasks: T5655 Differential Revision: https://secure.phabricator.com/D13266 --- .../20131121.repocredentials.2.mig.php | 6 +++--- src/__phutil_library_map__.php | 21 ++++++++++--------- .../DiffusionRepositoryCreateController.php | 12 +++++------ .../command/DrydockSSHCommandInterface.php | 2 +- .../DrydockSFTPFilesystemInterface.php | 2 +- ...sterHTTPRequestBuildStepImplementation.php | 4 ++-- .../PassphraseQueryConduitAPIMethod.php | 8 +++---- ...p => PassphrasePasswordCredentialType.php} | 2 +- ...ssphraseSSHGeneratedKeyCredentialType.php} | 4 ++-- ...PassphraseSSHPrivateKeyCredentialType.php} | 2 +- ...phraseSSHPrivateKeyFileCredentialType.php} | 4 ++-- ...phraseSSHPrivateKeyTextCredentialType.php} | 4 ++-- .../passphrase/keys/PassphrasePasswordKey.php | 2 +- .../passphrase/keys/PassphraseSSHKey.php | 4 ++-- .../PhabricatorRepositoryURITestCase.php | 4 ++-- ...abricatorStandardCustomFieldCredential.php | 2 +- 16 files changed, 42 insertions(+), 41 deletions(-) rename src/applications/passphrase/credentialtype/{PassphraseCredentialTypePassword.php => PassphrasePasswordCredentialType.php} (93%) rename src/applications/passphrase/credentialtype/{PassphraseCredentialTypeSSHGeneratedKey.php => PassphraseSSHGeneratedKeyCredentialType.php} (87%) rename src/applications/passphrase/credentialtype/{PassphraseCredentialTypeSSHPrivateKey.php => PassphraseSSHPrivateKeyCredentialType.php} (91%) rename src/applications/passphrase/credentialtype/{PassphraseCredentialTypeSSHPrivateKeyFile.php => PassphraseSSHPrivateKeyFileCredentialType.php} (90%) rename src/applications/passphrase/credentialtype/{PassphraseCredentialTypeSSHPrivateKeyText.php => PassphraseSSHPrivateKeyTextCredentialType.php} (93%) diff --git a/resources/sql/patches/20131121.repocredentials.2.mig.php b/resources/sql/patches/20131121.repocredentials.2.mig.php index 3953b8416f..3da813408f 100644 --- a/resources/sql/patches/20131121.repocredentials.2.mig.php +++ b/resources/sql/patches/20131121.repocredentials.2.mig.php @@ -26,7 +26,7 @@ foreach (new LiskMigrationIterator($table) as $repository) { if ($proto == 'http' || $proto == 'https' || $proto == 'svn') { $username = $repository->getDetail('http-login'); $secret = $repository->getDetail('http-pass'); - $type = PassphraseCredentialTypePassword::CREDENTIAL_TYPE; + $type = PassphrasePasswordCredentialType::CREDENTIAL_TYPE; } else { $username = $repository->getDetail('ssh-login'); if (!$username) { @@ -42,10 +42,10 @@ foreach (new LiskMigrationIterator($table) as $repository) { $file = $repository->getDetail('ssh-keyfile'); if ($file) { $secret = $file; - $type = PassphraseCredentialTypeSSHPrivateKeyFile::CREDENTIAL_TYPE; + $type = PassphraseSSHPrivateKeyFileCredentialType::CREDENTIAL_TYPE; } else { $secret = $repository->getDetail('ssh-key'); - $type = PassphraseCredentialTypeSSHPrivateKeyText::CREDENTIAL_TYPE; + $type = PassphraseSSHPrivateKeyTextCredentialType::CREDENTIAL_TYPE; } } diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 530101ae40..dea33f4aa2 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1260,17 +1260,17 @@ phutil_register_library_map(array( 'PassphraseCredentialTransactionEditor' => 'applications/passphrase/editor/PassphraseCredentialTransactionEditor.php', 'PassphraseCredentialTransactionQuery' => 'applications/passphrase/query/PassphraseCredentialTransactionQuery.php', 'PassphraseCredentialType' => 'applications/passphrase/credentialtype/PassphraseCredentialType.php', - 'PassphraseCredentialTypePassword' => 'applications/passphrase/credentialtype/PassphraseCredentialTypePassword.php', - 'PassphraseCredentialTypeSSHGeneratedKey' => 'applications/passphrase/credentialtype/PassphraseCredentialTypeSSHGeneratedKey.php', - 'PassphraseCredentialTypeSSHPrivateKey' => 'applications/passphrase/credentialtype/PassphraseCredentialTypeSSHPrivateKey.php', - 'PassphraseCredentialTypeSSHPrivateKeyFile' => 'applications/passphrase/credentialtype/PassphraseCredentialTypeSSHPrivateKeyFile.php', - 'PassphraseCredentialTypeSSHPrivateKeyText' => 'applications/passphrase/credentialtype/PassphraseCredentialTypeSSHPrivateKeyText.php', 'PassphraseCredentialViewController' => 'applications/passphrase/controller/PassphraseCredentialViewController.php', 'PassphraseDAO' => 'applications/passphrase/storage/PassphraseDAO.php', + 'PassphrasePasswordCredentialType' => 'applications/passphrase/credentialtype/PassphrasePasswordCredentialType.php', 'PassphrasePasswordKey' => 'applications/passphrase/keys/PassphrasePasswordKey.php', 'PassphraseQueryConduitAPIMethod' => 'applications/passphrase/conduit/PassphraseQueryConduitAPIMethod.php', 'PassphraseRemarkupRule' => 'applications/passphrase/remarkup/PassphraseRemarkupRule.php', + 'PassphraseSSHGeneratedKeyCredentialType' => 'applications/passphrase/credentialtype/PassphraseSSHGeneratedKeyCredentialType.php', 'PassphraseSSHKey' => 'applications/passphrase/keys/PassphraseSSHKey.php', + 'PassphraseSSHPrivateKeyCredentialType' => 'applications/passphrase/credentialtype/PassphraseSSHPrivateKeyCredentialType.php', + 'PassphraseSSHPrivateKeyFileCredentialType' => 'applications/passphrase/credentialtype/PassphraseSSHPrivateKeyFileCredentialType.php', + 'PassphraseSSHPrivateKeyTextCredentialType' => 'applications/passphrase/credentialtype/PassphraseSSHPrivateKeyTextCredentialType.php', 'PassphraseSchemaSpec' => 'applications/passphrase/storage/PassphraseSchemaSpec.php', 'PassphraseSearchIndexer' => 'applications/passphrase/search/PassphraseSearchIndexer.php', 'PassphraseSecret' => 'applications/passphrase/storage/PassphraseSecret.php', @@ -3933,6 +3933,7 @@ phutil_register_library_map(array( 'DivinerDAO', 'PhabricatorPolicyInterface', 'PhabricatorDestructibleInterface', + 'PhabricatorApplicationTransactionInterface', ), 'DivinerLivePublisher' => 'DivinerPublisher', 'DivinerLiveSymbol' => array( @@ -4641,17 +4642,17 @@ phutil_register_library_map(array( 'PassphraseCredentialTransactionEditor' => 'PhabricatorApplicationTransactionEditor', 'PassphraseCredentialTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PassphraseCredentialType' => 'Phobject', - 'PassphraseCredentialTypePassword' => 'PassphraseCredentialType', - 'PassphraseCredentialTypeSSHGeneratedKey' => 'PassphraseCredentialTypeSSHPrivateKey', - 'PassphraseCredentialTypeSSHPrivateKey' => 'PassphraseCredentialType', - 'PassphraseCredentialTypeSSHPrivateKeyFile' => 'PassphraseCredentialTypeSSHPrivateKey', - 'PassphraseCredentialTypeSSHPrivateKeyText' => 'PassphraseCredentialTypeSSHPrivateKey', 'PassphraseCredentialViewController' => 'PassphraseController', 'PassphraseDAO' => 'PhabricatorLiskDAO', + 'PassphrasePasswordCredentialType' => 'PassphraseCredentialType', 'PassphrasePasswordKey' => 'PassphraseAbstractKey', 'PassphraseQueryConduitAPIMethod' => 'PassphraseConduitAPIMethod', 'PassphraseRemarkupRule' => 'PhabricatorObjectRemarkupRule', + 'PassphraseSSHGeneratedKeyCredentialType' => 'PassphraseSSHPrivateKeyCredentialType', 'PassphraseSSHKey' => 'PassphraseAbstractKey', + 'PassphraseSSHPrivateKeyCredentialType' => 'PassphraseCredentialType', + 'PassphraseSSHPrivateKeyFileCredentialType' => 'PassphraseSSHPrivateKeyCredentialType', + 'PassphraseSSHPrivateKeyTextCredentialType' => 'PassphraseSSHPrivateKeyCredentialType', 'PassphraseSchemaSpec' => 'PhabricatorConfigSchemaSpec', 'PassphraseSearchIndexer' => 'PhabricatorSearchDocumentIndexer', 'PassphraseSecret' => 'PassphraseDAO', diff --git a/src/applications/diffusion/controller/DiffusionRepositoryCreateController.php b/src/applications/diffusion/controller/DiffusionRepositoryCreateController.php index 269523915e..9b6f4eee63 100644 --- a/src/applications/diffusion/controller/DiffusionRepositoryCreateController.php +++ b/src/applications/diffusion/controller/DiffusionRepositoryCreateController.php @@ -591,8 +591,8 @@ final class DiffusionRepositoryCreateController if ($this->isSSHProtocol($proto)) { $c_credential->setLabel(pht('SSH Key')); $c_credential->setCredentialType( - PassphraseCredentialTypeSSHPrivateKeyText::CREDENTIAL_TYPE); - $provides_type = PassphraseCredentialTypeSSHPrivateKey::PROVIDES_TYPE; + PassphraseSSHPrivateKeyTextCredentialType::CREDENTIAL_TYPE); + $provides_type = PassphraseSSHPrivateKeyCredentialType::PROVIDES_TYPE; $page->addRemarkupInstructions( pht( @@ -607,8 +607,8 @@ final class DiffusionRepositoryCreateController $c_credential->setLabel(pht('Password')); $c_credential->setAllowNull(true); $c_credential->setCredentialType( - PassphraseCredentialTypePassword::CREDENTIAL_TYPE); - $provides_type = PassphraseCredentialTypePassword::PROVIDES_TYPE; + PassphrasePasswordCredentialType::CREDENTIAL_TYPE); + $provides_type = PassphrasePasswordCredentialType::PROVIDES_TYPE; $page->addRemarkupInstructions( pht( @@ -663,7 +663,7 @@ final class DiffusionRepositoryCreateController pht('You must choose an SSH credential to connect over SSH.')); } - $ssh_type = PassphraseCredentialTypeSSHPrivateKey::PROVIDES_TYPE; + $ssh_type = PassphraseSSHPrivateKeyCredentialType::PROVIDES_TYPE; if ($credential->getProvidesType() !== $ssh_type) { $c_credential->setError(pht('Invalid')); $page->addPageError( @@ -674,7 +674,7 @@ final class DiffusionRepositoryCreateController } else if ($this->isUsernamePasswordProtocol($proto)) { if ($credential) { - $password_type = PassphraseCredentialTypePassword::PROVIDES_TYPE; + $password_type = PassphrasePasswordCredentialType::PROVIDES_TYPE; if ($credential->getProvidesType() !== $password_type) { $c_credential->setError(pht('Invalid')); $page->addPageError( diff --git a/src/applications/drydock/interface/command/DrydockSSHCommandInterface.php b/src/applications/drydock/interface/command/DrydockSSHCommandInterface.php index e691e0ecff..362e60e3c0 100644 --- a/src/applications/drydock/interface/command/DrydockSSHCommandInterface.php +++ b/src/applications/drydock/interface/command/DrydockSSHCommandInterface.php @@ -24,7 +24,7 @@ final class DrydockSSHCommandInterface extends DrydockCommandInterface { } if ($credential->getProvidesType() !== - PassphraseCredentialTypeSSHPrivateKey::PROVIDES_TYPE) { + PassphraseSSHPrivateKeyCredentialType::PROVIDES_TYPE) { throw new Exception(pht('Only private key credentials are supported.')); } diff --git a/src/applications/drydock/interface/filesystem/DrydockSFTPFilesystemInterface.php b/src/applications/drydock/interface/filesystem/DrydockSFTPFilesystemInterface.php index fe7d2d1cd3..41b126483d 100644 --- a/src/applications/drydock/interface/filesystem/DrydockSFTPFilesystemInterface.php +++ b/src/applications/drydock/interface/filesystem/DrydockSFTPFilesystemInterface.php @@ -16,7 +16,7 @@ final class DrydockSFTPFilesystemInterface extends DrydockFilesystemInterface { ->executeOne(); if ($credential->getProvidesType() !== - PassphraseCredentialTypeSSHPrivateKey::PROVIDES_TYPE) { + PassphraseSSHPrivateKeyCredentialType::PROVIDES_TYPE) { throw new Exception(pht('Only private key credentials are supported.')); } diff --git a/src/applications/harbormaster/step/HarbormasterHTTPRequestBuildStepImplementation.php b/src/applications/harbormaster/step/HarbormasterHTTPRequestBuildStepImplementation.php index dfc29cedc7..5d361b3de3 100644 --- a/src/applications/harbormaster/step/HarbormasterHTTPRequestBuildStepImplementation.php +++ b/src/applications/harbormaster/step/HarbormasterHTTPRequestBuildStepImplementation.php @@ -95,9 +95,9 @@ final class HarbormasterHTTPRequestBuildStepImplementation 'name' => pht('Credentials'), 'type' => 'credential', 'credential.type' - => PassphraseCredentialTypePassword::CREDENTIAL_TYPE, + => PassphrasePasswordCredentialType::CREDENTIAL_TYPE, 'credential.provides' - => PassphraseCredentialTypePassword::PROVIDES_TYPE, + => PassphrasePasswordCredentialType::PROVIDES_TYPE, ), ); } diff --git a/src/applications/passphrase/conduit/PassphraseQueryConduitAPIMethod.php b/src/applications/passphrase/conduit/PassphraseQueryConduitAPIMethod.php index 0163cd5046..18010efd73 100644 --- a/src/applications/passphrase/conduit/PassphraseQueryConduitAPIMethod.php +++ b/src/applications/passphrase/conduit/PassphraseQueryConduitAPIMethod.php @@ -78,7 +78,7 @@ final class PassphraseQueryConduitAPIMethod } switch ($credential->getCredentialType()) { - case PassphraseCredentialTypeSSHPrivateKeyFile::CREDENTIAL_TYPE: + case PassphraseSSHPrivateKeyFileCredentialType::CREDENTIAL_TYPE: if ($secret) { $material['file'] = $secret; } @@ -86,8 +86,8 @@ final class PassphraseQueryConduitAPIMethod $material['publicKey'] = $public_key; } break; - case PassphraseCredentialTypeSSHGeneratedKey::CREDENTIAL_TYPE: - case PassphraseCredentialTypeSSHPrivateKeyText::CREDENTIAL_TYPE: + case PassphraseSSHGeneratedKeyCredentialType::CREDENTIAL_TYPE: + case PassphraseSSHPrivateKeyTextCredentialType::CREDENTIAL_TYPE: if ($secret) { $material['privateKey'] = $secret; } @@ -95,7 +95,7 @@ final class PassphraseQueryConduitAPIMethod $material['publicKey'] = $public_key; } break; - case PassphraseCredentialTypePassword::CREDENTIAL_TYPE: + case PassphrasePasswordCredentialType::CREDENTIAL_TYPE: if ($secret) { $material['password'] = $secret; } diff --git a/src/applications/passphrase/credentialtype/PassphraseCredentialTypePassword.php b/src/applications/passphrase/credentialtype/PassphrasePasswordCredentialType.php similarity index 93% rename from src/applications/passphrase/credentialtype/PassphraseCredentialTypePassword.php rename to src/applications/passphrase/credentialtype/PassphrasePasswordCredentialType.php index bc55f1e4da..695059fd1d 100644 --- a/src/applications/passphrase/credentialtype/PassphraseCredentialTypePassword.php +++ b/src/applications/passphrase/credentialtype/PassphrasePasswordCredentialType.php @@ -1,6 +1,6 @@ loadAndValidateFromPHID( $phid, $viewer, - PassphraseCredentialTypePassword::PROVIDES_TYPE); + PassphrasePasswordCredentialType::PROVIDES_TYPE); } public function getPasswordEnvelope() { diff --git a/src/applications/passphrase/keys/PassphraseSSHKey.php b/src/applications/passphrase/keys/PassphraseSSHKey.php index 0790d5342e..f55eb3be93 100644 --- a/src/applications/passphrase/keys/PassphraseSSHKey.php +++ b/src/applications/passphrase/keys/PassphraseSSHKey.php @@ -9,13 +9,13 @@ final class PassphraseSSHKey extends PassphraseAbstractKey { return $key->loadAndValidateFromPHID( $phid, $viewer, - PassphraseCredentialTypeSSHPrivateKey::PROVIDES_TYPE); + PassphraseSSHPrivateKeyCredentialType::PROVIDES_TYPE); } public function getKeyfileEnvelope() { $credential = $this->requireCredential(); - $file_type = PassphraseCredentialTypeSSHPrivateKeyFile::CREDENTIAL_TYPE; + $file_type = PassphraseSSHPrivateKeyFileCredentialType::CREDENTIAL_TYPE; if ($credential->getCredentialType() != $file_type) { // If the credential does not store a file, write the key text out to a // temporary file so we can pass it to `ssh`. diff --git a/src/applications/repository/storage/__tests__/PhabricatorRepositoryURITestCase.php b/src/applications/repository/storage/__tests__/PhabricatorRepositoryURITestCase.php index d3535102de..0d13cf0e08 100644 --- a/src/applications/repository/storage/__tests__/PhabricatorRepositoryURITestCase.php +++ b/src/applications/repository/storage/__tests__/PhabricatorRepositoryURITestCase.php @@ -19,8 +19,8 @@ final class PhabricatorRepositoryURITestCase $http_secret = id(new PassphraseSecret())->setSecretData('quack')->save(); $http_credential = PassphraseCredential::initializeNewCredential($user) - ->setCredentialType(PassphraseCredentialTypePassword::CREDENTIAL_TYPE) - ->setProvidesType(PassphraseCredentialTypePassword::PROVIDES_TYPE) + ->setCredentialType(PassphrasePasswordCredentialType::CREDENTIAL_TYPE) + ->setProvidesType(PassphrasePasswordCredentialType::PROVIDES_TYPE) ->setUsername('duck') ->setSecretID($http_secret->getID()) ->save(); diff --git a/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldCredential.php b/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldCredential.php index 94fbe165a4..d842ef3d17 100644 --- a/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldCredential.php +++ b/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldCredential.php @@ -24,7 +24,7 @@ final class PhabricatorStandardCustomFieldCredential $all_types = PassphraseCredentialType::getAllProvidesTypes(); if (!in_array($provides_type, $all_types)) { - $provides_type = PassphraseCredentialTypePassword::PROVIDES_TYPE; + $provides_type = PassphrasePasswordCredentialType::PROVIDES_TYPE; } $credentials = id(new PassphraseCredentialQuery()) From 51bf2687f0c023f9bd91d05fb532878043cc5e2b Mon Sep 17 00:00:00 2001 From: Joshua Spence Date: Sun, 14 Jun 2015 14:12:38 +1000 Subject: [PATCH 30/50] Tidy up some text formatting in PhabricatorFeedConfigOptions Summary: Self-explanatory. Test Plan: Eyeball it. Reviewers: epriestley, #blessed_reviewers Reviewed By: epriestley, #blessed_reviewers Subscribers: epriestley, Korvin Differential Revision: https://secure.phabricator.com/D13268 --- .../config/PhabricatorFeedConfigOptions.php | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/applications/feed/config/PhabricatorFeedConfigOptions.php b/src/applications/feed/config/PhabricatorFeedConfigOptions.php index 2ee6a7bcaf..a3f7bf522f 100644 --- a/src/applications/feed/config/PhabricatorFeedConfigOptions.php +++ b/src/applications/feed/config/PhabricatorFeedConfigOptions.php @@ -36,22 +36,24 @@ final class PhabricatorFeedConfigOptions "public, and a login is not required to view them! This is ". "intended for things like open source projects that want to ". "expose an activity feed on the project homepage.\n\n". - "NOTE: You must also set `policy.allow-public` to true for this ". - "setting to work properly.")), + "NOTE: You must also set `%s` to true for this ". + "setting to work properly.", + 'policy.allow-public')), $this->newOption('feed.http-hooks', 'list', array()) ->setLocked(true) ->setSummary(pht('POST notifications of feed events.')) ->setDescription( pht( - "If you set this to a list of http URIs, when a feed story is ". - "published a task will be created for each uri that posts the ". - "story data to the uri. Daemons automagically retry failures 100 ". - "times, waiting \$fail_count * 60s between each subsequent ". - "failure. Be sure to keep the daemon console (/daemon/) open ". + "If you set this to a list of HTTP URIs, when a feed story is ". + "published a task will be created for each URI that posts the ". + "story data to the URI. Daemons automagically retry failures 100 ". + "times, waiting `\$fail_count * 60s` between each subsequent ". + "failure. Be sure to keep the daemon console (`%s`) open ". "while developing and testing your end points. You may need to". - "restart your daemons to start sending http requests.\n\n". - "NOTE: URIs are not validated, the URI must return http status ". - "200 within 30 seconds, and no permission checks are performed.")), + "restart your daemons to start sending HTTP requests.\n\n". + "NOTE: URIs are not validated, the URI must return HTTP status ". + "200 within 30 seconds, and no permission checks are performed.", + '/daemon/')), ); } From a1aedff90a867ab57dbc9f69a2ad9e2b17b754f8 Mon Sep 17 00:00:00 2001 From: Joshua Spence Date: Sun, 14 Jun 2015 14:12:57 +1000 Subject: [PATCH 31/50] Use PhutilInvalidStateException Summary: Use `PhutilInvalidStateException` in `PonderVoteEditor`. Test Plan: N/A Reviewers: epriestley, #blessed_reviewers Reviewed By: epriestley, #blessed_reviewers Subscribers: epriestley, Korvin Differential Revision: https://secure.phabricator.com/D13269 --- src/applications/ponder/editor/PonderVoteEditor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/applications/ponder/editor/PonderVoteEditor.php b/src/applications/ponder/editor/PonderVoteEditor.php index 2edb186787..9b9085eeab 100644 --- a/src/applications/ponder/editor/PonderVoteEditor.php +++ b/src/applications/ponder/editor/PonderVoteEditor.php @@ -25,7 +25,7 @@ final class PonderVoteEditor extends PhabricatorEditor { public function saveVote() { $actor = $this->requireActor(); if (!$this->votable) { - throw new Exception(pht('Must set votable before saving vote.')); + throw new PhutilInvalidStateException('setVotable'); } $votable = $this->votable; From 57e7c7c706c5c69064046d3959c52c460714df62 Mon Sep 17 00:00:00 2001 From: Joshua Spence Date: Sun, 14 Jun 2015 14:13:15 +1000 Subject: [PATCH 32/50] Tidy up some translation strings Summary: Parameterize command names in translation strings. Test Plan: Eyeball it. Reviewers: #blessed_reviewers, epriestley, eadler Reviewed By: #blessed_reviewers, epriestley, eadler Subscribers: epriestley, Korvin Differential Revision: https://secure.phabricator.com/D13270 --- .../lint/linter/PhabricatorJavelinLinter.php | 4 ++-- .../PhabricatorRemarkupFigletBlockInterpreter.php | 4 +++- .../PhabricatorRemarkupGraphvizBlockInterpreter.php | 7 +++++-- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/infrastructure/lint/linter/PhabricatorJavelinLinter.php b/src/infrastructure/lint/linter/PhabricatorJavelinLinter.php index d235dc889a..ac2957a4af 100644 --- a/src/infrastructure/lint/linter/PhabricatorJavelinLinter.php +++ b/src/infrastructure/lint/linter/PhabricatorJavelinLinter.php @@ -20,8 +20,8 @@ final class PhabricatorJavelinLinter extends ArcanistLinter { public function getInfoDescription() { return pht( 'This linter is intended for use with the Javelin JS library and '. - 'extensions. Use `javelinsymbols` to run Javelin rules on Javascript '. - 'source files.'); + 'extensions. Use `%s` to run Javelin rules on Javascript source files.', + 'javelinsymbols'); } private function getBinaryPath() { diff --git a/src/infrastructure/markup/interpreter/PhabricatorRemarkupFigletBlockInterpreter.php b/src/infrastructure/markup/interpreter/PhabricatorRemarkupFigletBlockInterpreter.php index 2314b998f3..c1b0d58055 100644 --- a/src/infrastructure/markup/interpreter/PhabricatorRemarkupFigletBlockInterpreter.php +++ b/src/infrastructure/markup/interpreter/PhabricatorRemarkupFigletBlockInterpreter.php @@ -10,7 +10,9 @@ final class PhabricatorRemarkupFigletBlockInterpreter public function markupContent($content, array $argv) { if (!Filesystem::binaryExists('figlet')) { return $this->markupError( - pht('Unable to locate the `figlet` binary. Install figlet.')); + pht( + 'Unable to locate the `%s` binary. Install figlet.', + 'figlet')); } $font = idx($argv, 'font', 'standard'); diff --git a/src/infrastructure/markup/interpreter/PhabricatorRemarkupGraphvizBlockInterpreter.php b/src/infrastructure/markup/interpreter/PhabricatorRemarkupGraphvizBlockInterpreter.php index d18ebbad10..e06432be6e 100644 --- a/src/infrastructure/markup/interpreter/PhabricatorRemarkupGraphvizBlockInterpreter.php +++ b/src/infrastructure/markup/interpreter/PhabricatorRemarkupGraphvizBlockInterpreter.php @@ -10,7 +10,9 @@ final class PhabricatorRemarkupGraphvizBlockInterpreter public function markupContent($content, array $argv) { if (!Filesystem::binaryExists('dot')) { return $this->markupError( - pht('Unable to locate the `dot` binary. Install Graphviz.')); + pht( + 'Unable to locate the `%s` binary. Install Graphviz.', + 'dot')); } $width = $this->parseDimension(idx($argv, 'width')); @@ -24,7 +26,8 @@ final class PhabricatorRemarkupGraphvizBlockInterpreter if ($err) { return $this->markupError( pht( - 'Execution of `dot` failed (#%d), check your syntax: %s', + 'Execution of `%s` failed (#%d), check your syntax: %s', + 'dot', $err, $stderr)); } From ede0b61260d9a1246b0b0adefa99e744a6cf5eae Mon Sep 17 00:00:00 2001 From: Joshua Spence Date: Sun, 14 Jun 2015 16:03:00 +1000 Subject: [PATCH 33/50] Update library map Auditors: epriestley --- src/__phutil_library_map__.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index dea33f4aa2..e0d447aa5a 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -3933,7 +3933,6 @@ phutil_register_library_map(array( 'DivinerDAO', 'PhabricatorPolicyInterface', 'PhabricatorDestructibleInterface', - 'PhabricatorApplicationTransactionInterface', ), 'DivinerLivePublisher' => 'DivinerPublisher', 'DivinerLiveSymbol' => array( From 934285a6d3d2aac42067edeb9b623eac45d28d0f Mon Sep 17 00:00:00 2001 From: Joshua Spence Date: Mon, 15 Jun 2015 07:30:05 +1000 Subject: [PATCH 34/50] Mark some PhabricatorApplication methods as final Summary: I don't believe that any subclass should override these methods. Test Plan: `arc unit` Reviewers: #blessed_reviewers, epriestley Reviewed By: #blessed_reviewers, epriestley Subscribers: epriestley, Korvin Differential Revision: https://secure.phabricator.com/D13265 --- .../base/PhabricatorApplication.php | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/applications/base/PhabricatorApplication.php b/src/applications/base/PhabricatorApplication.php index 0e49bad23d..47baf5150c 100644 --- a/src/applications/base/PhabricatorApplication.php +++ b/src/applications/base/PhabricatorApplication.php @@ -17,7 +17,7 @@ abstract class PhabricatorApplication implements PhabricatorPolicyInterface { const GROUP_ADMIN = 'admin'; const GROUP_DEVELOPER = 'developer'; - public static function getApplicationGroups() { + final public static function getApplicationGroups() { return array( self::GROUP_CORE => pht('Core Applications'), self::GROUP_UTILITIES => pht('Utilities'), @@ -35,7 +35,7 @@ abstract class PhabricatorApplication implements PhabricatorPolicyInterface { return pht('%s Application', $this->getName()); } - public function isInstalled() { + final public function isInstalled() { if (!$this->canUninstall()) { return true; } @@ -133,7 +133,7 @@ abstract class PhabricatorApplication implements PhabricatorPolicyInterface { return true; } - public function getPHID() { + final public function getPHID() { return 'PHID-APPS-'.get_class($this); } @@ -145,7 +145,7 @@ abstract class PhabricatorApplication implements PhabricatorPolicyInterface { return null; } - public function getApplicationURI($path = '') { + final public function getApplicationURI($path = '') { return $this->getBaseURI().ltrim($path, '/'); } @@ -169,7 +169,7 @@ abstract class PhabricatorApplication implements PhabricatorPolicyInterface { return null; } - public function getHelpMenuItems(PhabricatorUser $viewer) { + final public function getHelpMenuItems(PhabricatorUser $viewer) { $items = array(); $articles = $this->getHelpDocumentationArticles($viewer); @@ -249,7 +249,7 @@ abstract class PhabricatorApplication implements PhabricatorPolicyInterface { return false; } - protected function getInboundEmailSupportLink() { + final protected function getInboundEmailSupportLink() { return PhabricatorEnv::getDocLink('Configuring Inbound Email'); } @@ -286,7 +286,7 @@ abstract class PhabricatorApplication implements PhabricatorPolicyInterface { * @return string * @task ui */ - public static function formatStatusCount( + final public static function formatStatusCount( $count, $limit_string = '%s', $base_string = '%d') { @@ -359,7 +359,7 @@ abstract class PhabricatorApplication implements PhabricatorPolicyInterface { /* -( Application Management )--------------------------------------------- */ - public static function getByClass($class_name) { + final public static function getByClass($class_name) { $selected = null; $applications = self::getAllApplications(); @@ -377,7 +377,7 @@ abstract class PhabricatorApplication implements PhabricatorPolicyInterface { return $selected; } - public static function getAllApplications() { + final public static function getAllApplications() { static $applications; if ($applications === null) { @@ -401,7 +401,7 @@ abstract class PhabricatorApplication implements PhabricatorPolicyInterface { return $applications; } - public static function getAllInstalledApplications() { + final public static function getAllInstalledApplications() { $all_applications = self::getAllApplications(); $apps = array(); foreach ($all_applications as $app) { @@ -426,7 +426,7 @@ abstract class PhabricatorApplication implements PhabricatorPolicyInterface { * @return bool True if the class is installed. * @task meta */ - public static function isClassInstalled($class) { + final public static function isClassInstalled($class) { return self::getByClass($class)->isInstalled(); } @@ -443,7 +443,7 @@ abstract class PhabricatorApplication implements PhabricatorPolicyInterface { * @return bool True if the class is installed for the viewer. * @task meta */ - public static function isClassInstalledForViewer( + final public static function isClassInstalledForViewer( $class, PhabricatorUser $viewer) { @@ -502,7 +502,7 @@ abstract class PhabricatorApplication implements PhabricatorPolicyInterface { return array(); } - private function getCustomPolicySetting($capability) { + final private function getCustomPolicySetting($capability) { if (!$this->isCapabilityEditable($capability)) { return null; } @@ -528,7 +528,7 @@ abstract class PhabricatorApplication implements PhabricatorPolicyInterface { } - private function getCustomCapabilitySpecification($capability) { + final private function getCustomCapabilitySpecification($capability) { $custom = $this->getCustomCapabilities(); if (!isset($custom[$capability])) { throw new Exception(pht("Unknown capability '%s'!", $capability)); @@ -536,7 +536,7 @@ abstract class PhabricatorApplication implements PhabricatorPolicyInterface { return $custom[$capability]; } - public function getCapabilityLabel($capability) { + final public function getCapabilityLabel($capability) { switch ($capability) { case PhabricatorPolicyCapability::CAN_VIEW: return pht('Can Use Application'); @@ -552,7 +552,7 @@ abstract class PhabricatorApplication implements PhabricatorPolicyInterface { return null; } - public function isCapabilityEditable($capability) { + final public function isCapabilityEditable($capability) { switch ($capability) { case PhabricatorPolicyCapability::CAN_VIEW: return $this->canUninstall(); @@ -564,7 +564,7 @@ abstract class PhabricatorApplication implements PhabricatorPolicyInterface { } } - public function getCapabilityCaption($capability) { + final public function getCapabilityCaption($capability) { switch ($capability) { case PhabricatorPolicyCapability::CAN_VIEW: if (!$this->canUninstall()) { @@ -582,7 +582,7 @@ abstract class PhabricatorApplication implements PhabricatorPolicyInterface { } } - public function getCapabilityTemplatePHIDType($capability) { + final public function getCapabilityTemplatePHIDType($capability) { switch ($capability) { case PhabricatorPolicyCapability::CAN_VIEW: case PhabricatorPolicyCapability::CAN_EDIT: From d9af48cc52aa11c1d7ce5420742cbad438f942cd Mon Sep 17 00:00:00 2001 From: Joshua Spence Date: Mon, 15 Jun 2015 07:32:12 +1000 Subject: [PATCH 35/50] Add language specification to code blocks Summary: Add the language specification to code blocks in documentation. Test Plan: Eyeball it. Reviewers: chad, #blessed_reviewers, epriestley Reviewed By: #blessed_reviewers, epriestley Subscribers: epriestley, Korvin Differential Revision: https://secure.phabricator.com/D13277 --- src/docs/contributor/css_coding_standards.diviner | 2 ++ src/docs/contributor/php_coding_standards.diviner | 9 +++++++++ 2 files changed, 11 insertions(+) diff --git a/src/docs/contributor/css_coding_standards.diviner b/src/docs/contributor/css_coding_standards.diviner index 795d0952f6..c321124eae 100644 --- a/src/docs/contributor/css_coding_standards.diviner +++ b/src/docs/contributor/css_coding_standards.diviner @@ -22,6 +22,7 @@ Great Z-Index War where all indexes grow without bound in an endless arms race. Phabricator's preprocessor provides some standard color variables. You can reference these with `{$color}`. For example: + lang=css span.critical { color: {$red}; } @@ -78,6 +79,7 @@ adjust behavior responsively. In particular: Since many rules are specific to handheld devices, the `.device` class selects either tablets or phones: + lang=css .device { /* Phone or tablet (not desktop). */ } diff --git a/src/docs/contributor/php_coding_standards.diviner b/src/docs/contributor/php_coding_standards.diviner index 03f0bc158b..ff62ebe98e 100644 --- a/src/docs/contributor/php_coding_standards.diviner +++ b/src/docs/contributor/php_coding_standards.diviner @@ -67,6 +67,7 @@ guidelines, you probably don't need to read this super thoroughly. **if/else:** + lang=php if ($some_variable > 3) { // ... } else if ($some_variable === null) { @@ -81,6 +82,7 @@ use the "endif" construct, and write "else if" as two words. **for:** + lang=php for ($ii = 0; $ii < 10; $ii++) { // ... } @@ -90,12 +92,14 @@ visually and react better to "Find Next..." in editors. **foreach:** + lang=php foreach ($map as $key => $value) { // ... } **switch:** + lang=php switch ($value) { case 1: // ... @@ -115,6 +119,7 @@ visually and react better to "Find Next..." in editors. **array literals:** + lang=php $junk = array( 'nuts', 'bolts', @@ -126,6 +131,7 @@ diffs which add elements to the array affect only one line. **operators:** + lang=php $a + $b; // Put spaces around operators. $omg.$lol; // Exception: no spaces around string concatenation. $arr[] = $element; // Couple [] with the array when appending. @@ -133,6 +139,7 @@ diffs which add elements to the array affect only one line. **function/method calls:** + lang=php // One line eject($cargo); @@ -143,6 +150,7 @@ diffs which add elements to the array affect only one line. **function/method definitions:** + lang=php function example_function($base_value, $additional_value) { return $base_value + $additional_value; } @@ -157,6 +165,7 @@ diffs which add elements to the array affect only one line. **class:** + lang=php class Dog extends Animal { const CIRCLES_REQUIRED_TO_LIE_DOWN = 3; From 0aab026f7e067a9966fa4bbff566f3f53f7f41d4 Mon Sep 17 00:00:00 2001 From: Joshua Spence Date: Mon, 15 Jun 2015 07:32:28 +1000 Subject: [PATCH 36/50] Minor formatting changes for some documentation Summary: Self explanatory. Test Plan: Eyeball it. Reviewers: epriestley, #blessed_reviewers Reviewed By: epriestley, #blessed_reviewers Subscribers: epriestley, Korvin Differential Revision: https://secure.phabricator.com/D13278 --- src/docs/flavor/php_pitfalls.diviner | 298 +++++++++++++++------------ 1 file changed, 163 insertions(+), 135 deletions(-) diff --git a/src/docs/flavor/php_pitfalls.diviner b/src/docs/flavor/php_pitfalls.diviner index 09e0f108f0..0ffcaa42da 100644 --- a/src/docs/flavor/php_pitfalls.diviner +++ b/src/docs/flavor/php_pitfalls.diviner @@ -4,11 +4,11 @@ This document discusses difficult traps and pitfalls in PHP, and how to avoid, work around, or at least understand them. -= array_merge() in Incredibly Slow When Merging A List of Arrays = += `array_merge()` in Incredibly Slow When Merging A List of Arrays = If you merge a list of arrays like this: - COUNTEREXAMPLE + COUNTEREXAMPLE, lang=php $result = array(); foreach ($list_of_lists as $one_list) { $result = array_merge($result, $one_list); @@ -21,18 +21,19 @@ you iterate. In a libphutil environment, you can use @{function@libphutil:array_mergev} instead. -= var_export() Hates Baby Animals = += `var_export()` Hates Baby Animals = -If you try to var_export() an object that contains recursive references, your +If you try to `var_export()` an object that contains recursive references, your program will terminate. You have no chance to intercept or react to this or -otherwise stop it from happening. Avoid var_export() unless you are certain -you have only simple data. You can use print_r() or var_dump() to display +otherwise stop it from happening. Avoid `var_export()` unless you are certain +you have only simple data. You can use `print_r()` or `var_dump()` to display complex variables safely. -= isset(), empty() and Truthiness = += `isset()`, `empty()` and Truthiness = A value is "truthy" if it evaluates to true in an `if` clause: + lang=php $value = something(); if ($value) { // Value is truthy. @@ -59,16 +60,16 @@ empty comments) is wrong in PHP: This is wrong because it prevents users from making the comment "0". //THIS COMMENT IS TOTALLY AWESOME AND I MAKE IT ALL THE TIME SO YOU HAD BETTER NOT -BREAK IT!!!// A better test is probably strlen(). +BREAK IT!!!// A better test is probably `strlen()`. In addition to truth tests with `if`, PHP has two special truthiness operators -which look like functions but aren't: empty() and isset(). These operators help -deal with undeclared variables. +which look like functions but aren't: `empty()` and `isset()`. These operators +help deal with undeclared variables. In PHP, there are two major cases where you get undeclared variables -- either you directly use a variable without declaring it: - COUNTEREXAMPLE + COUNTEREXAMPLE, lang=php function f() { if ($not_declared) { // ... @@ -84,218 +85,245 @@ you directly use a variable without declaring it: } } -When you do either of these, PHP issues a warning. Avoid these warnings by using -empty() and isset() to do tests that are safe to apply to undeclared variables. +When you do either of these, PHP issues a warning. Avoid these warnings by +using `empty()` and `isset()` to do tests that are safe to apply to undeclared +variables. -empty() evaluates truthiness exactly opposite of if(). isset() returns true for -everything except null. This is the truth table: +`empty()` evaluates truthiness exactly opposite of `if()`. `isset()` returns +`true` for everything except `null`. This is the truth table: - VALUE if() empty() isset() +| Value | `if()` | `empty()` | `isset()` | +|-------|--------|-----------|-----------| +| `null` | `false` | `true` | `false` | +| `0` | `false` | `true` | `true` | +| `0.0` | `false` | `true` | `true` | +| `"0"` | `false` | `true` | `true` | +| `""` | `false` | `true` | `true` | +| `false` | `false` | `true` | `true` | +| `array()` | `false` | `true` | `true` | +| Everything else | `true` | `false` | `true` | - null false true false - 0 false true true - 0.0 false true true - "0" false true true - "" false true true - false false true true - array() false true true - EVERYTHING ELSE true false true +The value of these operators is that they accept undeclared variables and do +not issue a warning. Specifically, if you try to do this you get a warning: -The value of these operators is that they accept undeclared variables and do not -issue a warning. Specifically, if you try to do this you get a warning: - - COUNTEREXAMPLE - if ($not_previously_declared) { // PHP Notice: Undefined variable! - // ... - } +```lang=php, COUNTEREXAMPLE +if ($not_previously_declared) { // PHP Notice: Undefined variable! + // ... +} +``` But these are fine: - if (empty($not_previously_declared)) { // No notice, returns true. - // ... - } - if (isset($not_previously_declared)) { // No notice, returns false. - // ... - } +```lang=php +if (empty($not_previously_declared)) { // No notice, returns true. + // ... +} +if (isset($not_previously_declared)) { // No notice, returns false. + // ... +} +``` -So, isset() really means is_declared_and_is_set_to_something_other_than_null(). -empty() really means is_falsey_or_is_not_declared(). Thus: +So, `isset()` really means +`is_declared_and_is_set_to_something_other_than_null()`. `empty()` really means +`is_falsey_or_is_not_declared()`. Thus: - - If a variable is known to exist, test falsiness with if (!$v), not empty(). - In particular, test for empty arrays with if (!$array). There is no reason - to ever use empty() on a declared variable. - - When you use isset() on an array key, like isset($array['key']), it will - evaluate to "false" if the key exists but has the value null! Test for index - existence with array_key_exists(). + - If a variable is known to exist, test falsiness with `if (!$v)`, not + `empty()`. In particular, test for empty arrays with `if (!$array)`. There + is no reason to ever use `empty()` on a declared variable. + - When you use `isset()` on an array key, like `isset($array['key'])`, it + will evaluate to "false" if the key exists but has the value `null`! Test + for index existence with `array_key_exists()`. -Put another way, use isset() if you want to type "if ($value !== null)" but are -testing something that may not be declared. Use empty() if you want to type -"if (!$value)" but you are testing something that may not be declared. +Put another way, use `isset()` if you want to type `if ($value !== null)` but +are testing something that may not be declared. Use `empty()` if you want to +type `if (!$value)` but you are testing something that may not be declared. = usort(), uksort(), and uasort() are Slow = This family of functions is often extremely slow for large datasets. You should avoid them if at all possible. Instead, build an array which contains surrogate keys that are naturally sortable with a function that uses native comparison -(e.g., sort(), asort(), ksort(), or natcasesort()). Sort this array instead, and -use it to reorder the original array. +(e.g., `sort()`, `asort()`, `ksort()`, or `natcasesort()`). Sort this array +instead, and use it to reorder the original array. In a libphutil environment, you can often do this easily with @{function@libphutil:isort} or @{function@libphutil:msort}. -= array_intersect() and array_diff() are Also Slow = += `array_intersect()` and `array_diff()` are Also Slow = These functions are much slower for even moderately large inputs than -array_intersect_key() and array_diff_key(), because they can not make the +`array_intersect_key()` and `array_diff_key()`, because they can not make the assumption that their inputs are unique scalars as the `key` varieties can. Strongly prefer the `key` varieties. -= array_uintersect() and array_udiff() are Definitely Slow Too = += `array_uintersect()` and `array_udiff()` are Definitely Slow Too = These functions have the problems of both the `usort()` family and the `array_diff()` family. Avoid them. -= foreach() Does Not Create Scope = += `foreach()` Does Not Create Scope = -Variables survive outside of the scope of foreach(). More problematically, -references survive outside of the scope of foreach(). This code mutates +Variables survive outside of the scope of `foreach()`. More problematically, +references survive outside of the scope of `foreach()`. This code mutates `$array` because the reference leaks from the first loop to the second: - COUNTEREXAMPLE - $array = range(1, 3); - echo implode(',', $array); // Outputs '1,2,3' - foreach ($array as &$value) {} - echo implode(',', $array); // Outputs '1,2,3' - foreach ($array as $value) {} - echo implode(',', $array); // Outputs '1,2,2' +```lang=php, COUNTEREXAMPLE +$array = range(1, 3); +echo implode(',', $array); // Outputs '1,2,3' +foreach ($array as &$value) {} +echo implode(',', $array); // Outputs '1,2,3' +foreach ($array as $value) {} +echo implode(',', $array); // Outputs '1,2,2' +``` The easiest way to avoid this is to avoid using foreach-by-reference. If you do use it, unset the reference after the loop: - foreach ($array as &$value) { - // ... - } - unset($value); +```lang=php +foreach ($array as &$value) { + // ... +} +unset($value); +``` -= unserialize() is Incredibly Slow on Large Datasets = += `unserialize()` is Incredibly Slow on Large Datasets = -The performance of unserialize() is nonlinear in the number of zvals you -unserialize, roughly O(N^2). +The performance of `unserialize()` is nonlinear in the number of zvals you +unserialize, roughly `O(N^2)`. - zvals approximate time - 10000 5ms - 100000 85ms - 1000000 8,000ms - 10000000 72 billion years +| zvals | Approximate time | +|-------|------------------| +| 10000 |5ms | +| 100000 | 85ms | +| 1000000 | 8,000ms | +| 10000000 | 72 billion years | += `call_user_func()` Breaks References = -= call_user_func() Breaks References = - -If you use call_use_func() to invoke a function which takes parameters by +If you use `call_use_func()` to invoke a function which takes parameters by reference, the variables you pass in will have their references broken and will emerge unmodified. That is, if you have a function that takes references: - function add_one(&$v) { - $v++; - } +```lang=php +function add_one(&$v) { + $v++; +} +``` -...and you call it with call_user_func(): +...and you call it with `call_user_func()`: - COUNTEREXAMPLE - $x = 41; - call_user_func('add_one', $x); +```lang=php, COUNTEREXAMPLE +$x = 41; +call_user_func('add_one', $x); +``` -...`$x` will not be modified. The solution is to use call_user_func_array() +...`$x` will not be modified. The solution is to use `call_user_func_array()` and wrap the reference in an array: - $x = 41; - call_user_func_array( - 'add_one', - array(&$x)); // Note '&$x'! +```lang=php +$x = 41; +call_user_func_array( + 'add_one', + array(&$x)); // Note '&$x'! +``` This will work as expected. -= You Can't Throw From __toString() = += You Can't Throw From `__toString()` = -If you throw from __toString(), your program will terminate uselessly and you +If you throw from `__toString()`, your program will terminate uselessly and you won't get the exception. = An Object Can Have Any Scalar as a Property = Object properties are not limited to legal variable names: - $property = '!@#$%^&*()'; - $obj->$property = 'zebra'; - echo $obj->$property; // Outputs 'zebra'. +```lang=php +$property = '!@#$%^&*()'; +$obj->$property = 'zebra'; +echo $obj->$property; // Outputs 'zebra'. +``` So, don't make assumptions about property names. -= There is an (object) Cast = += There is an `(object)` Cast = You can cast a dictionary into an object. - $obj = (object)array('flavor' => 'coconut'); - echo $obj->flavor; // Outputs 'coconut'. - echo get_class($obj); // Outputs 'stdClass'. +```lang=php +$obj = (object)array('flavor' => 'coconut'); +echo $obj->flavor; // Outputs 'coconut'. +echo get_class($obj); // Outputs 'stdClass'. +``` This is occasionally useful, mostly to force an object to become a Javascript -dictionary (vs a list) when passed to json_encode(). +dictionary (vs a list) when passed to `json_encode()`. -= Invoking "new" With an Argument Vector is Really Hard = += Invoking `new` With an Argument Vector is Really Hard = -If you have some `$class_name` and some `$argv` of constructor -arguments and you want to do this: +If you have some `$class_name` and some `$argv` of constructor arguments +and you want to do this: - new $class_name($argv[0], $argv[1], ...); +```lang=php +new $class_name($argv[0], $argv[1], ...); +``` ...you'll probably invent a very interesting, very novel solution that is very wrong. In a libphutil environment, solve this problem with -@{function@libphutil:newv}. Elsewhere, copy newv()'s implementation. +@{function@libphutil:newv}. Elsewhere, copy `newv()`'s implementation. = Equality is not Transitive = This isn't terribly surprising since equality isn't transitive in a lot of -languages, but the == operator is not transitive: +languages, but the `==` operator is not transitive: - $a = ''; $b = 0; $c = '0a'; - $a == $b; // true - $b == $c; // true - $c == $a; // false! +```lang=php +$a = ''; $b = 0; $c = '0a'; +$a == $b; // true +$b == $c; // true +$c == $a; // false! +``` When either operand is an integer, the other operand is cast to an integer -before comparison. Avoid this and similar pitfalls by using the === operator, +before comparison. Avoid this and similar pitfalls by using the `===` operator, which is transitive. = All 676 Letters in the Alphabet = This doesn't do what you'd expect it to do in C: - for ($c = 'a'; $c <= 'z'; $c++) { - // ... - } +```lang=php +for ($c = 'a'; $c <= 'z'; $c++) { + // ... +} +``` -This is because the successor to 'z' is 'aa', which is "less than" 'z'. The -loop will run for ~700 iterations until it reaches 'zz' and terminates. That is, -`$c` will take on these values: +This is because the successor to `z` is `aa`, which is "less than" `z`. +The loop will run for ~700 iterations until it reaches `zz` and terminates. +That is, `$c` will take on these values: - a - b - ... - y - z - aa // loop continues because 'aa' <= 'z' - ab - ... - mf - mg - ... - zw - zx - zy - zz // loop now terminates because 'zz' > 'z' +``` +a +b +... +y +z +aa // loop continues because 'aa' <= 'z' +ab +... +mf +mg +... +zw +zx +zy +zz // loop now terminates because 'zz' > 'z' +``` Instead, use this loop: - foreach (range('a', 'z') as $c) { - // ... - } +```lang=php +foreach (range('a', 'z') as $c) { + // ... +} +``` From 69a9b5c3a33e2a657bd8f83996d9b3e42b54c5bc Mon Sep 17 00:00:00 2001 From: Joshua Spence Date: Mon, 15 Jun 2015 07:34:14 +1000 Subject: [PATCH 37/50] Fix method visibilities Summary: This should (hopefully) be the last one of these since D13185 has landed. Test Plan: `arc unit` Reviewers: epriestley, #blessed_reviewers Reviewed By: epriestley, #blessed_reviewers Subscribers: epriestley, Korvin Differential Revision: https://secure.phabricator.com/D13284 --- .../maniphest/query/ManiphestTaskSearchEngine.php | 8 ++++---- .../query/PhabricatorSpacesNamespaceSearchEngine.php | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/applications/maniphest/query/ManiphestTaskSearchEngine.php b/src/applications/maniphest/query/ManiphestTaskSearchEngine.php index 8a875202f1..ae5b5353c7 100644 --- a/src/applications/maniphest/query/ManiphestTaskSearchEngine.php +++ b/src/applications/maniphest/query/ManiphestTaskSearchEngine.php @@ -43,7 +43,7 @@ final class ManiphestTaskSearchEngine ->needProjectPHIDs(true); } - public function buildCustomSearchFields() { + protected function buildCustomSearchFields() { return array( id(new PhabricatorSearchOwnersField()) ->setLabel(pht('Assigned To')) @@ -105,7 +105,7 @@ final class ManiphestTaskSearchEngine ); } - public function getDefaultFieldOrder() { + protected function getDefaultFieldOrder() { return array( 'assignedPHIDs', 'projectPHIDs', @@ -128,7 +128,7 @@ final class ManiphestTaskSearchEngine ); } - public function getHiddenFields() { + protected function getHiddenFields() { $keys = array(); if ($this->getIsBoardView()) { @@ -140,7 +140,7 @@ final class ManiphestTaskSearchEngine return $keys; } - public function buildQueryFromParameters(array $map) { + protected function buildQueryFromParameters(array $map) { $query = id(new ManiphestTaskQuery()) ->needProjectPHIDs(true); diff --git a/src/applications/spaces/query/PhabricatorSpacesNamespaceSearchEngine.php b/src/applications/spaces/query/PhabricatorSpacesNamespaceSearchEngine.php index c12ad9e098..6a7ea7ca4a 100644 --- a/src/applications/spaces/query/PhabricatorSpacesNamespaceSearchEngine.php +++ b/src/applications/spaces/query/PhabricatorSpacesNamespaceSearchEngine.php @@ -15,7 +15,7 @@ final class PhabricatorSpacesNamespaceSearchEngine return new PhabricatorSpacesNamespaceQuery(); } - public function buildCustomSearchFields() { + protected function buildCustomSearchFields() { return array( id(new PhabricatorSearchThreeStateField()) ->setLabel(pht('Active')) @@ -27,7 +27,7 @@ final class PhabricatorSpacesNamespaceSearchEngine ); } - public function buildQueryFromParameters(array $map) { + protected function buildQueryFromParameters(array $map) { $query = $this->newQuery(); if ($map['active']) { From 070da828640778112e1b75ae0cafe8d5569f1283 Mon Sep 17 00:00:00 2001 From: Joshua Spence Date: Mon, 15 Jun 2015 07:38:28 +1000 Subject: [PATCH 38/50] Remove backticks from SQL statements Summary: Remove backticks from SQL statements for consistency. In //most// places, we don't use backticks around table/field names, so at least be consistent about this. Test Plan: Learned what backticks are used for in MySQL. Reviewers: eadler, epriestley, #blessed_reviewers Reviewed By: eadler, epriestley, #blessed_reviewers Subscribers: epriestley Differential Revision: https://secure.phabricator.com/D13267 --- .../garbagecollector/HeraldTranscriptGarbageCollector.php | 2 +- src/applications/ponder/editor/PonderVoteEditor.php | 4 ++-- .../controller/PhabricatorXHProfSampleListController.php | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/applications/herald/garbagecollector/HeraldTranscriptGarbageCollector.php b/src/applications/herald/garbagecollector/HeraldTranscriptGarbageCollector.php index 18e3ce0b7d..583778e535 100644 --- a/src/applications/herald/garbagecollector/HeraldTranscriptGarbageCollector.php +++ b/src/applications/herald/garbagecollector/HeraldTranscriptGarbageCollector.php @@ -20,7 +20,7 @@ final class HeraldTranscriptGarbageCollector conditionTranscripts = "", applyTranscripts = "", garbageCollected = 1 - WHERE garbageCollected = 0 AND `time` < %d + WHERE garbageCollected = 0 AND time < %d LIMIT 100', $table->getTableName(), time() - $ttl); diff --git a/src/applications/ponder/editor/PonderVoteEditor.php b/src/applications/ponder/editor/PonderVoteEditor.php index 9b9085eeab..58212a08d9 100644 --- a/src/applications/ponder/editor/PonderVoteEditor.php +++ b/src/applications/ponder/editor/PonderVoteEditor.php @@ -63,8 +63,8 @@ final class PonderVoteEditor extends PhabricatorEditor { queryfx($conn, 'UPDATE %T as t - SET t.`voteCount` = t.`voteCount` + %d - WHERE t.`PHID` = %s', + SET t.voteCount = t.voteCount + %d + WHERE t.PHID = %s', $votable->getTableName(), $delta, $votable->getVotablePHID()); diff --git a/src/applications/xhprof/controller/PhabricatorXHProfSampleListController.php b/src/applications/xhprof/controller/PhabricatorXHProfSampleListController.php index c96787cdf0..d04d361fef 100644 --- a/src/applications/xhprof/controller/PhabricatorXHProfSampleListController.php +++ b/src/applications/xhprof/controller/PhabricatorXHProfSampleListController.php @@ -18,18 +18,18 @@ final class PhabricatorXHProfSampleListController switch ($this->view) { case 'sampled': - $clause = '`sampleRate` > 0'; + $clause = 'sampleRate > 0'; $show_type = false; break; case 'my-runs': $clause = qsprintf( id(new PhabricatorXHProfSample())->establishConnection('r'), - '`sampleRate` = 0 AND `userPHID` = %s', + 'sampleRate = 0 AND userPHID = %s', $request->getUser()->getPHID()); $show_type = false; break; case 'manual': - $clause = '`sampleRate` = 0'; + $clause = 'sampleRate = 0'; $show_type = false; break; case 'all': From 32f4c962fc6eff7729c4b6e53022f93eca176ce0 Mon Sep 17 00:00:00 2001 From: Joshua Spence Date: Mon, 15 Jun 2015 07:55:08 +1000 Subject: [PATCH 39/50] Remove "@stable" annotations Summary: See D13285. Test Plan: N/A Reviewers: #blessed_reviewers, epriestley Reviewed By: #blessed_reviewers, epriestley Subscribers: epriestley, Korvin Differential Revision: https://secure.phabricator.com/D13287 --- .../storage/configuration/DatabaseConfigurationProvider.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/infrastructure/storage/configuration/DatabaseConfigurationProvider.php b/src/infrastructure/storage/configuration/DatabaseConfigurationProvider.php index 9c12607efa..abd0c9fb40 100644 --- a/src/infrastructure/storage/configuration/DatabaseConfigurationProvider.php +++ b/src/infrastructure/storage/configuration/DatabaseConfigurationProvider.php @@ -1,8 +1,5 @@ Date: Mon, 15 Jun 2015 08:32:08 +1000 Subject: [PATCH 40/50] Remove `break` from hunk migration Summary: This `break` statement causes `./bin/hunks migrate` to only migrate one-hunk-at-a-time, which is unnecessary and slightly misleading. Instead, allow the script to migrate //all// legacy hunks to modern storage. In particular, this means that we can recommend that installs run this command sometime before D13222 is landed. Test Plan: It's a pain to setup the data necessary to test this, but this is identical to the change that I made on our production install when I migrated our hunk storage. Reviewers: epriestley, #blessed_reviewers Reviewed By: epriestley, #blessed_reviewers Subscribers: epriestley, Korvin Differential Revision: https://secure.phabricator.com/D13288 --- .../management/PhabricatorHunksManagementMigrateWorkflow.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/applications/differential/management/PhabricatorHunksManagementMigrateWorkflow.php b/src/applications/differential/management/PhabricatorHunksManagementMigrateWorkflow.php index 552376d2e0..90c0be1717 100644 --- a/src/applications/differential/management/PhabricatorHunksManagementMigrateWorkflow.php +++ b/src/applications/differential/management/PhabricatorHunksManagementMigrateWorkflow.php @@ -48,8 +48,6 @@ final class PhabricatorHunksManagementMigrateWorkflow new PhutilNumber($diff_len), sprintf('%.1f%%', 100 * ($diff_len / $old_len)))); } - - break; } if ($saw_any_rows) { From 2fbc65e3964991ed4b358d19efcd7b8fd5fa1a9d Mon Sep 17 00:00:00 2001 From: epriestley Date: Sun, 14 Jun 2015 15:35:32 -0700 Subject: [PATCH 41/50] Call didRejectResult() in DiffusionCommitQuery properly Summary: Ref T4345. This error is per object-type in the query implementations, not a mail/permissions issue. Without `didRejectResult()`, we can't distinguish between "restricted" and "unknown" for objects filtered by `willFilterPage()`. - Call `didRejectResult()` on commits. - Make `didRejectResult()` handle both existing policy exceptions and filtering. - Recover from partial objects (like commits) which are missing attached data required to figure out policies. Test Plan: Saw "Restricted Diffusion Commit" instead of "Unknown Object (Diffusion Commit)" when viewing nonvisible commit handle in Maniphest. Reviewers: btrahan, joshuaspence Reviewed By: joshuaspence Subscribers: epriestley Maniphest Tasks: T4345 Differential Revision: https://secure.phabricator.com/D13289 --- .../diffusion/query/DiffusionCommitQuery.php | 1 + .../policy/PhabricatorPolicyAwareQuery.php | 18 +++++++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/applications/diffusion/query/DiffusionCommitQuery.php b/src/applications/diffusion/query/DiffusionCommitQuery.php index 93efb1df12..75913ba37e 100644 --- a/src/applications/diffusion/query/DiffusionCommitQuery.php +++ b/src/applications/diffusion/query/DiffusionCommitQuery.php @@ -193,6 +193,7 @@ final class DiffusionCommitQuery if ($repo) { $commit->attachRepository($repo); } else { + $this->didRejectResult($commit); unset($commits[$key]); continue; } diff --git a/src/infrastructure/query/policy/PhabricatorPolicyAwareQuery.php b/src/infrastructure/query/policy/PhabricatorPolicyAwareQuery.php index 1d8f10b916..e7b9b35628 100644 --- a/src/infrastructure/query/policy/PhabricatorPolicyAwareQuery.php +++ b/src/infrastructure/query/policy/PhabricatorPolicyAwareQuery.php @@ -338,9 +338,25 @@ abstract class PhabricatorPolicyAwareQuery extends PhabricatorOffsetPagedQuery { } protected function didRejectResult(PhabricatorPolicyInterface $object) { + // Some objects (like commits) may be rejected because related objects + // (like repositories) can not be loaded. In some cases, we may need these + // related objects to determine the object policy, so it's expected that + // we may occasionally be unable to determine the policy. + + try { + $policy = $object->getPolicy(PhabricatorPolicyCapability::CAN_VIEW); + } catch (Exception $ex) { + $policy = null; + } + + // Mark this object as filtered so handles can render "Restricted" instead + // of "Unknown". + $phid = $object->getPHID(); + $this->addPolicyFilteredPHIDs(array($phid => $phid)); + $this->getPolicyFilter()->rejectObject( $object, - $object->getPolicy(PhabricatorPolicyCapability::CAN_VIEW), + $policy, PhabricatorPolicyCapability::CAN_VIEW); } From 2d5f3d9e5affd207efe3bfd87324240cabe24ed6 Mon Sep 17 00:00:00 2001 From: Joshua Spence Date: Mon, 15 Jun 2015 18:01:09 +1000 Subject: [PATCH 42/50] Fix a pht string Summary: This translation string is wrong and causes the following warning when running unit tests: ``` [2015-06-15 16:03:41] ERROR 2: vsprintf(): Too few arguments at [/home/joshua/workspace/github.com/phacility/libphutil/src/internationalization/PhutilTranslator.php:95] arcanist(head=master, ref.master=956bfa701c36), phabricator(head=master, ref.master=80f11427e576), phutil(head=master, ref.master=3ff84448a916) #0 vsprintf(string, array) called at [/src/internationalization/PhutilTranslator.php:95] #1 PhutilTranslator::translate(string) #2 call_user_func_array(array, array) called at [/src/internationalization/pht.php:17] #3 pht(string) called at [/src/applications/auth/controller/PhabricatorAuthStartController.php:75] #4 PhabricatorAuthStartController::handleRequest(AphrontRequest) called at [/src/aphront/AphrontController.php:69] #5 AphrontController::delegateToController(PhabricatorAuthStartController) called at [/src/applications/base/controller/PhabricatorController.php:213] #6 PhabricatorController::willBeginExecution() called at [/src/applications/base/controller/__tests__/PhabricatorAccessControlTestCase.php:270] #7 PhabricatorAccessControlTestCase::checkAccess(string, PhabricatorTestController, AphrontRequest, array, array) called at [/src/applications/base/controller/__tests__/PhabricatorAccessControlTestCase.php:112] #8 PhabricatorAccessControlTestCase::testControllerAccessControls() #9 call_user_func_array(array, array) called at [/src/unit/engine/phutil/PhutilTestCase.php:492] #10 PhutilTestCase::run() called at [/src/unit/engine/PhutilUnitTestEngine.php:65] #11 PhutilUnitTestEngine::run() called at [/src/workflow/ArcanistUnitWorkflow.php:186] #12 ArcanistUnitWorkflow::run() called at [/scripts/arcanist.php:382] ``` Test Plan: `arc lint` Reviewers: epriestley, #blessed_reviewers, chad Reviewed By: #blessed_reviewers, chad Subscribers: epriestley, Korvin Differential Revision: https://secure.phabricator.com/D13292 --- .../auth/controller/PhabricatorAuthStartController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/applications/auth/controller/PhabricatorAuthStartController.php b/src/applications/auth/controller/PhabricatorAuthStartController.php index f9b9f7cb41..01578446a5 100644 --- a/src/applications/auth/controller/PhabricatorAuthStartController.php +++ b/src/applications/auth/controller/PhabricatorAuthStartController.php @@ -71,7 +71,7 @@ final class PhabricatorAuthStartController 'This Phabricator install is not configured with any enabled '. 'authentication providers which can be used to log in. If you '. 'have accidentally locked yourself out by disabling all providers, '. - 'you can use `%s` to recover access to an administrative account.'. + 'you can use `%s` to recover access to an administrative account.', 'phabricator/bin/auth recover ')); } From b6d745b6668784e4c9277bbd68f98c48e2898930 Mon Sep 17 00:00:00 2001 From: Joshua Spence Date: Mon, 15 Jun 2015 18:02:26 +1000 Subject: [PATCH 43/50] Extend from Phobject Summary: All classes should extend from some other class. See D13275 for some explanation. Test Plan: `arc unit` Reviewers: epriestley, #blessed_reviewers Reviewed By: epriestley, #blessed_reviewers Subscribers: epriestley, Korvin Differential Revision: https://secure.phabricator.com/D13283 --- src/__phutil_library_map__.php | 219 +++++++++++++++++- src/aphront/AphrontRequest.php | 3 +- src/aphront/AphrontURIMapper.php | 2 +- .../AphrontApplicationConfiguration.php | 2 +- src/aphront/response/AphrontResponse.php | 2 +- src/aphront/sink/AphrontHTTPSink.php | 2 +- .../query/AphlictDropdownDataQuery.php | 2 +- .../PhabricatorAuditActionConstants.php | 2 +- .../PhabricatorAuditCommitStatusConstants.php | 2 +- .../PhabricatorAuditStatusConstants.php | 2 +- .../storage/PhabricatorAuditInlineComment.php | 1 + .../data/PhabricatorAuthHighSecurityToken.php | 2 +- .../auth/provider/PhabricatorAuthProvider.php | 2 +- .../base/PhabricatorApplication.php | 4 +- src/applications/cache/PhabricatorCaches.php | 2 +- .../calendar/util/CalendarTimeUtil.php | 2 +- src/applications/celerity/CelerityAPI.php | 2 +- .../celerity/CelerityResourceMap.php | 3 +- .../celerity/CelerityResourceMapGenerator.php | 2 +- .../celerity/CelerityResourceTransformer.php | 2 +- .../celerity/CeleritySpriteGenerator.php | 2 +- .../CelerityStaticResourceResponse.php | 2 +- .../celerity/resources/CelerityResources.php | 2 +- src/applications/conduit/call/ConduitCall.php | 3 +- .../conduit/protocol/ConduitAPIRequest.php | 2 +- .../conduit/protocol/ConduitAPIResponse.php | 2 +- .../config/check/PhabricatorSetupCheck.php | 2 +- .../custom/PhabricatorConfigOptionType.php | 2 +- .../config/issue/PhabricatorSetupIssue.php | 2 +- .../config/json/PhabricatorConfigJSON.php | 2 +- .../ConpherenceTransactionRenderer.php | 2 +- .../constants/ConpherenceConstants.php | 2 +- .../console/core/DarkConsoleCore.php | 2 +- .../console/plugin/DarkConsolePlugin.php | 2 +- .../errorlog/DarkConsoleErrorLogPluginAPI.php | 2 +- .../xhprof/DarkConsoleXHProfPluginAPI.php | 2 +- .../PhabricatorDashboardLayoutConfig.php | 2 +- .../DifferentialGetWorkingCopy.php | 2 +- .../constants/DifferentialAction.php | 2 +- .../constants/DifferentialChangeType.php | 2 +- .../constants/DifferentialLintStatus.php | 2 +- .../constants/DifferentialReviewerStatus.php | 2 +- .../DifferentialRevisionControlSystem.php | 2 +- .../constants/DifferentialRevisionStatus.php | 2 +- .../constants/DifferentialUnitStatus.php | 2 +- .../constants/DifferentialUnitTestResult.php | 2 +- .../landing/DifferentialLandingStrategy.php | 2 +- .../parser/DifferentialChangesetParser.php | 4 +- .../DifferentialCommitMessageParser.php | 2 +- .../parser/DifferentialHunkParser.php | 2 +- .../render/DifferentialChangesetRenderer.php | 2 +- .../render/DifferentialRawDiffRenderer.php | 3 +- .../storage/DifferentialInlineComment.php | 1 + .../storage/DifferentialReviewer.php | 2 +- ...rentialChangesetFileTreeSideNavBuilder.php | 2 +- .../diffusion/DiffusionLintSaveRunner.php | 2 +- .../data/DiffusionBrowseResultSet.php | 2 +- .../diffusion/data/DiffusionFileContent.php | 2 +- .../diffusion/data/DiffusionGitBranch.php | 2 +- .../diffusion/data/DiffusionPathChange.php | 2 +- .../data/DiffusionRepositoryPath.php | 2 +- .../diffusion/data/DiffusionRepositoryTag.php | 2 +- .../DiffusionMercurialWireProtocol.php | 2 +- .../diffusion/query/DiffusionPathQuery.php | 2 +- .../query/DiffusionRenameHistoryQuery.php | 2 +- .../pathchange/DiffusionPathChangeQuery.php | 2 +- .../query/pathid/DiffusionPathIDQuery.php | 2 +- .../diffusion/request/DiffusionRequest.php | 2 +- .../DiffusionSubversionServeSSHWorkflow.php | 1 - .../symbol/DiffusionExternalSymbolQuery.php | 2 +- .../symbol/DiffusionExternalSymbolsSource.php | 2 +- src/applications/diviner/atom/DivinerAtom.php | 2 +- .../diviner/atom/DivinerAtomRef.php | 2 +- .../diviner/atomizer/DivinerAtomizer.php | 2 +- .../diviner/cache/DivinerDiskCache.php | 2 +- .../diviner/publisher/DivinerPublisher.php | 2 +- .../diviner/renderer/DivinerRenderer.php | 2 +- .../engine/DoorkeeperFeedStoryPublisher.php | 2 +- .../DrydockBlueprintImplementation.php | 2 +- .../drydock/constants/DrydockConstants.php | 2 +- .../drydock/interface/DrydockInterface.php | 2 +- .../util/DrydockBlueprintScopeGuard.php | 2 +- .../fact/engine/PhabricatorFactEngine.php | 2 +- .../fact/spec/PhabricatorFactSpec.php | 2 +- .../feed/PhabricatorFeedStoryPublisher.php | 2 +- .../feed/builder/PhabricatorFeedBuilder.php | 2 +- .../feed/story/PhabricatorFeedStory.php | 1 + .../files/PhabricatorImageTransformer.php | 2 +- .../engine/PhabricatorFileStorageEngine.php | 2 +- .../query/PhabricatorFileBundleLoader.php | 2 +- .../constants/PhabricatorFlagConstants.php | 2 +- .../HarbormasterBuildStepImplementation.php | 2 +- .../herald/adapter/HeraldAdapter.php | 2 +- .../config/HeraldRepetitionPolicyConfig.php | 2 +- .../herald/config/HeraldRuleTypeConfig.php | 2 +- .../herald/engine/HeraldEffect.php | 2 +- .../herald/engine/HeraldEngine.php | 7 +- .../herald/extension/HeraldCustomAction.php | 2 +- .../transcript/HeraldConditionTranscript.php | 2 +- .../transcript/HeraldObjectTranscript.php | 2 +- .../transcript/HeraldRuleTranscript.php | 2 +- .../PhabricatorTestDataGenerator.php | 2 +- .../lipsum/image/PhabricatorLipsumArtist.php | 2 +- .../constants/ManiphestConstants.php | 2 +- .../maniphest/export/ManiphestExcelFormat.php | 2 +- .../PhabricatorMailImplementationAdapter.php | 2 +- .../metamta/constants/MetaMTAConstants.php | 2 +- .../PhabricatorContentSource.php | 2 +- .../PhabricatorMetaMTAEmailBodyParser.php | 2 +- .../metamta/query/PhabricatorMetaMTAActor.php | 2 +- .../receiver/PhabricatorMailReceiver.php | 2 +- .../PhabricatorMailReplyHandler.php | 2 +- .../storage/PhabricatorMetaMTAAttachment.php | 2 +- .../view/PhabricatorMetaMTAMailBody.php | 2 +- .../view/PhabricatorMetaMTAMailSection.php | 4 +- .../multimeter/data/MultimeterControl.php | 2 +- .../PhabricatorNotificationBuilder.php | 2 +- .../client/PhabricatorNotificationClient.php | 2 +- .../oauthserver/PhabricatorOAuthServer.php | 2 +- .../PhabricatorOAuthServerScope.php | 2 +- .../query/PhabricatorOwnerPathQuery.php | 2 +- .../phame/skins/PhameSkinSpecification.php | 2 +- .../phid/PhabricatorObjectHandle.php | 1 + .../phid/PhabricatorPHIDConstants.php | 2 +- ...habricatorHandleObjectSelectorDataView.php | 2 +- .../phid/query/PhabricatorObjectListQuery.php | 2 +- .../phid/storage/PhabricatorPHID.php | 2 +- .../phid/type/PhabricatorPHIDType.php | 2 +- .../cart/PhortuneCartImplementation.php | 2 +- .../phortune/constants/PhortuneConstants.php | 2 +- .../product/PhortuneProductImplementation.php | 2 +- .../provider/PhortunePaymentProvider.php | 2 +- .../PhortuneSubscriptionImplementation.php | 2 +- .../phortune/view/PhortuneCreditCardForm.php | 2 +- .../constants/PhrictionConstants.php | 2 +- .../__tests__/PhabricatorPolicyTestObject.php | 1 + .../constants/PhabricatorPolicyConstants.php | 2 +- .../policy/filter/PhabricatorPolicyFilter.php | 2 +- .../policy/rule/PhabricatorPolicyRule.php | 2 +- .../ponder/constants/PonderConstants.php | 2 +- .../constants/PhabricatorProjectStatus.php | 2 +- .../project/view/ProjectBoardTaskCard.php | 2 +- .../commitfinder/ReleephCommitFinder.php | 2 +- .../constants/ReleephRequestStatus.php | 2 +- ...entialReleephRequestFieldSpecification.php | 2 +- .../field/selector/ReleephFieldSelector.php | 2 +- .../view/branch/ReleephBranchTemplate.php | 2 +- .../constants/PhabricatorRepositoryType.php | 2 +- .../engine/PhabricatorRepositoryCommitRef.php | 2 +- .../engine/PhabricatorRepositoryEngine.php | 2 +- .../PhabricatorRepositoryGraphCache.php | 2 +- .../PhabricatorSearchRelationship.php | 2 +- .../engine/PhabricatorJumpNavHandler.php | 2 +- .../search/engine/PhabricatorSearchEngine.php | 2 +- .../PhabricatorSearchAbstractDocument.php | 2 +- .../search/index/PhabricatorSearchIndexer.php | 2 +- .../panel/PhabricatorSettingsPanel.php | 2 +- .../view/SubscriptionListDialogBuilder.php | 2 +- .../view/SubscriptionListStringBuilder.php | 2 +- .../system/action/PhabricatorSystemAction.php | 2 +- .../constants/PhabricatorTransactions.php | 2 +- .../storage/PhabricatorTypeaheadResult.php | 2 +- .../examples/PhabricatorUIExample.php | 2 +- .../field/PhabricatorCustomField.php | 2 +- .../PhabricatorCustomFieldAttachment.php | 2 +- .../daemon/bot/PhabricatorBotMessage.php | 2 +- .../adapter/PhabricatorProtocolAdapter.php | 2 +- .../bot/handler/PhabricatorBotHandler.php | 2 +- .../bot/target/PhabricatorBotTarget.php | 2 +- .../control/PhabricatorDaemonReference.php | 2 +- .../daemon/workers/PhabricatorWorker.php | 2 +- .../diff/PhabricatorDifferenceEngine.php | 2 +- .../constants/PhabricatorEdgeConstants.php | 2 +- .../env/PhabricatorConfigSource.php | 2 +- src/infrastructure/env/PhabricatorEnv.php | 2 +- .../env/PhabricatorScopedEnv.php | 2 +- .../events/PhabricatorEventEngine.php | 2 +- src/infrastructure/javelin/Javelin.php | 2 +- .../log/PhabricatorAccessLog.php | 2 +- .../markup/PhabricatorMarkupEngine.php | 2 +- .../markup/PhabricatorMarkupOneOff.php | 4 +- .../markup/PhabricatorSyntaxHighlighter.php | 2 +- src/infrastructure/query/PhabricatorQuery.php | 2 +- .../PhabricatorSMSImplementationAdapter.php | 2 +- .../DefaultDatabaseConfigurationProvider.php | 1 + src/infrastructure/storage/lisk/LiskDAO.php | 2 +- .../storage/lisk/LiskDAOSet.php | 2 +- .../lisk/PhabricatorLiskSerializer.php | 2 +- .../PhabricatorStorageManagementAPI.php | 2 +- .../management/PhabricatorStoragePatch.php | 2 +- .../storage/patch/PhabricatorSQLPatchList.php | 2 +- .../PhabricatorStorageFixtureScopeGuard.php | 2 +- src/infrastructure/time/PhabricatorTime.php | 2 +- .../time/PhabricatorTimeGuard.php | 2 +- src/infrastructure/util/PhabricatorSlug.php | 2 +- .../PhabricatorObjectSelectorDialog.php | 2 +- src/view/phui/PHUI.php | 2 +- 197 files changed, 422 insertions(+), 199 deletions(-) diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index e0d447aa5a..c6bdc707b0 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -3387,11 +3387,13 @@ phutil_register_library_map(array( 'AlmanacServiceTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'AlmanacServiceType' => 'Phobject', 'AlmanacServiceViewController' => 'AlmanacServiceController', + 'AphlictDropdownDataQuery' => 'Phobject', 'Aphront304Response' => 'AphrontResponse', 'Aphront400Response' => 'AphrontResponse', 'Aphront403Response' => 'AphrontHTMLResponse', 'Aphront404Response' => 'AphrontHTMLResponse', 'AphrontAjaxResponse' => 'AphrontResponse', + 'AphrontApplicationConfiguration' => 'Phobject', 'AphrontBarView' => 'AphrontView', 'AphrontCSRFException' => 'AphrontException', 'AphrontCalendarEventView' => 'AphrontView', @@ -3426,6 +3428,7 @@ phutil_register_library_map(array( 'AphrontGlyphBarView' => 'AphrontBarView', 'AphrontHTMLResponse' => 'AphrontResponse', 'AphrontHTTPProxyResponse' => 'AphrontResponse', + 'AphrontHTTPSink' => 'Phobject', 'AphrontHTTPSinkTestCase' => 'PhabricatorTestCase', 'AphrontIsolatedDatabaseConnectionTestCase' => 'PhabricatorTestCase', 'AphrontIsolatedHTTPSink' => 'AphrontHTTPSink', @@ -3446,7 +3449,9 @@ phutil_register_library_map(array( 'AphrontRedirectResponse' => 'AphrontResponse', 'AphrontRedirectResponseTestCase' => 'PhabricatorTestCase', 'AphrontReloadResponse' => 'AphrontRedirectResponse', + 'AphrontRequest' => 'Phobject', 'AphrontRequestTestCase' => 'PhabricatorTestCase', + 'AphrontResponse' => 'Phobject', 'AphrontSideNavFilterView' => 'AphrontView', 'AphrontStackTraceView' => 'AphrontView', 'AphrontStandaloneHTMLResponse' => 'AphrontHTMLResponse', @@ -3455,6 +3460,7 @@ phutil_register_library_map(array( 'AphrontTokenizerTemplateView' => 'AphrontView', 'AphrontTwoColumnView' => 'AphrontView', 'AphrontTypeaheadTemplateView' => 'AphrontView', + 'AphrontURIMapper' => 'Phobject', 'AphrontUnhandledExceptionResponse' => 'AphrontStandaloneHTMLResponse', 'AphrontUsageException' => 'AphrontException', 'AphrontView' => array( @@ -3467,7 +3473,9 @@ phutil_register_library_map(array( 'AuditConduitAPIMethod' => 'ConduitAPIMethod', 'AuditQueryConduitAPIMethod' => 'AuditConduitAPIMethod', 'AuthManageProvidersCapability' => 'PhabricatorPolicyCapability', + 'CalendarTimeUtil' => 'Phobject', 'CalendarTimeUtilTestCase' => 'PhabricatorTestCase', + 'CelerityAPI' => 'Phobject', 'CelerityManagementMapWorkflow' => 'CelerityManagementWorkflow', 'CelerityManagementWorkflow' => 'PhabricatorManagementWorkflow', 'CelerityPhabricatorResourceController' => 'CelerityResourceController', @@ -3475,8 +3483,14 @@ phutil_register_library_map(array( 'CelerityPhysicalResources' => 'CelerityResources', 'CelerityResourceController' => 'PhabricatorController', 'CelerityResourceGraph' => 'AbstractDirectedGraph', + 'CelerityResourceMap' => 'Phobject', + 'CelerityResourceMapGenerator' => 'Phobject', + 'CelerityResourceTransformer' => 'Phobject', 'CelerityResourceTransformerTestCase' => 'PhabricatorTestCase', + 'CelerityResources' => 'Phobject', 'CelerityResourcesOnDisk' => 'CelerityPhysicalResources', + 'CeleritySpriteGenerator' => 'Phobject', + 'CelerityStaticResourceResponse' => 'Phobject', 'ChatLogConduitAPIMethod' => 'ConduitAPIMethod', 'ChatLogQueryConduitAPIMethod' => 'ChatLogConduitAPIMethod', 'ChatLogRecordConduitAPIMethod' => 'ChatLogConduitAPIMethod', @@ -3484,7 +3498,10 @@ phutil_register_library_map(array( 'Phobject', 'PhabricatorPolicyInterface', ), + 'ConduitAPIRequest' => 'Phobject', + 'ConduitAPIResponse' => 'Phobject', 'ConduitApplicationNotInstalledException' => 'ConduitMethodNotFoundException', + 'ConduitCall' => 'Phobject', 'ConduitCallTestCase' => 'PhabricatorTestCase', 'ConduitConnectConduitAPIMethod' => 'ConduitAPIMethod', 'ConduitConnectionGarbageCollector' => 'PhabricatorGarbageCollector', @@ -3502,6 +3519,7 @@ phutil_register_library_map(array( 'ConpherenceColumnViewController' => 'ConpherenceController', 'ConpherenceConduitAPIMethod' => 'ConduitAPIMethod', 'ConpherenceConfigOptions' => 'PhabricatorApplicationConfigOptions', + 'ConpherenceConstants' => 'Phobject', 'ConpherenceController' => 'PhabricatorController', 'ConpherenceCreateThreadConduitAPIMethod' => 'ConpherenceConduitAPIMethod', 'ConpherenceCreateThreadMailReceiver' => 'PhabricatorMailReceiver', @@ -3552,6 +3570,7 @@ phutil_register_library_map(array( 'ConpherenceTransaction' => 'PhabricatorApplicationTransaction', 'ConpherenceTransactionComment' => 'PhabricatorApplicationTransactionComment', 'ConpherenceTransactionQuery' => 'PhabricatorApplicationTransactionQuery', + 'ConpherenceTransactionRenderer' => 'Phobject', 'ConpherenceTransactionView' => 'AphrontView', 'ConpherenceUpdateActions' => 'ConpherenceConstants', 'ConpherenceUpdateController' => 'ConpherenceController', @@ -3561,14 +3580,22 @@ phutil_register_library_map(array( 'ConpherenceWidgetController' => 'ConpherenceController', 'ConpherenceWidgetView' => 'AphrontView', 'DarkConsoleController' => 'PhabricatorController', + 'DarkConsoleCore' => 'Phobject', 'DarkConsoleDataController' => 'PhabricatorController', 'DarkConsoleErrorLogPlugin' => 'DarkConsolePlugin', + 'DarkConsoleErrorLogPluginAPI' => 'Phobject', 'DarkConsoleEventPlugin' => 'DarkConsolePlugin', 'DarkConsoleEventPluginAPI' => 'PhabricatorEventListener', + 'DarkConsolePlugin' => 'Phobject', 'DarkConsoleRequestPlugin' => 'DarkConsolePlugin', 'DarkConsoleServicesPlugin' => 'DarkConsolePlugin', 'DarkConsoleXHProfPlugin' => 'DarkConsolePlugin', - 'DefaultDatabaseConfigurationProvider' => 'DatabaseConfigurationProvider', + 'DarkConsoleXHProfPluginAPI' => 'Phobject', + 'DefaultDatabaseConfigurationProvider' => array( + 'Phobject', + 'DatabaseConfigurationProvider', + ), + 'DifferentialAction' => 'Phobject', 'DifferentialActionEmailCommand' => 'MetaMTAEmailTransactionCommand', 'DifferentialActionMenuEventListener' => 'PhabricatorEventListener', 'DifferentialAddCommentView' => 'AphrontView', @@ -3580,18 +3607,22 @@ phutil_register_library_map(array( 'DifferentialAuthorField' => 'DifferentialCustomField', 'DifferentialBlameRevisionField' => 'DifferentialStoredCustomField', 'DifferentialBranchField' => 'DifferentialCustomField', + 'DifferentialChangeType' => 'Phobject', 'DifferentialChangesSinceLastUpdateField' => 'DifferentialCustomField', 'DifferentialChangeset' => array( 'DifferentialDAO', 'PhabricatorPolicyInterface', ), 'DifferentialChangesetDetailView' => 'AphrontView', + 'DifferentialChangesetFileTreeSideNavBuilder' => 'Phobject', 'DifferentialChangesetHTMLRenderer' => 'DifferentialChangesetRenderer', 'DifferentialChangesetListView' => 'AphrontView', 'DifferentialChangesetOneUpRenderer' => 'DifferentialChangesetHTMLRenderer', 'DifferentialChangesetOneUpTestRenderer' => 'DifferentialChangesetTestRenderer', + 'DifferentialChangesetParser' => 'Phobject', 'DifferentialChangesetParserTestCase' => 'PhabricatorTestCase', 'DifferentialChangesetQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', + 'DifferentialChangesetRenderer' => 'Phobject', 'DifferentialChangesetTestRenderer' => 'DifferentialChangesetRenderer', 'DifferentialChangesetTwoUpRenderer' => 'DifferentialChangesetHTMLRenderer', 'DifferentialChangesetTwoUpTestRenderer' => 'DifferentialChangesetTestRenderer', @@ -3599,6 +3630,7 @@ phutil_register_library_map(array( 'DifferentialCloseConduitAPIMethod' => 'DifferentialConduitAPIMethod', 'DifferentialCommentPreviewController' => 'DifferentialController', 'DifferentialCommentSaveController' => 'DifferentialController', + 'DifferentialCommitMessageParser' => 'Phobject', 'DifferentialCommitMessageParserTestCase' => 'PhabricatorTestCase', 'DifferentialCommitsField' => 'DifferentialCustomField', 'DifferentialConduitAPIMethod' => 'ConduitAPIMethod', @@ -3654,6 +3686,7 @@ phutil_register_library_map(array( 'DifferentialGetRawDiffConduitAPIMethod' => 'DifferentialConduitAPIMethod', 'DifferentialGetRevisionCommentsConduitAPIMethod' => 'DifferentialConduitAPIMethod', 'DifferentialGetRevisionConduitAPIMethod' => 'DifferentialConduitAPIMethod', + 'DifferentialGetWorkingCopy' => 'Phobject', 'DifferentialGitHubLandingStrategy' => 'DifferentialLandingStrategy', 'DifferentialGitSVNIDField' => 'DifferentialCustomField', 'DifferentialHiddenComment' => 'DifferentialDAO', @@ -3665,18 +3698,24 @@ phutil_register_library_map(array( 'DifferentialDAO', 'PhabricatorPolicyInterface', ), + 'DifferentialHunkParser' => 'Phobject', 'DifferentialHunkParserTestCase' => 'PhabricatorTestCase', 'DifferentialHunkQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'DifferentialHunkTestCase' => 'PhutilTestCase', - 'DifferentialInlineComment' => 'PhabricatorInlineCommentInterface', + 'DifferentialInlineComment' => array( + 'Phobject', + 'PhabricatorInlineCommentInterface', + ), 'DifferentialInlineCommentEditController' => 'PhabricatorInlineCommentController', 'DifferentialInlineCommentPreviewController' => 'PhabricatorInlineCommentPreviewController', 'DifferentialInlineCommentQuery' => 'PhabricatorOffsetPagedQuery', 'DifferentialJIRAIssuesField' => 'DifferentialStoredCustomField', 'DifferentialLandingActionMenuEventListener' => 'PhabricatorEventListener', + 'DifferentialLandingStrategy' => 'Phobject', 'DifferentialLegacyHunk' => 'DifferentialHunk', 'DifferentialLineAdjustmentMap' => 'Phobject', 'DifferentialLintField' => 'DifferentialCustomField', + 'DifferentialLintStatus' => 'Phobject', 'DifferentialLocalCommitsView' => 'AphrontView', 'DifferentialManiphestTasksField' => 'DifferentialCoreCustomField', 'DifferentialModernHunk' => 'DifferentialHunk', @@ -3689,6 +3728,8 @@ phutil_register_library_map(array( 'DifferentialProjectsField' => 'DifferentialCoreCustomField', 'DifferentialQueryConduitAPIMethod' => 'DifferentialConduitAPIMethod', 'DifferentialQueryDiffsConduitAPIMethod' => 'DifferentialConduitAPIMethod', + 'DifferentialRawDiffRenderer' => 'Phobject', + 'DifferentialReleephRequestFieldSpecification' => 'Phobject', 'DifferentialRemarkupRule' => 'PhabricatorObjectRemarkupRule', 'DifferentialReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler', 'DifferentialRepositoryField' => 'DifferentialCoreCustomField', @@ -3697,7 +3738,9 @@ phutil_register_library_map(array( 'DifferentialResultsTableView' => 'AphrontView', 'DifferentialRevertPlanField' => 'DifferentialStoredCustomField', 'DifferentialReviewedByField' => 'DifferentialCoreCustomField', + 'DifferentialReviewer' => 'Phobject', 'DifferentialReviewerForRevisionEdgeType' => 'PhabricatorEdgeType', + 'DifferentialReviewerStatus' => 'Phobject', 'DifferentialReviewersField' => 'DifferentialCoreCustomField', 'DifferentialReviewersView' => 'AphrontView', 'DifferentialRevision' => array( @@ -3716,6 +3759,7 @@ phutil_register_library_map(array( 'PhabricatorProjectInterface', ), 'DifferentialRevisionCloseDetailsController' => 'DifferentialController', + 'DifferentialRevisionControlSystem' => 'Phobject', 'DifferentialRevisionDependedOnByRevisionEdgeType' => 'PhabricatorEdgeType', 'DifferentialRevisionDependsOnRevisionEdgeType' => 'PhabricatorEdgeType', 'DifferentialRevisionDetailView' => 'AphrontView', @@ -3731,6 +3775,7 @@ phutil_register_library_map(array( 'DifferentialRevisionPHIDType' => 'PhabricatorPHIDType', 'DifferentialRevisionQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'DifferentialRevisionSearchEngine' => 'PhabricatorApplicationSearchEngine', + 'DifferentialRevisionStatus' => 'Phobject', 'DifferentialRevisionUpdateHistoryView' => 'AphrontView', 'DifferentialRevisionViewController' => 'DifferentialController', 'DifferentialSchemaSpec' => 'PhabricatorConfigSchemaSpec', @@ -3747,6 +3792,8 @@ phutil_register_library_map(array( 'DifferentialTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'DifferentialTransactionView' => 'PhabricatorApplicationTransactionView', 'DifferentialUnitField' => 'DifferentialCustomField', + 'DifferentialUnitStatus' => 'Phobject', + 'DifferentialUnitTestResult' => 'Phobject', 'DifferentialUpdateRevisionConduitAPIMethod' => 'DifferentialConduitAPIMethod', 'DifferentialUpdateUnitResultsConduitAPIMethod' => 'DifferentialConduitAPIMethod', 'DifferentialViewPolicyField' => 'DifferentialCoreCustomField', @@ -3759,6 +3806,7 @@ phutil_register_library_map(array( 'DiffusionBrowseFileController' => 'DiffusionBrowseController', 'DiffusionBrowseMainController' => 'DiffusionBrowseController', 'DiffusionBrowseQueryConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod', + 'DiffusionBrowseResultSet' => 'Phobject', 'DiffusionBrowseSearchController' => 'DiffusionBrowseController', 'DiffusionBrowseTableView' => 'DiffusionView', 'DiffusionCachedResolveRefsQuery' => 'DiffusionLowLevelQuery', @@ -3794,12 +3842,16 @@ phutil_register_library_map(array( 'DiffusionEmptyResultView' => 'DiffusionView', 'DiffusionExistsQueryConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod', 'DiffusionExternalController' => 'DiffusionController', + 'DiffusionExternalSymbolQuery' => 'Phobject', + 'DiffusionExternalSymbolsSource' => 'Phobject', + 'DiffusionFileContent' => 'Phobject', 'DiffusionFileContentQuery' => 'DiffusionQuery', 'DiffusionFileContentQueryConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod', 'DiffusionFindSymbolsConduitAPIMethod' => 'DiffusionConduitAPIMethod', 'DiffusionGetCommitsConduitAPIMethod' => 'DiffusionConduitAPIMethod', 'DiffusionGetLintMessagesConduitAPIMethod' => 'DiffusionConduitAPIMethod', 'DiffusionGetRecentCommitsByPathConduitAPIMethod' => 'DiffusionConduitAPIMethod', + 'DiffusionGitBranch' => 'Phobject', 'DiffusionGitBranchTestCase' => 'PhabricatorTestCase', 'DiffusionGitFileContentQuery' => 'DiffusionFileContentQuery', 'DiffusionGitFileContentQueryTestCase' => 'PhabricatorTestCase', @@ -3820,6 +3872,7 @@ phutil_register_library_map(array( 'DiffusionLintController' => 'DiffusionController', 'DiffusionLintCountQuery' => 'PhabricatorQuery', 'DiffusionLintDetailsController' => 'DiffusionController', + 'DiffusionLintSaveRunner' => 'Phobject', 'DiffusionLookSoonConduitAPIMethod' => 'DiffusionConduitAPIMethod', 'DiffusionLowLevelCommitFieldsQuery' => 'DiffusionLowLevelQuery', 'DiffusionLowLevelCommitQuery' => 'DiffusionLowLevelQuery', @@ -3836,11 +3889,16 @@ phutil_register_library_map(array( 'DiffusionMercurialSSHWorkflow' => 'DiffusionSSHWorkflow', 'DiffusionMercurialServeSSHWorkflow' => 'DiffusionMercurialSSHWorkflow', 'DiffusionMercurialWireClientSSHProtocolChannel' => 'PhutilProtocolChannel', + 'DiffusionMercurialWireProtocol' => 'Phobject', 'DiffusionMercurialWireSSHTestCase' => 'PhabricatorTestCase', 'DiffusionMergedCommitsQueryConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod', 'DiffusionMirrorDeleteController' => 'DiffusionController', 'DiffusionMirrorEditController' => 'DiffusionController', + 'DiffusionPathChange' => 'Phobject', + 'DiffusionPathChangeQuery' => 'Phobject', 'DiffusionPathCompleteController' => 'DiffusionController', + 'DiffusionPathIDQuery' => 'Phobject', + 'DiffusionPathQuery' => 'Phobject', 'DiffusionPathQueryTestCase' => 'PhabricatorTestCase', 'DiffusionPathTreeController' => 'DiffusionController', 'DiffusionPathValidateController' => 'DiffusionController', @@ -3861,6 +3919,7 @@ phutil_register_library_map(array( 'DiffusionRefNotFoundException' => 'Exception', 'DiffusionRefTableController' => 'DiffusionController', 'DiffusionRefsQueryConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod', + 'DiffusionRenameHistoryQuery' => 'Phobject', 'DiffusionRepositoryByIDRemarkupRule' => 'PhabricatorObjectRemarkupRule', 'DiffusionRepositoryController' => 'DiffusionController', 'DiffusionRepositoryCreateController' => 'DiffusionRepositoryEditController', @@ -3882,9 +3941,12 @@ phutil_register_library_map(array( 'DiffusionRepositoryEditUpdateController' => 'DiffusionRepositoryEditController', 'DiffusionRepositoryListController' => 'DiffusionController', 'DiffusionRepositoryNewController' => 'DiffusionController', + 'DiffusionRepositoryPath' => 'Phobject', 'DiffusionRepositoryRef' => 'Phobject', 'DiffusionRepositoryRemarkupRule' => 'PhabricatorObjectRemarkupRule', 'DiffusionRepositorySymbolsController' => 'DiffusionRepositoryEditController', + 'DiffusionRepositoryTag' => 'Phobject', + 'DiffusionRequest' => 'Phobject', 'DiffusionResolveRefsConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod', 'DiffusionResolveUserQuery' => 'Phobject', 'DiffusionSSHWorkflow' => 'PhabricatorSSHWorkflow', @@ -3909,14 +3971,17 @@ phutil_register_library_map(array( 'DiffusionUpdateCoverageConduitAPIMethod' => 'DiffusionConduitAPIMethod', 'DiffusionView' => 'AphrontView', 'DivinerArticleAtomizer' => 'DivinerAtomizer', + 'DivinerAtom' => 'Phobject', 'DivinerAtomCache' => 'DivinerDiskCache', 'DivinerAtomController' => 'DivinerController', 'DivinerAtomListController' => 'DivinerController', 'DivinerAtomPHIDType' => 'PhabricatorPHIDType', 'DivinerAtomQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', + 'DivinerAtomRef' => 'Phobject', 'DivinerAtomSearchEngine' => 'PhabricatorApplicationSearchEngine', 'DivinerAtomSearchIndexer' => 'PhabricatorSearchDocumentIndexer', 'DivinerAtomizeWorkflow' => 'DivinerWorkflow', + 'DivinerAtomizer' => 'Phobject', 'DivinerBookController' => 'DivinerController', 'DivinerBookItemView' => 'AphrontTagView', 'DivinerBookPHIDType' => 'PhabricatorPHIDType', @@ -3925,6 +3990,7 @@ phutil_register_library_map(array( 'DivinerController' => 'PhabricatorController', 'DivinerDAO' => 'PhabricatorLiskDAO', 'DivinerDefaultRenderer' => 'DivinerRenderer', + 'DivinerDiskCache' => 'Phobject', 'DivinerFileAtomizer' => 'DivinerAtomizer', 'DivinerFindController' => 'DivinerController', 'DivinerGenerateWorkflow' => 'DivinerWorkflow', @@ -3945,6 +4011,8 @@ phutil_register_library_map(array( 'DivinerPHPAtomizer' => 'DivinerAtomizer', 'DivinerParameterTableView' => 'AphrontTagView', 'DivinerPublishCache' => 'DivinerDiskCache', + 'DivinerPublisher' => 'Phobject', + 'DivinerRenderer' => 'Phobject', 'DivinerReturnTableView' => 'AphrontTagView', 'DivinerSectionView' => 'AphrontTagView', 'DivinerStaticPublisher' => 'DivinerPublisher', @@ -3962,6 +4030,7 @@ phutil_register_library_map(array( 'PhabricatorPolicyInterface', ), 'DoorkeeperExternalObjectQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', + 'DoorkeeperFeedStoryPublisher' => 'Phobject', 'DoorkeeperFeedWorker' => 'FeedPushWorker', 'DoorkeeperImportEngine' => 'Phobject', 'DoorkeeperJIRAFeedWorker' => 'DoorkeeperFeedWorker', @@ -3989,21 +4058,25 @@ phutil_register_library_map(array( 'DrydockBlueprintCustomField' => 'PhabricatorCustomField', 'DrydockBlueprintEditController' => 'DrydockBlueprintController', 'DrydockBlueprintEditor' => 'PhabricatorApplicationTransactionEditor', + 'DrydockBlueprintImplementation' => 'Phobject', 'DrydockBlueprintListController' => 'DrydockBlueprintController', 'DrydockBlueprintPHIDType' => 'PhabricatorPHIDType', 'DrydockBlueprintQuery' => 'DrydockQuery', + 'DrydockBlueprintScopeGuard' => 'Phobject', 'DrydockBlueprintSearchEngine' => 'PhabricatorApplicationSearchEngine', 'DrydockBlueprintTransaction' => 'PhabricatorApplicationTransaction', 'DrydockBlueprintTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'DrydockBlueprintViewController' => 'DrydockBlueprintController', 'DrydockCommandInterface' => 'DrydockInterface', 'DrydockConsoleController' => 'DrydockController', + 'DrydockConstants' => 'Phobject', 'DrydockController' => 'PhabricatorController', 'DrydockCreateBlueprintsCapability' => 'PhabricatorPolicyCapability', 'DrydockDAO' => 'PhabricatorLiskDAO', 'DrydockDefaultEditCapability' => 'PhabricatorPolicyCapability', 'DrydockDefaultViewCapability' => 'PhabricatorPolicyCapability', 'DrydockFilesystemInterface' => 'DrydockInterface', + 'DrydockInterface' => 'Phobject', 'DrydockLease' => array( 'DrydockDAO', 'PhabricatorPolicyInterface', @@ -4176,6 +4249,7 @@ phutil_register_library_map(array( ), 'HarbormasterBuildStepCustomField' => 'PhabricatorCustomField', 'HarbormasterBuildStepEditor' => 'PhabricatorApplicationTransactionEditor', + 'HarbormasterBuildStepImplementation' => 'Phobject', 'HarbormasterBuildStepPHIDType' => 'PhabricatorPHIDType', 'HarbormasterBuildStepQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'HarbormasterBuildStepTransaction' => 'PhabricatorApplicationTransaction', @@ -4241,26 +4315,33 @@ phutil_register_library_map(array( 'HarbormasterWaitForPreviousBuildStepImplementation' => 'HarbormasterBuildStepImplementation', 'HarbormasterWorker' => 'PhabricatorWorker', 'HeraldAction' => 'HeraldDAO', + 'HeraldAdapter' => 'Phobject', 'HeraldApplyTranscript' => 'Phobject', 'HeraldCommitAdapter' => 'HeraldAdapter', 'HeraldCondition' => 'HeraldDAO', + 'HeraldConditionTranscript' => 'Phobject', 'HeraldController' => 'PhabricatorController', + 'HeraldCustomAction' => 'Phobject', 'HeraldDAO' => 'PhabricatorLiskDAO', 'HeraldDifferentialAdapter' => 'HeraldAdapter', 'HeraldDifferentialDiffAdapter' => 'HeraldDifferentialAdapter', 'HeraldDifferentialRevisionAdapter' => 'HeraldDifferentialAdapter', 'HeraldDisableController' => 'HeraldController', + 'HeraldEffect' => 'Phobject', + 'HeraldEngine' => 'Phobject', 'HeraldInvalidActionException' => 'Exception', 'HeraldInvalidConditionException' => 'Exception', 'HeraldManageGlobalRulesCapability' => 'PhabricatorPolicyCapability', 'HeraldManiphestTaskAdapter' => 'HeraldAdapter', 'HeraldNewController' => 'HeraldController', + 'HeraldObjectTranscript' => 'Phobject', 'HeraldPholioMockAdapter' => 'HeraldAdapter', 'HeraldPreCommitAdapter' => 'HeraldAdapter', 'HeraldPreCommitContentAdapter' => 'HeraldPreCommitAdapter', 'HeraldPreCommitRefAdapter' => 'HeraldPreCommitAdapter', 'HeraldRecursiveConditionsException' => 'Exception', 'HeraldRemarkupRule' => 'PhabricatorObjectRemarkupRule', + 'HeraldRepetitionPolicyConfig' => 'Phobject', 'HeraldRule' => array( 'HeraldDAO', 'PhabricatorApplicationTransactionInterface', @@ -4277,6 +4358,8 @@ phutil_register_library_map(array( 'HeraldRuleTestCase' => 'PhabricatorTestCase', 'HeraldRuleTransaction' => 'PhabricatorApplicationTransaction', 'HeraldRuleTransactionComment' => 'PhabricatorApplicationTransactionComment', + 'HeraldRuleTranscript' => 'Phobject', + 'HeraldRuleTypeConfig' => 'Phobject', 'HeraldRuleViewController' => 'HeraldController', 'HeraldSchemaSpec' => 'PhabricatorConfigSchemaSpec', 'HeraldTestConsoleController' => 'HeraldController', @@ -4292,6 +4375,7 @@ phutil_register_library_map(array( 'HeraldTranscriptQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'HeraldTranscriptSearchEngine' => 'PhabricatorApplicationSearchEngine', 'HeraldTranscriptTestCase' => 'PhabricatorTestCase', + 'Javelin' => 'Phobject', 'JavelinReactorUIExample' => 'PhabricatorUIExample', 'JavelinUIExample' => 'PhabricatorUIExample', 'JavelinViewExampleServerView' => 'AphrontView', @@ -4343,6 +4427,8 @@ phutil_register_library_map(array( 'LegalpadTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'LegalpadTransactionView' => 'PhabricatorApplicationTransactionView', 'LiskChunkTestCase' => 'PhabricatorTestCase', + 'LiskDAO' => 'Phobject', + 'LiskDAOSet' => 'Phobject', 'LiskDAOTestCase' => 'PhabricatorTestCase', 'LiskEphemeralObjectException' => 'Exception', 'LiskFixtureTestCase' => 'PhabricatorTestCase', @@ -4365,6 +4451,7 @@ phutil_register_library_map(array( 'ManiphestCustomField', 'PhabricatorStandardCustomFieldInterface', ), + 'ManiphestConstants' => 'Phobject', 'ManiphestController' => 'PhabricatorController', 'ManiphestCreateMailReceiver' => 'PhabricatorMailReceiver', 'ManiphestCreateTaskConduitAPIMethod' => 'ManiphestConduitAPIMethod', @@ -4384,6 +4471,7 @@ phutil_register_library_map(array( 'ManiphestEditStatusCapability' => 'PhabricatorPolicyCapability', 'ManiphestEmailCommand' => 'MetaMTAEmailTransactionCommand', 'ManiphestExcelDefaultFormat' => 'ManiphestExcelFormat', + 'ManiphestExcelFormat' => 'Phobject', 'ManiphestExportController' => 'ManiphestController', 'ManiphestGetTaskTransactionsConduitAPIMethod' => 'ManiphestConduitAPIMethod', 'ManiphestHovercardEventListener' => 'PhabricatorEventListener', @@ -4448,11 +4536,13 @@ phutil_register_library_map(array( 'ManiphestTransactionSaveController' => 'ManiphestController', 'ManiphestUpdateConduitAPIMethod' => 'ManiphestConduitAPIMethod', 'ManiphestView' => 'AphrontView', + 'MetaMTAConstants' => 'Phobject', 'MetaMTAEmailTransactionCommand' => 'Phobject', 'MetaMTAMailReceivedGarbageCollector' => 'PhabricatorGarbageCollector', 'MetaMTAMailSentGarbageCollector' => 'PhabricatorGarbageCollector', 'MetaMTAReceivedMailStatus' => 'MetaMTAConstants', 'MultimeterContext' => 'MultimeterDimension', + 'MultimeterControl' => 'Phobject', 'MultimeterController' => 'PhabricatorController', 'MultimeterDAO' => 'PhabricatorLiskDAO', 'MultimeterDimension' => 'MultimeterDAO', @@ -4540,6 +4630,7 @@ phutil_register_library_map(array( 'PHIDInfoConduitAPIMethod' => 'PHIDConduitAPIMethod', 'PHIDLookupConduitAPIMethod' => 'PHIDConduitAPIMethod', 'PHIDQueryConduitAPIMethod' => 'PHIDConduitAPIMethod', + 'PHUI' => 'Phobject', 'PHUIActionHeaderExample' => 'PhabricatorUIExample', 'PHUIActionHeaderView' => 'AphrontView', 'PHUIActionPanelExample' => 'PhabricatorUIExample', @@ -4671,6 +4762,7 @@ phutil_register_library_map(array( 'Phabricator404Controller' => 'PhabricatorController', 'PhabricatorAWSConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorAccessControlTestCase' => 'PhabricatorTestCase', + 'PhabricatorAccessLog' => 'Phobject', 'PhabricatorAccessLogConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorAccountSettingsPanel' => 'PhabricatorSettingsPanel', 'PhabricatorActionListView' => 'AphrontView', @@ -4690,7 +4782,10 @@ phutil_register_library_map(array( 'PhabricatorAphrontBarUIExample' => 'PhabricatorUIExample', 'PhabricatorAphrontViewTestCase' => 'PhabricatorTestCase', 'PhabricatorAppSearchEngine' => 'PhabricatorApplicationSearchEngine', - 'PhabricatorApplication' => 'PhabricatorPolicyInterface', + 'PhabricatorApplication' => array( + 'Phobject', + 'PhabricatorPolicyInterface', + ), 'PhabricatorApplicationApplicationPHIDType' => 'PhabricatorPHIDType', 'PhabricatorApplicationConfigOptions' => 'Phobject', 'PhabricatorApplicationConfigurationPanel' => 'Phobject', @@ -4751,12 +4846,17 @@ phutil_register_library_map(array( 'PhabricatorAsanaConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorAsanaSubtaskHasObjectEdgeType' => 'PhabricatorEdgeType', 'PhabricatorAsanaTaskHasObjectEdgeType' => 'PhabricatorEdgeType', + 'PhabricatorAuditActionConstants' => 'Phobject', 'PhabricatorAuditAddCommentController' => 'PhabricatorAuditController', 'PhabricatorAuditApplication' => 'PhabricatorApplication', 'PhabricatorAuditCommentEditor' => 'PhabricatorEditor', + 'PhabricatorAuditCommitStatusConstants' => 'Phobject', 'PhabricatorAuditController' => 'PhabricatorController', 'PhabricatorAuditEditor' => 'PhabricatorApplicationTransactionEditor', - 'PhabricatorAuditInlineComment' => 'PhabricatorInlineCommentInterface', + 'PhabricatorAuditInlineComment' => array( + 'Phobject', + 'PhabricatorInlineCommentInterface', + ), 'PhabricatorAuditListController' => 'PhabricatorAuditController', 'PhabricatorAuditListView' => 'AphrontView', 'PhabricatorAuditMailReceiver' => 'PhabricatorObjectMailReceiver', @@ -4764,6 +4864,7 @@ phutil_register_library_map(array( 'PhabricatorAuditManagementWorkflow' => 'PhabricatorManagementWorkflow', 'PhabricatorAuditPreviewController' => 'PhabricatorAuditController', 'PhabricatorAuditReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler', + 'PhabricatorAuditStatusConstants' => 'Phobject', 'PhabricatorAuditTransaction' => 'PhabricatorApplicationTransaction', 'PhabricatorAuditTransactionComment' => 'PhabricatorApplicationTransactionComment', 'PhabricatorAuditTransactionQuery' => 'PhabricatorApplicationTransactionQuery', @@ -4783,6 +4884,7 @@ phutil_register_library_map(array( 'PhabricatorAuthFactorConfig' => 'PhabricatorAuthDAO', 'PhabricatorAuthFinishController' => 'PhabricatorAuthController', 'PhabricatorAuthHighSecurityRequiredException' => 'Exception', + 'PhabricatorAuthHighSecurityToken' => 'Phobject', 'PhabricatorAuthInvite' => array( 'PhabricatorUserDAO', 'PhabricatorPolicyInterface', @@ -4821,6 +4923,7 @@ phutil_register_library_map(array( 'PhabricatorAuthNewController' => 'PhabricatorAuthProviderConfigController', 'PhabricatorAuthOldOAuthRedirectController' => 'PhabricatorAuthController', 'PhabricatorAuthOneTimeLoginController' => 'PhabricatorAuthController', + 'PhabricatorAuthProvider' => 'Phobject', 'PhabricatorAuthProviderConfig' => array( 'PhabricatorAuthDAO', 'PhabricatorApplicationTransactionInterface', @@ -4877,10 +4980,13 @@ phutil_register_library_map(array( 'PhabricatorBotDebugLogHandler' => 'PhabricatorBotHandler', 'PhabricatorBotFeedNotificationHandler' => 'PhabricatorBotHandler', 'PhabricatorBotFlowdockProtocolAdapter' => 'PhabricatorStreamingProtocolAdapter', + 'PhabricatorBotHandler' => 'Phobject', 'PhabricatorBotLogHandler' => 'PhabricatorBotHandler', 'PhabricatorBotMacroHandler' => 'PhabricatorBotHandler', + 'PhabricatorBotMessage' => 'Phobject', 'PhabricatorBotObjectNameHandler' => 'PhabricatorBotHandler', 'PhabricatorBotSymbolHandler' => 'PhabricatorBotHandler', + 'PhabricatorBotTarget' => 'Phobject', 'PhabricatorBotUser' => 'PhabricatorBotTarget', 'PhabricatorBotWhatsNewHandler' => 'PhabricatorBotHandler', 'PhabricatorBritishEnglishTranslation' => 'PhutilTranslation', @@ -4895,6 +5001,7 @@ phutil_register_library_map(array( 'PhabricatorCacheSetupCheck' => 'PhabricatorSetupCheck', 'PhabricatorCacheSpec' => 'Phobject', 'PhabricatorCacheTTLGarbageCollector' => 'PhabricatorGarbageCollector', + 'PhabricatorCaches' => 'Phobject', 'PhabricatorCachesTestCase' => 'PhabricatorTestCase', 'PhabricatorCalendarApplication' => 'PhabricatorApplication', 'PhabricatorCalendarController' => 'PhabricatorController', @@ -5026,6 +5133,7 @@ phutil_register_library_map(array( 'PhabricatorConfigIgnoreController' => 'PhabricatorConfigController', 'PhabricatorConfigIssueListController' => 'PhabricatorConfigController', 'PhabricatorConfigIssueViewController' => 'PhabricatorConfigController', + 'PhabricatorConfigJSON' => 'Phobject', 'PhabricatorConfigJSONOptionType' => 'PhabricatorConfigOptionType', 'PhabricatorConfigKeySchema' => 'PhabricatorConfigStorageSchema', 'PhabricatorConfigListController' => 'PhabricatorConfigController', @@ -5040,12 +5148,14 @@ phutil_register_library_map(array( 'Phobject', 'PhabricatorMarkupInterface', ), + 'PhabricatorConfigOptionType' => 'Phobject', 'PhabricatorConfigProxySource' => 'PhabricatorConfigSource', 'PhabricatorConfigResponse' => 'AphrontStandaloneHTMLResponse', 'PhabricatorConfigSchemaQuery' => 'Phobject', 'PhabricatorConfigSchemaSpec' => 'Phobject', 'PhabricatorConfigServerSchema' => 'PhabricatorConfigStorageSchema', 'PhabricatorConfigSiteSource' => 'PhabricatorConfigProxySource', + 'PhabricatorConfigSource' => 'Phobject', 'PhabricatorConfigStackSource' => 'PhabricatorConfigSource', 'PhabricatorConfigStorageSchema' => 'Phobject', 'PhabricatorConfigTableSchema' => 'PhabricatorConfigStorageSchema', @@ -5057,6 +5167,7 @@ phutil_register_library_map(array( 'PhabricatorConpherencePreferencesSettingsPanel' => 'PhabricatorSettingsPanel', 'PhabricatorConpherenceThreadPHIDType' => 'PhabricatorPHIDType', 'PhabricatorConsoleApplication' => 'PhabricatorApplication', + 'PhabricatorContentSource' => 'Phobject', 'PhabricatorContentSourceView' => 'AphrontView', 'PhabricatorContributedToObjectEdgeType' => 'PhabricatorEdgeType', 'PhabricatorController' => 'AphrontController', @@ -5081,6 +5192,8 @@ phutil_register_library_map(array( 'PhabricatorCountdownViewController' => 'PhabricatorCountdownController', 'PhabricatorCredentialsUsedByObjectEdgeType' => 'PhabricatorEdgeType', 'PhabricatorCursorPagedPolicyAwareQuery' => 'PhabricatorPolicyAwareQuery', + 'PhabricatorCustomField' => 'Phobject', + 'PhabricatorCustomFieldAttachment' => 'Phobject', 'PhabricatorCustomFieldConfigOptionType' => 'PhabricatorConfigOptionType', 'PhabricatorCustomFieldDataNotAvailableException' => 'Exception', 'PhabricatorCustomFieldImplementationIncompleteException' => 'Exception', @@ -5121,6 +5234,7 @@ phutil_register_library_map(array( 'PhabricatorDaemonManagementStatusWorkflow' => 'PhabricatorDaemonManagementWorkflow', 'PhabricatorDaemonManagementStopWorkflow' => 'PhabricatorDaemonManagementWorkflow', 'PhabricatorDaemonManagementWorkflow' => 'PhabricatorManagementWorkflow', + 'PhabricatorDaemonReference' => 'Phobject', 'PhabricatorDaemonTaskGarbageCollector' => 'PhabricatorGarbageCollector', 'PhabricatorDaemonTasksTableView' => 'AphrontView', 'PhabricatorDaemonsApplication' => 'PhabricatorApplication', @@ -5143,6 +5257,7 @@ phutil_register_library_map(array( 'PhabricatorDashboardHistoryController' => 'PhabricatorDashboardController', 'PhabricatorDashboardInstall' => 'PhabricatorDashboardDAO', 'PhabricatorDashboardInstallController' => 'PhabricatorDashboardController', + 'PhabricatorDashboardLayoutConfig' => 'Phobject', 'PhabricatorDashboardListController' => 'PhabricatorDashboardController', 'PhabricatorDashboardManageController' => 'PhabricatorDashboardController', 'PhabricatorDashboardMovePanelController' => 'PhabricatorDashboardController', @@ -5199,6 +5314,7 @@ phutil_register_library_map(array( 'PhabricatorDeveloperPreferencesSettingsPanel' => 'PhabricatorSettingsPanel', 'PhabricatorDiffInlineCommentQuery' => 'PhabricatorApplicationTransactionCommentQuery', 'PhabricatorDiffPreferencesSettingsPanel' => 'PhabricatorSettingsPanel', + 'PhabricatorDifferenceEngine' => 'Phobject', 'PhabricatorDifferentialApplication' => 'PhabricatorApplication', 'PhabricatorDifferentialConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorDifferentialRevisionTestDataGenerator' => 'PhabricatorTestDataGenerator', @@ -5214,6 +5330,7 @@ phutil_register_library_map(array( 'PhabricatorDraftDAO' => 'PhabricatorLiskDAO', 'PhabricatorDrydockApplication' => 'PhabricatorApplication', 'PhabricatorEdgeConfig' => 'PhabricatorEdgeConstants', + 'PhabricatorEdgeConstants' => 'Phobject', 'PhabricatorEdgeCycleException' => 'Exception', 'PhabricatorEdgeEditor' => 'Phobject', 'PhabricatorEdgeGraph' => 'AbstractDirectedGraph', @@ -5231,8 +5348,10 @@ phutil_register_library_map(array( 'PhabricatorEmbedFileRemarkupRule' => 'PhabricatorObjectRemarkupRule', 'PhabricatorEmojiRemarkupRule' => 'PhutilRemarkupRule', 'PhabricatorEmptyQueryException' => 'Exception', + 'PhabricatorEnv' => 'Phobject', 'PhabricatorEnvTestCase' => 'PhabricatorTestCase', 'PhabricatorEvent' => 'PhutilEvent', + 'PhabricatorEventEngine' => 'Phobject', 'PhabricatorEventListener' => 'PhutilEventListener', 'PhabricatorEventType' => 'PhutilEventType', 'PhabricatorExampleEventListener' => 'PhabricatorEventListener', @@ -5254,6 +5373,7 @@ phutil_register_library_map(array( 'PhabricatorFactCursor' => 'PhabricatorFactDAO', 'PhabricatorFactDAO' => 'PhabricatorLiskDAO', 'PhabricatorFactDaemon' => 'PhabricatorDaemon', + 'PhabricatorFactEngine' => 'Phobject', 'PhabricatorFactHomeController' => 'PhabricatorFactController', 'PhabricatorFactLastUpdatedEngine' => 'PhabricatorFactEngine', 'PhabricatorFactManagementAnalyzeWorkflow' => 'PhabricatorFactManagementWorkflow', @@ -5264,8 +5384,10 @@ phutil_register_library_map(array( 'PhabricatorFactManagementWorkflow' => 'PhabricatorManagementWorkflow', 'PhabricatorFactRaw' => 'PhabricatorFactDAO', 'PhabricatorFactSimpleSpec' => 'PhabricatorFactSpec', + 'PhabricatorFactSpec' => 'Phobject', 'PhabricatorFactUpdateIterator' => 'PhutilBufferedIterator', 'PhabricatorFeedApplication' => 'PhabricatorApplication', + 'PhabricatorFeedBuilder' => 'Phobject', 'PhabricatorFeedConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorFeedController' => 'PhabricatorController', 'PhabricatorFeedDAO' => 'PhabricatorLiskDAO', @@ -5277,11 +5399,13 @@ phutil_register_library_map(array( 'PhabricatorFeedQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorFeedSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorFeedStory' => array( + 'Phobject', 'PhabricatorPolicyInterface', 'PhabricatorMarkupInterface', ), 'PhabricatorFeedStoryData' => 'PhabricatorFeedDAO', 'PhabricatorFeedStoryNotification' => 'PhabricatorFeedDAO', + 'PhabricatorFeedStoryPublisher' => 'Phobject', 'PhabricatorFeedStoryReference' => 'PhabricatorFeedDAO', 'PhabricatorFile' => array( 'PhabricatorFileDAO', @@ -5292,6 +5416,7 @@ phutil_register_library_map(array( 'PhabricatorPolicyInterface', 'PhabricatorDestructibleInterface', ), + 'PhabricatorFileBundleLoader' => 'Phobject', 'PhabricatorFileChunk' => array( 'PhabricatorFileDAO', 'PhabricatorPolicyInterface', @@ -5330,6 +5455,7 @@ phutil_register_library_map(array( 'PhabricatorFileSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorFileStorageBlob' => 'PhabricatorFileDAO', 'PhabricatorFileStorageConfigurationException' => 'Exception', + 'PhabricatorFileStorageEngine' => 'Phobject', 'PhabricatorFileTemporaryGarbageCollector' => 'PhabricatorGarbageCollector', 'PhabricatorFileTestCase' => 'PhabricatorTestCase', 'PhabricatorFileTestDataGenerator' => 'PhabricatorTestDataGenerator', @@ -5360,6 +5486,7 @@ phutil_register_library_map(array( 'PhabricatorPolicyInterface', ), 'PhabricatorFlagColor' => 'PhabricatorFlagConstants', + 'PhabricatorFlagConstants' => 'Phobject', 'PhabricatorFlagController' => 'PhabricatorController', 'PhabricatorFlagDAO' => 'PhabricatorLiskDAO', 'PhabricatorFlagDeleteController' => 'PhabricatorFlagController', @@ -5387,6 +5514,7 @@ phutil_register_library_map(array( 'ArrayAccess', 'Countable', ), + 'PhabricatorHandleObjectSelectorDataView' => 'Phobject', 'PhabricatorHandlePool' => 'Phobject', 'PhabricatorHandlePoolTestCase' => 'PhabricatorTestCase', 'PhabricatorHandleQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', @@ -5412,6 +5540,7 @@ phutil_register_library_map(array( 'PhabricatorIRCProtocolAdapter' => 'PhabricatorProtocolAdapter', 'PhabricatorIconRemarkupRule' => 'PhutilRemarkupRule', 'PhabricatorImageMacroRemarkupRule' => 'PhutilRemarkupRule', + 'PhabricatorImageTransformer' => 'Phobject', 'PhabricatorImagemagickSetupCheck' => 'PhabricatorSetupCheck', 'PhabricatorInfrastructureTestCase' => 'PhabricatorTestCase', 'PhabricatorInlineCommentController' => 'PhabricatorController', @@ -5425,6 +5554,7 @@ phutil_register_library_map(array( 'PhabricatorJIRAAuthProvider' => 'PhabricatorOAuth1AuthProvider', 'PhabricatorJavelinLinter' => 'ArcanistLinter', 'PhabricatorJiraIssueHasObjectEdgeType' => 'PhabricatorEdgeType', + 'PhabricatorJumpNavHandler' => 'Phobject', 'PhabricatorKeyValueDatabaseCache' => 'PhutilKeyValueCache', 'PhabricatorLDAPAuthProvider' => 'PhabricatorAuthProvider', 'PhabricatorLegalpadApplication' => 'PhabricatorApplication', @@ -5432,10 +5562,12 @@ phutil_register_library_map(array( 'PhabricatorLegalpadDocumentPHIDType' => 'PhabricatorPHIDType', 'PhabricatorLegalpadSignaturePolicyRule' => 'PhabricatorPolicyRule', 'PhabricatorLibraryTestCase' => 'PhutilLibraryTestCase', + 'PhabricatorLipsumArtist' => 'Phobject', 'PhabricatorLipsumGenerateWorkflow' => 'PhabricatorLipsumManagementWorkflow', 'PhabricatorLipsumManagementWorkflow' => 'PhabricatorManagementWorkflow', 'PhabricatorLipsumMondrianArtist' => 'PhabricatorLipsumArtist', 'PhabricatorLiskDAO' => 'LiskDAO', + 'PhabricatorLiskSerializer' => 'Phobject', 'PhabricatorListFilterUIExample' => 'PhabricatorUIExample', 'PhabricatorLocalDiskFileStorageEngine' => 'PhabricatorFileStorageEngine', 'PhabricatorLocalTimeTestCase' => 'PhabricatorTestCase', @@ -5466,6 +5598,7 @@ phutil_register_library_map(array( 'PhabricatorMacroTransactionComment' => 'PhabricatorApplicationTransactionComment', 'PhabricatorMacroTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhabricatorMacroViewController' => 'PhabricatorMacroController', + 'PhabricatorMailImplementationAdapter' => 'Phobject', 'PhabricatorMailImplementationAmazonSESAdapter' => 'PhabricatorMailImplementationPHPMailerLiteAdapter', 'PhabricatorMailImplementationMailgunAdapter' => 'PhabricatorMailImplementationAdapter', 'PhabricatorMailImplementationPHPMailerAdapter' => 'PhabricatorMailImplementationAdapter', @@ -5480,7 +5613,9 @@ phutil_register_library_map(array( 'PhabricatorMailManagementShowInboundWorkflow' => 'PhabricatorMailManagementWorkflow', 'PhabricatorMailManagementShowOutboundWorkflow' => 'PhabricatorMailManagementWorkflow', 'PhabricatorMailManagementWorkflow' => 'PhabricatorManagementWorkflow', + 'PhabricatorMailReceiver' => 'Phobject', 'PhabricatorMailReceiverTestCase' => 'PhabricatorTestCase', + 'PhabricatorMailReplyHandler' => 'Phobject', 'PhabricatorMailSetupCheck' => 'PhabricatorSetupCheck', 'PhabricatorMailTarget' => 'Phobject', 'PhabricatorMailgunConfigOptions' => 'PhabricatorApplicationConfigOptions', @@ -5491,11 +5626,16 @@ phutil_register_library_map(array( 'PhabricatorManiphestConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorManiphestTaskTestDataGenerator' => 'PhabricatorTestDataGenerator', 'PhabricatorMarkupCache' => 'PhabricatorCacheDAO', - 'PhabricatorMarkupOneOff' => 'PhabricatorMarkupInterface', + 'PhabricatorMarkupEngine' => 'Phobject', + 'PhabricatorMarkupOneOff' => array( + 'Phobject', + 'PhabricatorMarkupInterface', + ), 'PhabricatorMarkupPreviewController' => 'PhabricatorController', 'PhabricatorMemeRemarkupRule' => 'PhutilRemarkupRule', 'PhabricatorMentionRemarkupRule' => 'PhutilRemarkupRule', 'PhabricatorMercurialGraphStream' => 'PhabricatorRepositoryGraphStream', + 'PhabricatorMetaMTAActor' => 'Phobject', 'PhabricatorMetaMTAActorQuery' => 'PhabricatorQuery', 'PhabricatorMetaMTAApplication' => 'PhabricatorApplication', 'PhabricatorMetaMTAApplicationEmail' => array( @@ -5512,13 +5652,17 @@ phutil_register_library_map(array( 'PhabricatorMetaMTAApplicationEmailQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorMetaMTAApplicationEmailTransaction' => 'PhabricatorApplicationTransaction', 'PhabricatorMetaMTAApplicationEmailTransactionQuery' => 'PhabricatorApplicationTransactionQuery', + 'PhabricatorMetaMTAAttachment' => 'Phobject', 'PhabricatorMetaMTAConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorMetaMTAController' => 'PhabricatorController', 'PhabricatorMetaMTADAO' => 'PhabricatorLiskDAO', + 'PhabricatorMetaMTAEmailBodyParser' => 'Phobject', 'PhabricatorMetaMTAEmailBodyParserTestCase' => 'PhabricatorTestCase', 'PhabricatorMetaMTAErrorMailAction' => 'PhabricatorSystemAction', 'PhabricatorMetaMTAMail' => 'PhabricatorMetaMTADAO', + 'PhabricatorMetaMTAMailBody' => 'Phobject', 'PhabricatorMetaMTAMailBodyTestCase' => 'PhabricatorTestCase', + 'PhabricatorMetaMTAMailSection' => 'Phobject', 'PhabricatorMetaMTAMailTestCase' => 'PhabricatorTestCase', 'PhabricatorMetaMTAMailableDatasource' => 'PhabricatorTypeaheadCompositeDatasource', 'PhabricatorMetaMTAMailableFunctionDatasource' => 'PhabricatorTypeaheadCompositeDatasource', @@ -5549,7 +5693,9 @@ phutil_register_library_map(array( 'PhabricatorNavigationRemarkupRule' => 'PhutilRemarkupRule', 'PhabricatorNeverTriggerClock' => 'PhabricatorTriggerClock', 'PhabricatorNotificationAdHocFeedStory' => 'PhabricatorFeedStory', + 'PhabricatorNotificationBuilder' => 'Phobject', 'PhabricatorNotificationClearController' => 'PhabricatorNotificationController', + 'PhabricatorNotificationClient' => 'Phobject', 'PhabricatorNotificationConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorNotificationController' => 'PhabricatorController', 'PhabricatorNotificationIndividualController' => 'PhabricatorNotificationController', @@ -5578,6 +5724,7 @@ phutil_register_library_map(array( 'PhabricatorOAuthClientSecretController' => 'PhabricatorOAuthClientController', 'PhabricatorOAuthClientViewController' => 'PhabricatorOAuthClientController', 'PhabricatorOAuthResponse' => 'AphrontResponse', + 'PhabricatorOAuthServer' => 'Phobject', 'PhabricatorOAuthServerAccessToken' => 'PhabricatorOAuthServerDAO', 'PhabricatorOAuthServerApplication' => 'PhabricatorApplication', 'PhabricatorOAuthServerAuthController' => 'PhabricatorAuthController', @@ -5595,10 +5742,14 @@ phutil_register_library_map(array( 'PhabricatorOAuthServerController' => 'PhabricatorController', 'PhabricatorOAuthServerCreateClientsCapability' => 'PhabricatorPolicyCapability', 'PhabricatorOAuthServerDAO' => 'PhabricatorLiskDAO', + 'PhabricatorOAuthServerScope' => 'Phobject', 'PhabricatorOAuthServerTestCase' => 'PhabricatorTestCase', 'PhabricatorOAuthServerTestController' => 'PhabricatorOAuthServerController', 'PhabricatorOAuthServerTokenController' => 'PhabricatorAuthController', - 'PhabricatorObjectHandle' => 'PhabricatorPolicyInterface', + 'PhabricatorObjectHandle' => array( + 'Phobject', + 'PhabricatorPolicyInterface', + ), 'PhabricatorObjectHasAsanaSubtaskEdgeType' => 'PhabricatorEdgeType', 'PhabricatorObjectHasAsanaTaskEdgeType' => 'PhabricatorEdgeType', 'PhabricatorObjectHasContributorEdgeType' => 'PhabricatorEdgeType', @@ -5607,6 +5758,7 @@ phutil_register_library_map(array( 'PhabricatorObjectHasSubscriberEdgeType' => 'PhabricatorEdgeType', 'PhabricatorObjectHasUnsubscriberEdgeType' => 'PhabricatorEdgeType', 'PhabricatorObjectHasWatcherEdgeType' => 'PhabricatorEdgeType', + 'PhabricatorObjectListQuery' => 'Phobject', 'PhabricatorObjectListQueryTestCase' => 'PhabricatorTestCase', 'PhabricatorObjectMailReceiver' => 'PhabricatorMailReceiver', 'PhabricatorObjectMailReceiverTestCase' => 'PhabricatorTestCase', @@ -5614,10 +5766,12 @@ phutil_register_library_map(array( 'PhabricatorObjectMentionsObjectEdgeType' => 'PhabricatorEdgeType', 'PhabricatorObjectQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorObjectRemarkupRule' => 'PhutilRemarkupRule', + 'PhabricatorObjectSelectorDialog' => 'Phobject', 'PhabricatorObjectUsesCredentialsEdgeType' => 'PhabricatorEdgeType', 'PhabricatorOffsetPagedQuery' => 'PhabricatorQuery', 'PhabricatorOneTimeTriggerClock' => 'PhabricatorTriggerClock', 'PhabricatorOpcodeCacheSpec' => 'PhabricatorCacheSpec', + 'PhabricatorOwnerPathQuery' => 'Phobject', 'PhabricatorOwnersApplication' => 'PhabricatorApplication', 'PhabricatorOwnersConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorOwnersController' => 'PhabricatorController', @@ -5642,6 +5796,9 @@ phutil_register_library_map(array( 'PhabricatorOwnersPath' => 'PhabricatorOwnersDAO', 'PhabricatorOwnersPathsController' => 'PhabricatorOwnersController', 'PhabricatorPHDConfigOptions' => 'PhabricatorApplicationConfigOptions', + 'PhabricatorPHID' => 'Phobject', + 'PhabricatorPHIDConstants' => 'Phobject', + 'PhabricatorPHIDType' => 'Phobject', 'PhabricatorPHPASTApplication' => 'PhabricatorApplication', 'PhabricatorPHPConfigSetupCheck' => 'PhabricatorSetupCheck', 'PhabricatorPHPMailerConfigOptions' => 'PhabricatorApplicationConfigOptions', @@ -5751,20 +5908,24 @@ phutil_register_library_map(array( 'PhabricatorPolicyCanViewCapability' => 'PhabricatorPolicyCapability', 'PhabricatorPolicyCapability' => 'Phobject', 'PhabricatorPolicyConfigOptions' => 'PhabricatorApplicationConfigOptions', + 'PhabricatorPolicyConstants' => 'Phobject', 'PhabricatorPolicyController' => 'PhabricatorController', 'PhabricatorPolicyDAO' => 'PhabricatorLiskDAO', 'PhabricatorPolicyDataTestCase' => 'PhabricatorTestCase', 'PhabricatorPolicyEditController' => 'PhabricatorPolicyController', 'PhabricatorPolicyException' => 'Exception', 'PhabricatorPolicyExplainController' => 'PhabricatorPolicyController', + 'PhabricatorPolicyFilter' => 'Phobject', 'PhabricatorPolicyInterface' => 'PhabricatorPHIDInterface', 'PhabricatorPolicyManagementShowWorkflow' => 'PhabricatorPolicyManagementWorkflow', 'PhabricatorPolicyManagementUnlockWorkflow' => 'PhabricatorPolicyManagementWorkflow', 'PhabricatorPolicyManagementWorkflow' => 'PhabricatorManagementWorkflow', 'PhabricatorPolicyPHIDTypePolicy' => 'PhabricatorPHIDType', 'PhabricatorPolicyQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', + 'PhabricatorPolicyRule' => 'Phobject', 'PhabricatorPolicyTestCase' => 'PhabricatorTestCase', 'PhabricatorPolicyTestObject' => array( + 'Phobject', 'PhabricatorPolicyInterface', 'PhabricatorExtendedPolicyInterface', ), @@ -5850,6 +6011,7 @@ phutil_register_library_map(array( 'PhabricatorProjectCustomField', 'PhabricatorStandardCustomFieldInterface', ), + 'PhabricatorProjectStatus' => 'Phobject', 'PhabricatorProjectTestDataGenerator' => 'PhabricatorTestDataGenerator', 'PhabricatorProjectTransaction' => 'PhabricatorApplicationTransaction', 'PhabricatorProjectTransactionEditor' => 'PhabricatorApplicationTransactionEditor', @@ -5859,7 +6021,9 @@ phutil_register_library_map(array( 'PhabricatorProjectViewController' => 'PhabricatorProjectController', 'PhabricatorProjectWatchController' => 'PhabricatorProjectController', 'PhabricatorProjectsPolicyRule' => 'PhabricatorPolicyRule', + 'PhabricatorProtocolAdapter' => 'Phobject', 'PhabricatorPygmentSetupCheck' => 'PhabricatorSetupCheck', + 'PhabricatorQuery' => 'Phobject', 'PhabricatorQueryConstraint' => 'Phobject', 'PhabricatorQueryOrderItem' => 'Phobject', 'PhabricatorQueryOrderTestCase' => 'PhabricatorTestCase', @@ -5921,13 +6085,16 @@ phutil_register_library_map(array( 'PhabricatorRepositoryCommitOwnersWorker' => 'PhabricatorRepositoryCommitParserWorker', 'PhabricatorRepositoryCommitPHIDType' => 'PhabricatorPHIDType', 'PhabricatorRepositoryCommitParserWorker' => 'PhabricatorWorker', + 'PhabricatorRepositoryCommitRef' => 'Phobject', 'PhabricatorRepositoryCommitSearchIndexer' => 'PhabricatorSearchDocumentIndexer', 'PhabricatorRepositoryConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorRepositoryDAO' => 'PhabricatorLiskDAO', 'PhabricatorRepositoryDiscoveryEngine' => 'PhabricatorRepositoryEngine', 'PhabricatorRepositoryEditor' => 'PhabricatorApplicationTransactionEditor', + 'PhabricatorRepositoryEngine' => 'Phobject', 'PhabricatorRepositoryGitCommitChangeParserWorker' => 'PhabricatorRepositoryCommitChangeParserWorker', 'PhabricatorRepositoryGitCommitMessageParserWorker' => 'PhabricatorRepositoryCommitMessageParserWorker', + 'PhabricatorRepositoryGraphCache' => 'Phobject', 'PhabricatorRepositoryGraphStream' => 'Phobject', 'PhabricatorRepositoryManagementCacheWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 'PhabricatorRepositoryManagementDiscoverWorkflow' => 'PhabricatorRepositoryManagementWorkflow', @@ -5987,6 +6154,7 @@ phutil_register_library_map(array( 'PhabricatorRepositoryTestCase' => 'PhabricatorTestCase', 'PhabricatorRepositoryTransaction' => 'PhabricatorApplicationTransaction', 'PhabricatorRepositoryTransactionQuery' => 'PhabricatorApplicationTransactionQuery', + 'PhabricatorRepositoryType' => 'Phobject', 'PhabricatorRepositoryURINormalizer' => 'Phobject', 'PhabricatorRepositoryURINormalizerTestCase' => 'PhabricatorTestCase', 'PhabricatorRepositoryURITestCase' => 'PhabricatorTestCase', @@ -5998,6 +6166,7 @@ phutil_register_library_map(array( 'PhabricatorSMSConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorSMSDAO' => 'PhabricatorLiskDAO', 'PhabricatorSMSDemultiplexWorker' => 'PhabricatorSMSWorker', + 'PhabricatorSMSImplementationAdapter' => 'Phobject', 'PhabricatorSMSImplementationTestBlackholeAdapter' => 'PhabricatorSMSImplementationAdapter', 'PhabricatorSMSImplementationTwilioAdapter' => 'PhabricatorSMSImplementationAdapter', 'PhabricatorSMSManagementListOutboundWorkflow' => 'PhabricatorSMSManagementWorkflow', @@ -6006,6 +6175,7 @@ phutil_register_library_map(array( 'PhabricatorSMSManagementWorkflow' => 'PhabricatorManagementWorkflow', 'PhabricatorSMSSendWorker' => 'PhabricatorSMSWorker', 'PhabricatorSMSWorker' => 'PhabricatorWorker', + 'PhabricatorSQLPatchList' => 'Phobject', 'PhabricatorSSHKeyGenerator' => 'Phobject', 'PhabricatorSSHKeysSettingsPanel' => 'PhabricatorSettingsPanel', 'PhabricatorSSHLog' => 'Phobject', @@ -6017,6 +6187,8 @@ phutil_register_library_map(array( ), 'PhabricatorSavedQueryQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorScheduleTaskTriggerAction' => 'PhabricatorTriggerAction', + 'PhabricatorScopedEnv' => 'Phobject', + 'PhabricatorSearchAbstractDocument' => 'Phobject', 'PhabricatorSearchApplication' => 'PhabricatorApplication', 'PhabricatorSearchApplicationSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorSearchApplicationStorageEnginePanel' => 'PhabricatorApplicationConfigurationPanel', @@ -6039,8 +6211,10 @@ phutil_register_library_map(array( 'PhabricatorSearchDocumentRelationship' => 'PhabricatorSearchDAO', 'PhabricatorSearchDocumentTypeDatasource' => 'PhabricatorTypeaheadDatasource', 'PhabricatorSearchEditController' => 'PhabricatorSearchBaseController', + 'PhabricatorSearchEngine' => 'Phobject', 'PhabricatorSearchField' => 'Phobject', 'PhabricatorSearchHovercardController' => 'PhabricatorSearchBaseController', + 'PhabricatorSearchIndexer' => 'Phobject', 'PhabricatorSearchManagementIndexWorkflow' => 'PhabricatorSearchManagementWorkflow', 'PhabricatorSearchManagementInitWorkflow' => 'PhabricatorSearchManagementWorkflow', 'PhabricatorSearchManagementWorkflow' => 'PhabricatorManagementWorkflow', @@ -6049,6 +6223,7 @@ phutil_register_library_map(array( 'PhabricatorSearchOwnersField' => 'PhabricatorSearchTokenizerField', 'PhabricatorSearchPreferencesSettingsPanel' => 'PhabricatorSettingsPanel', 'PhabricatorSearchProjectsField' => 'PhabricatorSearchTokenizerField', + 'PhabricatorSearchRelationship' => 'Phobject', 'PhabricatorSearchResultView' => 'AphrontView', 'PhabricatorSearchSelectController' => 'PhabricatorSearchBaseController', 'PhabricatorSearchSelectField' => 'PhabricatorSearchField', @@ -6068,6 +6243,9 @@ phutil_register_library_map(array( 'PhabricatorSettingsAdjustController' => 'PhabricatorController', 'PhabricatorSettingsApplication' => 'PhabricatorApplication', 'PhabricatorSettingsMainController' => 'PhabricatorController', + 'PhabricatorSettingsPanel' => 'Phobject', + 'PhabricatorSetupCheck' => 'Phobject', + 'PhabricatorSetupIssue' => 'Phobject', 'PhabricatorSetupIssueUIExample' => 'PhabricatorUIExample', 'PhabricatorSetupIssueView' => 'AphrontView', 'PhabricatorSlowvoteApplication' => 'PhabricatorApplication', @@ -6100,6 +6278,7 @@ phutil_register_library_map(array( 'PhabricatorSlowvoteTransactionComment' => 'PhabricatorApplicationTransactionComment', 'PhabricatorSlowvoteTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhabricatorSlowvoteVoteController' => 'PhabricatorSlowvoteController', + 'PhabricatorSlug' => 'Phobject', 'PhabricatorSlugTestCase' => 'PhabricatorTestCase', 'PhabricatorSortTableUIExample' => 'PhabricatorUIExample', 'PhabricatorSourceCodeView' => 'AphrontView', @@ -6145,6 +6324,8 @@ phutil_register_library_map(array( 'PhabricatorStandardPageView' => 'PhabricatorBarePageView', 'PhabricatorStatusController' => 'PhabricatorController', 'PhabricatorStatusUIExample' => 'PhabricatorUIExample', + 'PhabricatorStorageFixtureScopeGuard' => 'Phobject', + 'PhabricatorStorageManagementAPI' => 'Phobject', 'PhabricatorStorageManagementAdjustWorkflow' => 'PhabricatorStorageManagementWorkflow', 'PhabricatorStorageManagementDatabasesWorkflow' => 'PhabricatorStorageManagementWorkflow', 'PhabricatorStorageManagementDestroyWorkflow' => 'PhabricatorStorageManagementWorkflow', @@ -6156,6 +6337,7 @@ phutil_register_library_map(array( 'PhabricatorStorageManagementStatusWorkflow' => 'PhabricatorStorageManagementWorkflow', 'PhabricatorStorageManagementUpgradeWorkflow' => 'PhabricatorStorageManagementWorkflow', 'PhabricatorStorageManagementWorkflow' => 'PhabricatorManagementWorkflow', + 'PhabricatorStoragePatch' => 'Phobject', 'PhabricatorStorageSchemaSpec' => 'PhabricatorConfigSchemaSpec', 'PhabricatorStorageSetupCheck' => 'PhabricatorSetupCheck', 'PhabricatorStreamingProtocolAdapter' => 'PhabricatorProtocolAdapter', @@ -6172,7 +6354,9 @@ phutil_register_library_map(array( 'PhabricatorSubscriptionsUIEventListener' => 'PhabricatorEventListener', 'PhabricatorSubscriptionsUnsubscribeEmailCommand' => 'MetaMTAEmailTransactionCommand', 'PhabricatorSupportApplication' => 'PhabricatorApplication', + 'PhabricatorSyntaxHighlighter' => 'Phobject', 'PhabricatorSyntaxHighlightingConfigOptions' => 'PhabricatorApplicationConfigOptions', + 'PhabricatorSystemAction' => 'Phobject', 'PhabricatorSystemActionEngine' => 'Phobject', 'PhabricatorSystemActionGarbageCollector' => 'PhabricatorGarbageCollector', 'PhabricatorSystemActionLog' => 'PhabricatorSystemDAO', @@ -6192,9 +6376,12 @@ phutil_register_library_map(array( 'PhabricatorTestApplication' => 'PhabricatorApplication', 'PhabricatorTestCase' => 'PhutilTestCase', 'PhabricatorTestController' => 'PhabricatorController', + 'PhabricatorTestDataGenerator' => 'Phobject', 'PhabricatorTestNoCycleEdgeType' => 'PhabricatorEdgeType', 'PhabricatorTestStorageEngine' => 'PhabricatorFileStorageEngine', 'PhabricatorTestWorker' => 'PhabricatorWorker', + 'PhabricatorTime' => 'Phobject', + 'PhabricatorTimeGuard' => 'Phobject', 'PhabricatorTimeTestCase' => 'PhabricatorTestCase', 'PhabricatorTimezoneSetupCheck' => 'PhabricatorSetupCheck', 'PhabricatorToken' => array( @@ -6222,6 +6409,7 @@ phutil_register_library_map(array( 'PhabricatorTokensApplication' => 'PhabricatorApplication', 'PhabricatorTokensSettingsPanel' => 'PhabricatorSettingsPanel', 'PhabricatorTooltipUIExample' => 'PhabricatorUIExample', + 'PhabricatorTransactions' => 'Phobject', 'PhabricatorTransactionsApplication' => 'PhabricatorApplication', 'PhabricatorTransformedFile' => 'PhabricatorFileDAO', 'PhabricatorTranslationsConfigOptions' => 'PhabricatorApplicationConfigOptions', @@ -6241,9 +6429,11 @@ phutil_register_library_map(array( 'PhabricatorTypeaheadInvalidTokenException' => 'Exception', 'PhabricatorTypeaheadModularDatasourceController' => 'PhabricatorTypeaheadDatasourceController', 'PhabricatorTypeaheadMonogramDatasource' => 'PhabricatorTypeaheadDatasource', + 'PhabricatorTypeaheadResult' => 'Phobject', 'PhabricatorTypeaheadRuntimeCompositeDatasource' => 'PhabricatorTypeaheadCompositeDatasource', 'PhabricatorTypeaheadTokenView' => 'AphrontTagView', 'PhabricatorUIConfigOptions' => 'PhabricatorApplicationConfigOptions', + 'PhabricatorUIExample' => 'Phobject', 'PhabricatorUIExampleRenderController' => 'PhabricatorController', 'PhabricatorUIExamplesApplication' => 'PhabricatorApplication', 'PhabricatorUSEnglishTranslation' => 'PhutilTranslation', @@ -6296,6 +6486,7 @@ phutil_register_library_map(array( 'PhabricatorViewerDatasource' => 'PhabricatorTypeaheadDatasource', 'PhabricatorWatcherHasObjectEdgeType' => 'PhabricatorEdgeType', 'PhabricatorWordPressAuthProvider' => 'PhabricatorOAuth2AuthProvider', + 'PhabricatorWorker' => 'Phobject', 'PhabricatorWorkerActiveTask' => 'PhabricatorWorkerTask', 'PhabricatorWorkerArchiveTask' => 'PhabricatorWorkerTask', 'PhabricatorWorkerArchiveTaskQuery' => 'PhabricatorQuery', @@ -6395,6 +6586,7 @@ phutil_register_library_map(array( 'PhameQueryPostsConduitAPIMethod' => 'PhameConduitAPIMethod', 'PhameResourceController' => 'CelerityResourceController', 'PhameSchemaSpec' => 'PhabricatorConfigSchemaSpec', + 'PhameSkinSpecification' => 'Phobject', 'PhluxController' => 'PhabricatorController', 'PhluxDAO' => 'PhabricatorLiskDAO', 'PhluxEditController' => 'PhluxController', @@ -6486,6 +6678,7 @@ phutil_register_library_map(array( 'PhortuneCartCheckoutController' => 'PhortuneCartController', 'PhortuneCartController' => 'PhortuneController', 'PhortuneCartEditor' => 'PhabricatorApplicationTransactionEditor', + 'PhortuneCartImplementation' => 'Phobject', 'PhortuneCartListController' => 'PhortuneController', 'PhortuneCartPHIDType' => 'PhabricatorPHIDType', 'PhortuneCartQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', @@ -6504,7 +6697,9 @@ phutil_register_library_map(array( 'PhortuneChargeQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhortuneChargeSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhortuneChargeTableView' => 'AphrontView', + 'PhortuneConstants' => 'Phobject', 'PhortuneController' => 'PhabricatorController', + 'PhortuneCreditCardForm' => 'Phobject', 'PhortuneCurrency' => 'Phobject', 'PhortuneCurrencySerializer' => 'PhabricatorLiskSerializer', 'PhortuneCurrencyTestCase' => 'PhabricatorTestCase', @@ -6544,6 +6739,7 @@ phutil_register_library_map(array( 'PhortunePaymentMethodEditController' => 'PhortuneController', 'PhortunePaymentMethodPHIDType' => 'PhabricatorPHIDType', 'PhortunePaymentMethodQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', + 'PhortunePaymentProvider' => 'Phobject', 'PhortunePaymentProviderConfig' => array( 'PhortuneDAO', 'PhabricatorPolicyInterface', @@ -6557,6 +6753,7 @@ phutil_register_library_map(array( 'PhortuneDAO', 'PhabricatorPolicyInterface', ), + 'PhortuneProductImplementation' => 'Phobject', 'PhortuneProductListController' => 'PhabricatorController', 'PhortuneProductPHIDType' => 'PhabricatorPHIDType', 'PhortuneProductQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', @@ -6578,6 +6775,7 @@ phutil_register_library_map(array( ), 'PhortuneSubscriptionCart' => 'PhortuneCartImplementation', 'PhortuneSubscriptionEditController' => 'PhortuneController', + 'PhortuneSubscriptionImplementation' => 'Phobject', 'PhortuneSubscriptionListController' => 'PhortuneController', 'PhortuneSubscriptionPHIDType' => 'PhabricatorPHIDType', 'PhortuneSubscriptionProduct' => 'PhortuneProductImplementation', @@ -6653,6 +6851,7 @@ phutil_register_library_map(array( 'PhrequentUserTimeQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhrictionChangeType' => 'PhrictionConstants', 'PhrictionConduitAPIMethod' => 'ConduitAPIMethod', + 'PhrictionConstants' => 'Phobject', 'PhrictionContent' => array( 'PhrictionDAO', 'PhabricatorMarkupInterface', @@ -6717,6 +6916,7 @@ phutil_register_library_map(array( 'PonderAnswerTransaction' => 'PhabricatorApplicationTransaction', 'PonderAnswerTransactionComment' => 'PhabricatorApplicationTransactionComment', 'PonderAnswerTransactionQuery' => 'PhabricatorApplicationTransactionQuery', + 'PonderConstants' => 'Phobject', 'PonderController' => 'PhabricatorController', 'PonderDAO' => 'PhabricatorLiskDAO', 'PonderEditor' => 'PhabricatorApplicationTransactionEditor', @@ -6760,6 +6960,7 @@ phutil_register_library_map(array( 'PonderVotingUserHasAnswerEdgeType' => 'PhabricatorEdgeType', 'PonderVotingUserHasQuestionEdgeType' => 'PhabricatorEdgeType', 'ProjectAddProjectsEmailCommand' => 'MetaMTAEmailTransactionCommand', + 'ProjectBoardTaskCard' => 'Phobject', 'ProjectCanLockProjectsCapability' => 'PhabricatorPolicyCapability', 'ProjectConduitAPIMethod' => 'ConduitAPIMethod', 'ProjectCreateConduitAPIMethod' => 'ProjectConduitAPIMethod', @@ -6790,12 +6991,14 @@ phutil_register_library_map(array( 'ReleephBranchPreviewView' => 'AphrontFormControl', 'ReleephBranchQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'ReleephBranchSearchEngine' => 'PhabricatorApplicationSearchEngine', + 'ReleephBranchTemplate' => 'Phobject', 'ReleephBranchTransaction' => 'PhabricatorApplicationTransaction', 'ReleephBranchTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'ReleephBranchViewController' => array( 'ReleephBranchController', 'PhabricatorApplicationSearchResultsControllerInterface', ), + 'ReleephCommitFinder' => 'Phobject', 'ReleephCommitFinderException' => 'Exception', 'ReleephCommitMessageFieldSpecification' => 'ReleephFieldSpecification', 'ReleephConduitAPIMethod' => 'ConduitAPIMethod', @@ -6807,6 +7010,7 @@ phutil_register_library_map(array( 'ReleephDiffMessageFieldSpecification' => 'ReleephFieldSpecification', 'ReleephDiffSizeFieldSpecification' => 'ReleephFieldSpecification', 'ReleephFieldParseException' => 'Exception', + 'ReleephFieldSelector' => 'Phobject', 'ReleephFieldSpecification' => array( 'PhabricatorCustomField', 'PhabricatorMarkupInterface', @@ -6857,6 +7061,7 @@ phutil_register_library_map(array( 'ReleephRequestQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'ReleephRequestReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler', 'ReleephRequestSearchEngine' => 'PhabricatorApplicationSearchEngine', + 'ReleephRequestStatus' => 'Phobject', 'ReleephRequestTransaction' => 'PhabricatorApplicationTransaction', 'ReleephRequestTransactionComment' => 'PhabricatorApplicationTransactionComment', 'ReleephRequestTransactionQuery' => 'PhabricatorApplicationTransactionQuery', @@ -6886,6 +7091,8 @@ phutil_register_library_map(array( 'SlowvoteEmbedView' => 'AphrontView', 'SlowvoteInfoConduitAPIMethod' => 'SlowvoteConduitAPIMethod', 'SlowvoteRemarkupRule' => 'PhabricatorObjectRemarkupRule', + 'SubscriptionListDialogBuilder' => 'Phobject', + 'SubscriptionListStringBuilder' => 'Phobject', 'TokenConduitAPIMethod' => 'ConduitAPIMethod', 'TokenGiveConduitAPIMethod' => 'TokenConduitAPIMethod', 'TokenGivenConduitAPIMethod' => 'TokenConduitAPIMethod', diff --git a/src/aphront/AphrontRequest.php b/src/aphront/AphrontRequest.php index f4a1ee2cff..d29cd926d1 100644 --- a/src/aphront/AphrontRequest.php +++ b/src/aphront/AphrontRequest.php @@ -5,7 +5,7 @@ * @task cookie Managing Cookies * @task cluster Working With a Phabricator Cluster */ -final class AphrontRequest { +final class AphrontRequest extends Phobject { // NOTE: These magic request-type parameters are automatically included in // certain requests (e.g., by phabricator_form(), JX.Request, @@ -27,6 +27,7 @@ final class AphrontRequest { private $user; private $applicationConfiguration; private $uriData; + private $cookiePrefix; public function __construct($host, $path) { $this->host = $host; diff --git a/src/aphront/AphrontURIMapper.php b/src/aphront/AphrontURIMapper.php index 32f464911a..13108729b7 100644 --- a/src/aphront/AphrontURIMapper.php +++ b/src/aphront/AphrontURIMapper.php @@ -1,6 +1,6 @@ Saturday list, whilest the profile view shows a more simple * seven day rolling list of events. */ -final class CalendarTimeUtil { +final class CalendarTimeUtil extends Phobject { public static function getCalendarEventEpochs( PhabricatorUser $user, diff --git a/src/applications/celerity/CelerityAPI.php b/src/applications/celerity/CelerityAPI.php index d5649471af..2d5100ad17 100644 --- a/src/applications/celerity/CelerityAPI.php +++ b/src/applications/celerity/CelerityAPI.php @@ -4,7 +4,7 @@ * Indirection layer which provisions for a terrifying future where we need to * build multiple resource responses per page. */ -final class CelerityAPI { +final class CelerityAPI extends Phobject { private static $response; diff --git a/src/applications/celerity/CelerityResourceMap.php b/src/applications/celerity/CelerityResourceMap.php index 7e5e00594b..03ccfe607d 100644 --- a/src/applications/celerity/CelerityResourceMap.php +++ b/src/applications/celerity/CelerityResourceMap.php @@ -6,7 +6,7 @@ * not need to invoke it directly; instead, you call higher-level Celerity APIs * and it uses the resource map to satisfy your requests. */ -final class CelerityResourceMap { +final class CelerityResourceMap extends Phobject { private static $instances = array(); @@ -16,6 +16,7 @@ final class CelerityResourceMap { private $packageMap; private $nameMap; private $hashMap; + private $componentMap; public function __construct(CelerityResources $resources) { $this->resources = $resources; diff --git a/src/applications/celerity/CelerityResourceMapGenerator.php b/src/applications/celerity/CelerityResourceMapGenerator.php index b9c4ddaa37..a5bb657bd9 100644 --- a/src/applications/celerity/CelerityResourceMapGenerator.php +++ b/src/applications/celerity/CelerityResourceMapGenerator.php @@ -1,6 +1,6 @@ execute(); * */ -final class ConduitCall { +final class ConduitCall extends Phobject { private $method; + private $handler; private $request; private $user; diff --git a/src/applications/conduit/protocol/ConduitAPIRequest.php b/src/applications/conduit/protocol/ConduitAPIRequest.php index fe8af34b65..be1b88323e 100644 --- a/src/applications/conduit/protocol/ConduitAPIRequest.php +++ b/src/applications/conduit/protocol/ConduitAPIRequest.php @@ -1,6 +1,6 @@ rangeStart = $start; $this->rangeEnd = $end; diff --git a/src/applications/differential/parser/DifferentialCommitMessageParser.php b/src/applications/differential/parser/DifferentialCommitMessageParser.php index 00d2fe2c3f..fda7ae05b6 100644 --- a/src/applications/differential/parser/DifferentialCommitMessageParser.php +++ b/src/applications/differential/parser/DifferentialCommitMessageParser.php @@ -19,7 +19,7 @@ * @task support Support Methods * @task internal Internals */ -final class DifferentialCommitMessageParser { +final class DifferentialCommitMessageParser extends Phobject { private $labelMap; private $titleKey; diff --git a/src/applications/differential/parser/DifferentialHunkParser.php b/src/applications/differential/parser/DifferentialHunkParser.php index d49f4e1e26..8903c85f93 100644 --- a/src/applications/differential/parser/DifferentialHunkParser.php +++ b/src/applications/differential/parser/DifferentialHunkParser.php @@ -1,6 +1,6 @@ paths = $paths; diff --git a/src/applications/diffusion/request/DiffusionRequest.php b/src/applications/diffusion/request/DiffusionRequest.php index 2ed8e1f88e..6cf9aba8b3 100644 --- a/src/applications/diffusion/request/DiffusionRequest.php +++ b/src/applications/diffusion/request/DiffusionRequest.php @@ -7,7 +7,7 @@ * @task new Creating Requests * @task uri Managing Diffusion URIs */ -abstract class DiffusionRequest { +abstract class DiffusionRequest extends Phobject { protected $callsign; protected $path; diff --git a/src/applications/diffusion/ssh/DiffusionSubversionServeSSHWorkflow.php b/src/applications/diffusion/ssh/DiffusionSubversionServeSSHWorkflow.php index 4d085302c9..257e6e9adb 100644 --- a/src/applications/diffusion/ssh/DiffusionSubversionServeSSHWorkflow.php +++ b/src/applications/diffusion/ssh/DiffusionSubversionServeSSHWorkflow.php @@ -4,7 +4,6 @@ * This protocol has a good spec here: * * http://svn.apache.org/repos/asf/subversion/trunk/subversion/libsvn_ra_svn/protocol - * */ final class DiffusionSubversionServeSSHWorkflow extends DiffusionSubversionSSHWorkflow { diff --git a/src/applications/diffusion/symbol/DiffusionExternalSymbolQuery.php b/src/applications/diffusion/symbol/DiffusionExternalSymbolQuery.php index f8ca15aabd..d32f1b3f64 100644 --- a/src/applications/diffusion/symbol/DiffusionExternalSymbolQuery.php +++ b/src/applications/diffusion/symbol/DiffusionExternalSymbolQuery.php @@ -1,6 +1,6 @@ blueprint = $blueprint; diff --git a/src/applications/fact/engine/PhabricatorFactEngine.php b/src/applications/fact/engine/PhabricatorFactEngine.php index 99cee6a725..734b3296c0 100644 --- a/src/applications/fact/engine/PhabricatorFactEngine.php +++ b/src/applications/fact/engine/PhabricatorFactEngine.php @@ -1,6 +1,6 @@ diff --git a/src/applications/releeph/view/branch/ReleephBranchTemplate.php b/src/applications/releeph/view/branch/ReleephBranchTemplate.php index 7efaaad9fb..2441d924c1 100644 --- a/src/applications/releeph/view/branch/ReleephBranchTemplate.php +++ b/src/applications/releeph/view/branch/ReleephBranchTemplate.php @@ -1,6 +1,6 @@ Date: Mon, 15 Jun 2015 18:07:06 +1000 Subject: [PATCH 44/50] Add a bunch of tests for subclass implementations Summary: Add a bunch of tests to ensure that subclasses behave. Test Plan: `arc unit` Reviewers: eadler, #blessed_reviewers, epriestley Reviewed By: eadler, #blessed_reviewers, epriestley Subscribers: epriestley, Korvin Differential Revision: https://secure.phabricator.com/D13272 --- src/__phutil_library_map__.php | 46 +++++++++++++++++++ .../__tests__/AlmanacServiceTypeTestCase.php | 10 ++++ .../PhabricatorAuthFactorTestCase.php | 10 ++++ .../PhabricatorApplicationTestCase.php | 10 ++++ .../resources/CelerityPhysicalResources.php | 1 + .../CelerityPhysicalResourcesTestCase.php | 10 ++++ .../conduit/method/ConduitAPIMethod.php | 7 ++- .../__tests__/ConduitAPIMethodTestCase.php | 10 ++++ .../config/check/PhabricatorSetupCheck.php | 8 +++- .../PhabricatorSetupCheckTestCase.php | 10 ++++ ...DrydockBlueprintImplementationTestCase.php | 10 ++++ .../PhabricatorFactEngineTestCase.php | 10 ++++ .../PhabricatorFileStorageEngineTestCase.php | 10 ++++ .../PhabricatorFileTransformTestCase.php | 10 ++++ ...rmasterBuildStepImplementationTestCase.php | 11 +++++ .../ManiphestExcelFormatTestCase.php | 10 ++++ ...rApplicationConfigurationPanelTestCase.php | 11 +++++ ...MetaMTAEmailTransactionCommandTestCase.php | 10 ++++ .../NuanceSourceDefinitionTestCase.php | 10 ++++ .../PassphraseCredentialTypeTestCase.php | 10 ++++ .../phid/type/PhabricatorPHIDType.php | 2 +- .../__tests__/PhabricatorPHIDTypeTestCase.php | 10 ++++ .../PhortunePaymentProviderTestCase.php | 10 ++++ .../PhabricatorPolicyCapabilityTestCase.php | 11 +++++ ...ricatorApplicationSearchEngineTestCase.php | 11 +++++ .../PhabricatorSearchEngineTestCase.php | 10 ++++ .../__tests__/PhabricatorEdgeTypeTestCase.php | 10 ++++ ...catorIteratedMD5PasswordHasherTestCase.php | 15 ++++++ .../PhabricatorPasswordHasherTestCase.php | 10 ++-- 29 files changed, 302 insertions(+), 11 deletions(-) create mode 100644 src/applications/almanac/servicetype/__tests__/AlmanacServiceTypeTestCase.php create mode 100644 src/applications/auth/factor/__tests__/PhabricatorAuthFactorTestCase.php create mode 100644 src/applications/base/__tests__/PhabricatorApplicationTestCase.php create mode 100644 src/applications/celerity/resources/__tests__/CelerityPhysicalResourcesTestCase.php create mode 100644 src/applications/conduit/method/__tests__/ConduitAPIMethodTestCase.php create mode 100644 src/applications/config/check/__tests__/PhabricatorSetupCheckTestCase.php create mode 100644 src/applications/drydock/blueprint/__tests__/DrydockBlueprintImplementationTestCase.php create mode 100644 src/applications/fact/engine/__tests__/PhabricatorFactEngineTestCase.php create mode 100644 src/applications/files/engine/__tests__/PhabricatorFileStorageEngineTestCase.php create mode 100644 src/applications/files/transform/__tests__/PhabricatorFileTransformTestCase.php create mode 100644 src/applications/harbormaster/step/__tests__/HarbormasterBuildStepImplementationTestCase.php create mode 100644 src/applications/maniphest/export/__tests__/ManiphestExcelFormatTestCase.php create mode 100644 src/applications/meta/panel/__tests__/PhabricatorApplicationConfigurationPanelTestCase.php create mode 100644 src/applications/metamta/command/__tests__/MetaMTAEmailTransactionCommandTestCase.php create mode 100644 src/applications/nuance/source/__tests__/NuanceSourceDefinitionTestCase.php create mode 100644 src/applications/passphrase/credentialtype/__tests__/PassphraseCredentialTypeTestCase.php create mode 100644 src/applications/phid/type/__tests__/PhabricatorPHIDTypeTestCase.php create mode 100644 src/applications/phortune/provider/__tests__/PhortunePaymentProviderTestCase.php create mode 100644 src/applications/policy/capability/__tests__/PhabricatorPolicyCapabilityTestCase.php create mode 100644 src/applications/search/engine/__tests__/PhabricatorApplicationSearchEngineTestCase.php create mode 100644 src/applications/search/engine/__tests__/PhabricatorSearchEngineTestCase.php create mode 100644 src/infrastructure/edges/type/__tests__/PhabricatorEdgeTypeTestCase.php create mode 100644 src/infrastructure/util/password/__tests__/PhabricatorIteratedMD5PasswordHasherTestCase.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index c6bdc707b0..2b435ef161 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -92,6 +92,7 @@ phutil_register_library_map(array( 'AlmanacServiceTransaction' => 'applications/almanac/storage/AlmanacServiceTransaction.php', 'AlmanacServiceTransactionQuery' => 'applications/almanac/query/AlmanacServiceTransactionQuery.php', 'AlmanacServiceType' => 'applications/almanac/servicetype/AlmanacServiceType.php', + 'AlmanacServiceTypeTestCase' => 'applications/almanac/servicetype/__tests__/AlmanacServiceTypeTestCase.php', 'AlmanacServiceViewController' => 'applications/almanac/controller/AlmanacServiceViewController.php', 'AphlictDropdownDataQuery' => 'applications/aphlict/query/AphlictDropdownDataQuery.php', 'Aphront304Response' => 'aphront/response/Aphront304Response.php', @@ -184,6 +185,7 @@ phutil_register_library_map(array( 'CelerityPhabricatorResourceController' => 'applications/celerity/controller/CelerityPhabricatorResourceController.php', 'CelerityPhabricatorResources' => 'applications/celerity/resources/CelerityPhabricatorResources.php', 'CelerityPhysicalResources' => 'applications/celerity/resources/CelerityPhysicalResources.php', + 'CelerityPhysicalResourcesTestCase' => 'applications/celerity/resources/__tests__/CelerityPhysicalResourcesTestCase.php', 'CelerityResourceController' => 'applications/celerity/controller/CelerityResourceController.php', 'CelerityResourceGraph' => 'applications/celerity/CelerityResourceGraph.php', 'CelerityResourceMap' => 'applications/celerity/CelerityResourceMap.php', @@ -198,6 +200,7 @@ phutil_register_library_map(array( 'ChatLogQueryConduitAPIMethod' => 'applications/chatlog/conduit/ChatLogQueryConduitAPIMethod.php', 'ChatLogRecordConduitAPIMethod' => 'applications/chatlog/conduit/ChatLogRecordConduitAPIMethod.php', 'ConduitAPIMethod' => 'applications/conduit/method/ConduitAPIMethod.php', + 'ConduitAPIMethodTestCase' => 'applications/conduit/method/__tests__/ConduitAPIMethodTestCase.php', 'ConduitAPIRequest' => 'applications/conduit/protocol/ConduitAPIRequest.php', 'ConduitAPIResponse' => 'applications/conduit/protocol/ConduitAPIResponse.php', 'ConduitApplicationNotInstalledException' => 'applications/conduit/protocol/exception/ConduitApplicationNotInstalledException.php', @@ -702,6 +705,7 @@ phutil_register_library_map(array( 'DrydockBlueprintEditController' => 'applications/drydock/controller/DrydockBlueprintEditController.php', 'DrydockBlueprintEditor' => 'applications/drydock/editor/DrydockBlueprintEditor.php', 'DrydockBlueprintImplementation' => 'applications/drydock/blueprint/DrydockBlueprintImplementation.php', + 'DrydockBlueprintImplementationTestCase' => 'applications/drydock/blueprint/__tests__/DrydockBlueprintImplementationTestCase.php', 'DrydockBlueprintListController' => 'applications/drydock/controller/DrydockBlueprintListController.php', 'DrydockBlueprintPHIDType' => 'applications/drydock/phid/DrydockBlueprintPHIDType.php', 'DrydockBlueprintQuery' => 'applications/drydock/query/DrydockBlueprintQuery.php', @@ -844,6 +848,7 @@ phutil_register_library_map(array( 'HarbormasterBuildStepCustomField' => 'applications/harbormaster/customfield/HarbormasterBuildStepCustomField.php', 'HarbormasterBuildStepEditor' => 'applications/harbormaster/editor/HarbormasterBuildStepEditor.php', 'HarbormasterBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterBuildStepImplementation.php', + 'HarbormasterBuildStepImplementationTestCase' => 'applications/harbormaster/step/__tests__/HarbormasterBuildStepImplementationTestCase.php', 'HarbormasterBuildStepPHIDType' => 'applications/harbormaster/phid/HarbormasterBuildStepPHIDType.php', 'HarbormasterBuildStepQuery' => 'applications/harbormaster/query/HarbormasterBuildStepQuery.php', 'HarbormasterBuildStepTransaction' => 'applications/harbormaster/storage/configuration/HarbormasterBuildStepTransaction.php', @@ -1034,6 +1039,7 @@ phutil_register_library_map(array( 'ManiphestEmailCommand' => 'applications/maniphest/command/ManiphestEmailCommand.php', 'ManiphestExcelDefaultFormat' => 'applications/maniphest/export/ManiphestExcelDefaultFormat.php', 'ManiphestExcelFormat' => 'applications/maniphest/export/ManiphestExcelFormat.php', + 'ManiphestExcelFormatTestCase' => 'applications/maniphest/export/__tests__/ManiphestExcelFormatTestCase.php', 'ManiphestExportController' => 'applications/maniphest/controller/ManiphestExportController.php', 'ManiphestGetTaskTransactionsConduitAPIMethod' => 'applications/maniphest/conduit/ManiphestGetTaskTransactionsConduitAPIMethod.php', 'ManiphestHovercardEventListener' => 'applications/maniphest/event/ManiphestHovercardEventListener.php', @@ -1086,6 +1092,7 @@ phutil_register_library_map(array( 'ManiphestView' => 'applications/maniphest/view/ManiphestView.php', 'MetaMTAConstants' => 'applications/metamta/constants/MetaMTAConstants.php', 'MetaMTAEmailTransactionCommand' => 'applications/metamta/command/MetaMTAEmailTransactionCommand.php', + 'MetaMTAEmailTransactionCommandTestCase' => 'applications/metamta/command/__tests__/MetaMTAEmailTransactionCommandTestCase.php', 'MetaMTAMailReceivedGarbageCollector' => 'applications/metamta/garbagecollector/MetaMTAMailReceivedGarbageCollector.php', 'MetaMTAMailSentGarbageCollector' => 'applications/metamta/garbagecollector/MetaMTAMailSentGarbageCollector.php', 'MetaMTAReceivedMailStatus' => 'applications/metamta/constants/MetaMTAReceivedMailStatus.php', @@ -1144,6 +1151,7 @@ phutil_register_library_map(array( 'NuanceSourceDefaultEditCapability' => 'applications/nuance/capability/NuanceSourceDefaultEditCapability.php', 'NuanceSourceDefaultViewCapability' => 'applications/nuance/capability/NuanceSourceDefaultViewCapability.php', 'NuanceSourceDefinition' => 'applications/nuance/source/NuanceSourceDefinition.php', + 'NuanceSourceDefinitionTestCase' => 'applications/nuance/source/__tests__/NuanceSourceDefinitionTestCase.php', 'NuanceSourceEditController' => 'applications/nuance/controller/NuanceSourceEditController.php', 'NuanceSourceEditor' => 'applications/nuance/editor/NuanceSourceEditor.php', 'NuanceSourceListController' => 'applications/nuance/controller/NuanceSourceListController.php', @@ -1260,6 +1268,7 @@ phutil_register_library_map(array( 'PassphraseCredentialTransactionEditor' => 'applications/passphrase/editor/PassphraseCredentialTransactionEditor.php', 'PassphraseCredentialTransactionQuery' => 'applications/passphrase/query/PassphraseCredentialTransactionQuery.php', 'PassphraseCredentialType' => 'applications/passphrase/credentialtype/PassphraseCredentialType.php', + 'PassphraseCredentialTypeTestCase' => 'applications/passphrase/credentialtype/__tests__/PassphraseCredentialTypeTestCase.php', 'PassphraseCredentialViewController' => 'applications/passphrase/controller/PassphraseCredentialViewController.php', 'PassphraseDAO' => 'applications/passphrase/storage/PassphraseDAO.php', 'PassphrasePasswordCredentialType' => 'applications/passphrase/credentialtype/PassphrasePasswordCredentialType.php', @@ -1314,6 +1323,7 @@ phutil_register_library_map(array( 'PhabricatorApplicationApplicationPHIDType' => 'applications/meta/phid/PhabricatorApplicationApplicationPHIDType.php', 'PhabricatorApplicationConfigOptions' => 'applications/config/option/PhabricatorApplicationConfigOptions.php', 'PhabricatorApplicationConfigurationPanel' => 'applications/meta/panel/PhabricatorApplicationConfigurationPanel.php', + 'PhabricatorApplicationConfigurationPanelTestCase' => 'applications/meta/panel/__tests__/PhabricatorApplicationConfigurationPanelTestCase.php', 'PhabricatorApplicationDatasource' => 'applications/meta/typeahead/PhabricatorApplicationDatasource.php', 'PhabricatorApplicationDetailViewController' => 'applications/meta/controller/PhabricatorApplicationDetailViewController.php', 'PhabricatorApplicationEditController' => 'applications/meta/controller/PhabricatorApplicationEditController.php', @@ -1323,8 +1333,10 @@ phutil_register_library_map(array( 'PhabricatorApplicationQuery' => 'applications/meta/query/PhabricatorApplicationQuery.php', 'PhabricatorApplicationSearchController' => 'applications/search/controller/PhabricatorApplicationSearchController.php', 'PhabricatorApplicationSearchEngine' => 'applications/search/engine/PhabricatorApplicationSearchEngine.php', + 'PhabricatorApplicationSearchEngineTestCase' => 'applications/search/engine/__tests__/PhabricatorApplicationSearchEngineTestCase.php', 'PhabricatorApplicationSearchResultsControllerInterface' => 'applications/search/interface/PhabricatorApplicationSearchResultsControllerInterface.php', 'PhabricatorApplicationStatusView' => 'applications/meta/view/PhabricatorApplicationStatusView.php', + 'PhabricatorApplicationTestCase' => 'applications/base/__tests__/PhabricatorApplicationTestCase.php', 'PhabricatorApplicationTransaction' => 'applications/transactions/storage/PhabricatorApplicationTransaction.php', 'PhabricatorApplicationTransactionComment' => 'applications/transactions/storage/PhabricatorApplicationTransactionComment.php', 'PhabricatorApplicationTransactionCommentEditController' => 'applications/transactions/controller/PhabricatorApplicationTransactionCommentEditController.php', @@ -1397,6 +1409,7 @@ phutil_register_library_map(array( 'PhabricatorAuthEditController' => 'applications/auth/controller/config/PhabricatorAuthEditController.php', 'PhabricatorAuthFactor' => 'applications/auth/factor/PhabricatorAuthFactor.php', 'PhabricatorAuthFactorConfig' => 'applications/auth/storage/PhabricatorAuthFactorConfig.php', + 'PhabricatorAuthFactorTestCase' => 'applications/auth/factor/__tests__/PhabricatorAuthFactorTestCase.php', 'PhabricatorAuthFinishController' => 'applications/auth/controller/PhabricatorAuthFinishController.php', 'PhabricatorAuthHighSecurityRequiredException' => 'applications/auth/exception/PhabricatorAuthHighSecurityRequiredException.php', 'PhabricatorAuthHighSecurityToken' => 'applications/auth/data/PhabricatorAuthHighSecurityToken.php', @@ -1786,6 +1799,7 @@ phutil_register_library_map(array( 'PhabricatorEdgeQuery' => 'infrastructure/edges/query/PhabricatorEdgeQuery.php', 'PhabricatorEdgeTestCase' => 'infrastructure/edges/__tests__/PhabricatorEdgeTestCase.php', 'PhabricatorEdgeType' => 'infrastructure/edges/type/PhabricatorEdgeType.php', + 'PhabricatorEdgeTypeTestCase' => 'infrastructure/edges/type/__tests__/PhabricatorEdgeTypeTestCase.php', 'PhabricatorEditor' => 'infrastructure/PhabricatorEditor.php', 'PhabricatorElasticSearchEngine' => 'applications/search/engine/PhabricatorElasticSearchEngine.php', 'PhabricatorElasticSearchSetupCheck' => 'applications/config/check/PhabricatorElasticSearchSetupCheck.php', @@ -1821,6 +1835,7 @@ phutil_register_library_map(array( 'PhabricatorFactDAO' => 'applications/fact/storage/PhabricatorFactDAO.php', 'PhabricatorFactDaemon' => 'applications/fact/daemon/PhabricatorFactDaemon.php', 'PhabricatorFactEngine' => 'applications/fact/engine/PhabricatorFactEngine.php', + 'PhabricatorFactEngineTestCase' => 'applications/fact/engine/__tests__/PhabricatorFactEngineTestCase.php', 'PhabricatorFactHomeController' => 'applications/fact/controller/PhabricatorFactHomeController.php', 'PhabricatorFactLastUpdatedEngine' => 'applications/fact/engine/PhabricatorFactLastUpdatedEngine.php', 'PhabricatorFactManagementAnalyzeWorkflow' => 'applications/fact/management/PhabricatorFactManagementAnalyzeWorkflow.php', @@ -1878,6 +1893,7 @@ phutil_register_library_map(array( 'PhabricatorFileStorageBlob' => 'applications/files/storage/PhabricatorFileStorageBlob.php', 'PhabricatorFileStorageConfigurationException' => 'applications/files/exception/PhabricatorFileStorageConfigurationException.php', 'PhabricatorFileStorageEngine' => 'applications/files/engine/PhabricatorFileStorageEngine.php', + 'PhabricatorFileStorageEngineTestCase' => 'applications/files/engine/__tests__/PhabricatorFileStorageEngineTestCase.php', 'PhabricatorFileTemporaryGarbageCollector' => 'applications/files/garbagecollector/PhabricatorFileTemporaryGarbageCollector.php', 'PhabricatorFileTestCase' => 'applications/files/storage/__tests__/PhabricatorFileTestCase.php', 'PhabricatorFileTestDataGenerator' => 'applications/files/lipsum/PhabricatorFileTestDataGenerator.php', @@ -1888,6 +1904,7 @@ phutil_register_library_map(array( 'PhabricatorFileTransform' => 'applications/files/transform/PhabricatorFileTransform.php', 'PhabricatorFileTransformController' => 'applications/files/controller/PhabricatorFileTransformController.php', 'PhabricatorFileTransformListController' => 'applications/files/controller/PhabricatorFileTransformListController.php', + 'PhabricatorFileTransformTestCase' => 'applications/files/transform/__tests__/PhabricatorFileTransformTestCase.php', 'PhabricatorFileUploadController' => 'applications/files/controller/PhabricatorFileUploadController.php', 'PhabricatorFileUploadDialogController' => 'applications/files/controller/PhabricatorFileUploadDialogController.php', 'PhabricatorFileUploadException' => 'applications/files/exception/PhabricatorFileUploadException.php', @@ -1965,6 +1982,7 @@ phutil_register_library_map(array( 'PhabricatorInternationalizationManagementWorkflow' => 'infrastructure/internationalization/management/PhabricatorInternationalizationManagementWorkflow.php', 'PhabricatorInvalidConfigSetupCheck' => 'applications/config/check/PhabricatorInvalidConfigSetupCheck.php', 'PhabricatorIteratedMD5PasswordHasher' => 'infrastructure/util/password/PhabricatorIteratedMD5PasswordHasher.php', + 'PhabricatorIteratedMD5PasswordHasherTestCase' => 'infrastructure/util/password/__tests__/PhabricatorIteratedMD5PasswordHasherTestCase.php', 'PhabricatorJIRAAuthProvider' => 'applications/auth/provider/PhabricatorJIRAAuthProvider.php', 'PhabricatorJavelinLinter' => 'infrastructure/lint/linter/PhabricatorJavelinLinter.php', 'PhabricatorJiraIssueHasObjectEdgeType' => 'applications/doorkeeper/edge/PhabricatorJiraIssueHasObjectEdgeType.php', @@ -2190,6 +2208,7 @@ phutil_register_library_map(array( 'PhabricatorPHIDConstants' => 'applications/phid/PhabricatorPHIDConstants.php', 'PhabricatorPHIDInterface' => 'applications/phid/interface/PhabricatorPHIDInterface.php', 'PhabricatorPHIDType' => 'applications/phid/type/PhabricatorPHIDType.php', + 'PhabricatorPHIDTypeTestCase' => 'applications/phid/type/__tests__/PhabricatorPHIDTypeTestCase.php', 'PhabricatorPHPASTApplication' => 'applications/phpast/application/PhabricatorPHPASTApplication.php', 'PhabricatorPHPConfigSetupCheck' => 'applications/config/check/PhabricatorPHPConfigSetupCheck.php', 'PhabricatorPHPMailerConfigOptions' => 'applications/config/option/PhabricatorPHPMailerConfigOptions.php', @@ -2283,6 +2302,7 @@ phutil_register_library_map(array( 'PhabricatorPolicyCanJoinCapability' => 'applications/policy/capability/PhabricatorPolicyCanJoinCapability.php', 'PhabricatorPolicyCanViewCapability' => 'applications/policy/capability/PhabricatorPolicyCanViewCapability.php', 'PhabricatorPolicyCapability' => 'applications/policy/capability/PhabricatorPolicyCapability.php', + 'PhabricatorPolicyCapabilityTestCase' => 'applications/policy/capability/__tests__/PhabricatorPolicyCapabilityTestCase.php', 'PhabricatorPolicyConfigOptions' => 'applications/policy/config/PhabricatorPolicyConfigOptions.php', 'PhabricatorPolicyConstants' => 'applications/policy/constants/PhabricatorPolicyConstants.php', 'PhabricatorPolicyController' => 'applications/policy/controller/PhabricatorPolicyController.php', @@ -2520,6 +2540,7 @@ phutil_register_library_map(array( 'PhabricatorSearchDocumentTypeDatasource' => 'applications/search/typeahead/PhabricatorSearchDocumentTypeDatasource.php', 'PhabricatorSearchEditController' => 'applications/search/controller/PhabricatorSearchEditController.php', 'PhabricatorSearchEngine' => 'applications/search/engine/PhabricatorSearchEngine.php', + 'PhabricatorSearchEngineTestCase' => 'applications/search/engine/__tests__/PhabricatorSearchEngineTestCase.php', 'PhabricatorSearchField' => 'applications/search/field/PhabricatorSearchField.php', 'PhabricatorSearchHovercardController' => 'applications/search/controller/PhabricatorSearchHovercardController.php', 'PhabricatorSearchIndexer' => 'applications/search/index/PhabricatorSearchIndexer.php', @@ -2553,6 +2574,7 @@ phutil_register_library_map(array( 'PhabricatorSettingsMainController' => 'applications/settings/controller/PhabricatorSettingsMainController.php', 'PhabricatorSettingsPanel' => 'applications/settings/panel/PhabricatorSettingsPanel.php', 'PhabricatorSetupCheck' => 'applications/config/check/PhabricatorSetupCheck.php', + 'PhabricatorSetupCheckTestCase' => 'applications/config/check/__tests__/PhabricatorSetupCheckTestCase.php', 'PhabricatorSetupIssue' => 'applications/config/issue/PhabricatorSetupIssue.php', 'PhabricatorSetupIssueUIExample' => 'applications/uiexample/examples/PhabricatorSetupIssueUIExample.php', 'PhabricatorSetupIssueView' => 'applications/config/view/PhabricatorSetupIssueView.php', @@ -2970,6 +2992,7 @@ phutil_register_library_map(array( 'PhortunePaymentProviderConfigTransaction' => 'applications/phortune/storage/PhortunePaymentProviderConfigTransaction.php', 'PhortunePaymentProviderConfigTransactionQuery' => 'applications/phortune/query/PhortunePaymentProviderConfigTransactionQuery.php', 'PhortunePaymentProviderPHIDType' => 'applications/phortune/phid/PhortunePaymentProviderPHIDType.php', + 'PhortunePaymentProviderTestCase' => 'applications/phortune/provider/__tests__/PhortunePaymentProviderTestCase.php', 'PhortuneProduct' => 'applications/phortune/storage/PhortuneProduct.php', 'PhortuneProductImplementation' => 'applications/phortune/product/PhortuneProductImplementation.php', 'PhortuneProductListController' => 'applications/phortune/controller/PhortuneProductListController.php', @@ -3386,6 +3409,7 @@ phutil_register_library_map(array( 'AlmanacServiceTransaction' => 'PhabricatorApplicationTransaction', 'AlmanacServiceTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'AlmanacServiceType' => 'Phobject', + 'AlmanacServiceTypeTestCase' => 'PhabricatorTestCase', 'AlmanacServiceViewController' => 'AlmanacServiceController', 'AphlictDropdownDataQuery' => 'Phobject', 'Aphront304Response' => 'AphrontResponse', @@ -3481,6 +3505,7 @@ phutil_register_library_map(array( 'CelerityPhabricatorResourceController' => 'CelerityResourceController', 'CelerityPhabricatorResources' => 'CelerityResourcesOnDisk', 'CelerityPhysicalResources' => 'CelerityResources', + 'CelerityPhysicalResourcesTestCase' => 'PhabricatorTestCase', 'CelerityResourceController' => 'PhabricatorController', 'CelerityResourceGraph' => 'AbstractDirectedGraph', 'CelerityResourceMap' => 'Phobject', @@ -3498,6 +3523,7 @@ phutil_register_library_map(array( 'Phobject', 'PhabricatorPolicyInterface', ), + 'ConduitAPIMethodTestCase' => 'PhabricatorTestCase', 'ConduitAPIRequest' => 'Phobject', 'ConduitAPIResponse' => 'Phobject', 'ConduitApplicationNotInstalledException' => 'ConduitMethodNotFoundException', @@ -4059,6 +4085,7 @@ phutil_register_library_map(array( 'DrydockBlueprintEditController' => 'DrydockBlueprintController', 'DrydockBlueprintEditor' => 'PhabricatorApplicationTransactionEditor', 'DrydockBlueprintImplementation' => 'Phobject', + 'DrydockBlueprintImplementationTestCase' => 'PhabricatorTestCase', 'DrydockBlueprintListController' => 'DrydockBlueprintController', 'DrydockBlueprintPHIDType' => 'PhabricatorPHIDType', 'DrydockBlueprintQuery' => 'DrydockQuery', @@ -4250,6 +4277,7 @@ phutil_register_library_map(array( 'HarbormasterBuildStepCustomField' => 'PhabricatorCustomField', 'HarbormasterBuildStepEditor' => 'PhabricatorApplicationTransactionEditor', 'HarbormasterBuildStepImplementation' => 'Phobject', + 'HarbormasterBuildStepImplementationTestCase' => 'PhabricatorTestCase', 'HarbormasterBuildStepPHIDType' => 'PhabricatorPHIDType', 'HarbormasterBuildStepQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'HarbormasterBuildStepTransaction' => 'PhabricatorApplicationTransaction', @@ -4472,6 +4500,7 @@ phutil_register_library_map(array( 'ManiphestEmailCommand' => 'MetaMTAEmailTransactionCommand', 'ManiphestExcelDefaultFormat' => 'ManiphestExcelFormat', 'ManiphestExcelFormat' => 'Phobject', + 'ManiphestExcelFormatTestCase' => 'PhabricatorTestCase', 'ManiphestExportController' => 'ManiphestController', 'ManiphestGetTaskTransactionsConduitAPIMethod' => 'ManiphestConduitAPIMethod', 'ManiphestHovercardEventListener' => 'PhabricatorEventListener', @@ -4538,6 +4567,7 @@ phutil_register_library_map(array( 'ManiphestView' => 'AphrontView', 'MetaMTAConstants' => 'Phobject', 'MetaMTAEmailTransactionCommand' => 'Phobject', + 'MetaMTAEmailTransactionCommandTestCase' => 'PhabricatorTestCase', 'MetaMTAMailReceivedGarbageCollector' => 'PhabricatorGarbageCollector', 'MetaMTAMailSentGarbageCollector' => 'PhabricatorGarbageCollector', 'MetaMTAReceivedMailStatus' => 'MetaMTAConstants', @@ -4611,6 +4641,7 @@ phutil_register_library_map(array( 'NuanceSourceDefaultEditCapability' => 'PhabricatorPolicyCapability', 'NuanceSourceDefaultViewCapability' => 'PhabricatorPolicyCapability', 'NuanceSourceDefinition' => 'Phobject', + 'NuanceSourceDefinitionTestCase' => 'PhabricatorTestCase', 'NuanceSourceEditController' => 'NuanceController', 'NuanceSourceEditor' => 'PhabricatorApplicationTransactionEditor', 'NuanceSourceListController' => 'NuanceController', @@ -4732,6 +4763,7 @@ phutil_register_library_map(array( 'PassphraseCredentialTransactionEditor' => 'PhabricatorApplicationTransactionEditor', 'PassphraseCredentialTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PassphraseCredentialType' => 'Phobject', + 'PassphraseCredentialTypeTestCase' => 'PhabricatorTestCase', 'PassphraseCredentialViewController' => 'PassphraseController', 'PassphraseDAO' => 'PhabricatorLiskDAO', 'PassphrasePasswordCredentialType' => 'PassphraseCredentialType', @@ -4789,6 +4821,7 @@ phutil_register_library_map(array( 'PhabricatorApplicationApplicationPHIDType' => 'PhabricatorPHIDType', 'PhabricatorApplicationConfigOptions' => 'Phobject', 'PhabricatorApplicationConfigurationPanel' => 'Phobject', + 'PhabricatorApplicationConfigurationPanelTestCase' => 'PhabricatorTestCase', 'PhabricatorApplicationDatasource' => 'PhabricatorTypeaheadDatasource', 'PhabricatorApplicationDetailViewController' => 'PhabricatorApplicationsController', 'PhabricatorApplicationEditController' => 'PhabricatorApplicationsController', @@ -4798,7 +4831,9 @@ phutil_register_library_map(array( 'PhabricatorApplicationQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorApplicationSearchController' => 'PhabricatorSearchBaseController', 'PhabricatorApplicationSearchEngine' => 'Phobject', + 'PhabricatorApplicationSearchEngineTestCase' => 'PhabricatorTestCase', 'PhabricatorApplicationStatusView' => 'AphrontView', + 'PhabricatorApplicationTestCase' => 'PhabricatorTestCase', 'PhabricatorApplicationTransaction' => array( 'PhabricatorLiskDAO', 'PhabricatorPolicyInterface', @@ -4882,6 +4917,7 @@ phutil_register_library_map(array( 'PhabricatorAuthEditController' => 'PhabricatorAuthProviderConfigController', 'PhabricatorAuthFactor' => 'Phobject', 'PhabricatorAuthFactorConfig' => 'PhabricatorAuthDAO', + 'PhabricatorAuthFactorTestCase' => 'PhabricatorTestCase', 'PhabricatorAuthFinishController' => 'PhabricatorAuthController', 'PhabricatorAuthHighSecurityRequiredException' => 'Exception', 'PhabricatorAuthHighSecurityToken' => 'Phobject', @@ -5337,6 +5373,7 @@ phutil_register_library_map(array( 'PhabricatorEdgeQuery' => 'PhabricatorQuery', 'PhabricatorEdgeTestCase' => 'PhabricatorTestCase', 'PhabricatorEdgeType' => 'Phobject', + 'PhabricatorEdgeTypeTestCase' => 'PhabricatorTestCase', 'PhabricatorEditor' => 'Phobject', 'PhabricatorElasticSearchEngine' => 'PhabricatorSearchEngine', 'PhabricatorElasticSearchSetupCheck' => 'PhabricatorSetupCheck', @@ -5374,6 +5411,7 @@ phutil_register_library_map(array( 'PhabricatorFactDAO' => 'PhabricatorLiskDAO', 'PhabricatorFactDaemon' => 'PhabricatorDaemon', 'PhabricatorFactEngine' => 'Phobject', + 'PhabricatorFactEngineTestCase' => 'PhabricatorTestCase', 'PhabricatorFactHomeController' => 'PhabricatorFactController', 'PhabricatorFactLastUpdatedEngine' => 'PhabricatorFactEngine', 'PhabricatorFactManagementAnalyzeWorkflow' => 'PhabricatorFactManagementWorkflow', @@ -5456,6 +5494,7 @@ phutil_register_library_map(array( 'PhabricatorFileStorageBlob' => 'PhabricatorFileDAO', 'PhabricatorFileStorageConfigurationException' => 'Exception', 'PhabricatorFileStorageEngine' => 'Phobject', + 'PhabricatorFileStorageEngineTestCase' => 'PhabricatorTestCase', 'PhabricatorFileTemporaryGarbageCollector' => 'PhabricatorGarbageCollector', 'PhabricatorFileTestCase' => 'PhabricatorTestCase', 'PhabricatorFileTestDataGenerator' => 'PhabricatorTestDataGenerator', @@ -5466,6 +5505,7 @@ phutil_register_library_map(array( 'PhabricatorFileTransform' => 'Phobject', 'PhabricatorFileTransformController' => 'PhabricatorFileController', 'PhabricatorFileTransformListController' => 'PhabricatorFileController', + 'PhabricatorFileTransformTestCase' => 'PhabricatorTestCase', 'PhabricatorFileUploadController' => 'PhabricatorFileController', 'PhabricatorFileUploadDialogController' => 'PhabricatorFileController', 'PhabricatorFileUploadException' => 'Exception', @@ -5551,6 +5591,7 @@ phutil_register_library_map(array( 'PhabricatorInternationalizationManagementWorkflow' => 'PhabricatorManagementWorkflow', 'PhabricatorInvalidConfigSetupCheck' => 'PhabricatorSetupCheck', 'PhabricatorIteratedMD5PasswordHasher' => 'PhabricatorPasswordHasher', + 'PhabricatorIteratedMD5PasswordHasherTestCase' => 'PhabricatorTestCase', 'PhabricatorJIRAAuthProvider' => 'PhabricatorOAuth1AuthProvider', 'PhabricatorJavelinLinter' => 'ArcanistLinter', 'PhabricatorJiraIssueHasObjectEdgeType' => 'PhabricatorEdgeType', @@ -5799,6 +5840,7 @@ phutil_register_library_map(array( 'PhabricatorPHID' => 'Phobject', 'PhabricatorPHIDConstants' => 'Phobject', 'PhabricatorPHIDType' => 'Phobject', + 'PhabricatorPHIDTypeTestCase' => 'PhutilTestCase', 'PhabricatorPHPASTApplication' => 'PhabricatorApplication', 'PhabricatorPHPConfigSetupCheck' => 'PhabricatorSetupCheck', 'PhabricatorPHPMailerConfigOptions' => 'PhabricatorApplicationConfigOptions', @@ -5907,6 +5949,7 @@ phutil_register_library_map(array( 'PhabricatorPolicyCanJoinCapability' => 'PhabricatorPolicyCapability', 'PhabricatorPolicyCanViewCapability' => 'PhabricatorPolicyCapability', 'PhabricatorPolicyCapability' => 'Phobject', + 'PhabricatorPolicyCapabilityTestCase' => 'PhabricatorTestCase', 'PhabricatorPolicyConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorPolicyConstants' => 'Phobject', 'PhabricatorPolicyController' => 'PhabricatorController', @@ -6212,6 +6255,7 @@ phutil_register_library_map(array( 'PhabricatorSearchDocumentTypeDatasource' => 'PhabricatorTypeaheadDatasource', 'PhabricatorSearchEditController' => 'PhabricatorSearchBaseController', 'PhabricatorSearchEngine' => 'Phobject', + 'PhabricatorSearchEngineTestCase' => 'PhabricatorTestCase', 'PhabricatorSearchField' => 'Phobject', 'PhabricatorSearchHovercardController' => 'PhabricatorSearchBaseController', 'PhabricatorSearchIndexer' => 'Phobject', @@ -6245,6 +6289,7 @@ phutil_register_library_map(array( 'PhabricatorSettingsMainController' => 'PhabricatorController', 'PhabricatorSettingsPanel' => 'Phobject', 'PhabricatorSetupCheck' => 'Phobject', + 'PhabricatorSetupCheckTestCase' => 'PhabricatorTestCase', 'PhabricatorSetupIssue' => 'Phobject', 'PhabricatorSetupIssueUIExample' => 'PhabricatorUIExample', 'PhabricatorSetupIssueView' => 'AphrontView', @@ -6749,6 +6794,7 @@ phutil_register_library_map(array( 'PhortunePaymentProviderConfigTransaction' => 'PhabricatorApplicationTransaction', 'PhortunePaymentProviderConfigTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhortunePaymentProviderPHIDType' => 'PhabricatorPHIDType', + 'PhortunePaymentProviderTestCase' => 'PhabricatorTestCase', 'PhortuneProduct' => array( 'PhortuneDAO', 'PhabricatorPolicyInterface', diff --git a/src/applications/almanac/servicetype/__tests__/AlmanacServiceTypeTestCase.php b/src/applications/almanac/servicetype/__tests__/AlmanacServiceTypeTestCase.php new file mode 100644 index 0000000000..535c07f6d8 --- /dev/null +++ b/src/applications/almanac/servicetype/__tests__/AlmanacServiceTypeTestCase.php @@ -0,0 +1,10 @@ +assertTrue(true); + } + +} diff --git a/src/applications/auth/factor/__tests__/PhabricatorAuthFactorTestCase.php b/src/applications/auth/factor/__tests__/PhabricatorAuthFactorTestCase.php new file mode 100644 index 0000000000..ccc4fc5c93 --- /dev/null +++ b/src/applications/auth/factor/__tests__/PhabricatorAuthFactorTestCase.php @@ -0,0 +1,10 @@ +assertTrue(true); + } + +} diff --git a/src/applications/base/__tests__/PhabricatorApplicationTestCase.php b/src/applications/base/__tests__/PhabricatorApplicationTestCase.php new file mode 100644 index 0000000000..ca01cba111 --- /dev/null +++ b/src/applications/base/__tests__/PhabricatorApplicationTestCase.php @@ -0,0 +1,10 @@ +assertTrue(true); + } + +} diff --git a/src/applications/celerity/resources/CelerityPhysicalResources.php b/src/applications/celerity/resources/CelerityPhysicalResources.php index 41665d15f2..730c8dc435 100644 --- a/src/applications/celerity/resources/CelerityPhysicalResources.php +++ b/src/applications/celerity/resources/CelerityPhysicalResources.php @@ -21,6 +21,7 @@ abstract class CelerityPhysicalResources extends CelerityResources { public static function getAll() { static $resources_map; + if ($resources_map === null) { $resources_map = array(); diff --git a/src/applications/celerity/resources/__tests__/CelerityPhysicalResourcesTestCase.php b/src/applications/celerity/resources/__tests__/CelerityPhysicalResourcesTestCase.php new file mode 100644 index 0000000000..a7ac29649a --- /dev/null +++ b/src/applications/celerity/resources/__tests__/CelerityPhysicalResourcesTestCase.php @@ -0,0 +1,10 @@ +assertTrue(true); + } + +} diff --git a/src/applications/conduit/method/ConduitAPIMethod.php b/src/applications/conduit/method/ConduitAPIMethod.php index 8b9a67f4be..a56f680432 100644 --- a/src/applications/conduit/method/ConduitAPIMethod.php +++ b/src/applications/conduit/method/ConduitAPIMethod.php @@ -115,7 +115,7 @@ abstract class ConduitAPIMethod return head(explode('.', $this->getAPIMethodName(), 2)); } - public static function getConduitMethod($method_name) { + public static function loadAllConduitMethods() { static $method_map = null; if ($method_map === null) { @@ -143,6 +143,11 @@ abstract class ConduitAPIMethod } } + return $method_map; + } + + public static function getConduitMethod($method_name) { + $method_map = self::loadAllConduitMethods(); return idx($method_map, $method_name); } diff --git a/src/applications/conduit/method/__tests__/ConduitAPIMethodTestCase.php b/src/applications/conduit/method/__tests__/ConduitAPIMethodTestCase.php new file mode 100644 index 0000000000..d0f54e297c --- /dev/null +++ b/src/applications/conduit/method/__tests__/ConduitAPIMethodTestCase.php @@ -0,0 +1,10 @@ +assertTrue(true); + } + +} diff --git a/src/applications/config/check/PhabricatorSetupCheck.php b/src/applications/config/check/PhabricatorSetupCheck.php index 61b34df875..2ea2facd4e 100644 --- a/src/applications/config/check/PhabricatorSetupCheck.php +++ b/src/applications/config/check/PhabricatorSetupCheck.php @@ -111,7 +111,7 @@ abstract class PhabricatorSetupCheck extends Phobject { } } - final public static function runAllChecks() { + final public static function loadAllChecks() { $symbols = id(new PhutilSymbolLoader()) ->setAncestorClass(__CLASS__) ->setConcreteOnly(true) @@ -122,7 +122,11 @@ abstract class PhabricatorSetupCheck extends Phobject { $checks[] = newv($symbol['name'], array()); } - $checks = msort($checks, 'getExecutionOrder'); + return msort($checks, 'getExecutionOrder'); + } + + final public static function runAllChecks() { + $checks = self::loadAllChecks(); $issues = array(); foreach ($checks as $check) { diff --git a/src/applications/config/check/__tests__/PhabricatorSetupCheckTestCase.php b/src/applications/config/check/__tests__/PhabricatorSetupCheckTestCase.php new file mode 100644 index 0000000000..256b69ee7f --- /dev/null +++ b/src/applications/config/check/__tests__/PhabricatorSetupCheckTestCase.php @@ -0,0 +1,10 @@ +assertTrue(true); + } + +} diff --git a/src/applications/drydock/blueprint/__tests__/DrydockBlueprintImplementationTestCase.php b/src/applications/drydock/blueprint/__tests__/DrydockBlueprintImplementationTestCase.php new file mode 100644 index 0000000000..b3f4a78a27 --- /dev/null +++ b/src/applications/drydock/blueprint/__tests__/DrydockBlueprintImplementationTestCase.php @@ -0,0 +1,10 @@ +assertTrue(true); + } + +} diff --git a/src/applications/fact/engine/__tests__/PhabricatorFactEngineTestCase.php b/src/applications/fact/engine/__tests__/PhabricatorFactEngineTestCase.php new file mode 100644 index 0000000000..fd665d237a --- /dev/null +++ b/src/applications/fact/engine/__tests__/PhabricatorFactEngineTestCase.php @@ -0,0 +1,10 @@ +assertTrue(true); + } + +} diff --git a/src/applications/files/engine/__tests__/PhabricatorFileStorageEngineTestCase.php b/src/applications/files/engine/__tests__/PhabricatorFileStorageEngineTestCase.php new file mode 100644 index 0000000000..8ffbe0366b --- /dev/null +++ b/src/applications/files/engine/__tests__/PhabricatorFileStorageEngineTestCase.php @@ -0,0 +1,10 @@ +assertTrue(true); + } + +} diff --git a/src/applications/files/transform/__tests__/PhabricatorFileTransformTestCase.php b/src/applications/files/transform/__tests__/PhabricatorFileTransformTestCase.php new file mode 100644 index 0000000000..4cc4a6e54b --- /dev/null +++ b/src/applications/files/transform/__tests__/PhabricatorFileTransformTestCase.php @@ -0,0 +1,10 @@ +assertTrue(true); + } + +} diff --git a/src/applications/harbormaster/step/__tests__/HarbormasterBuildStepImplementationTestCase.php b/src/applications/harbormaster/step/__tests__/HarbormasterBuildStepImplementationTestCase.php new file mode 100644 index 0000000000..6a37b0112d --- /dev/null +++ b/src/applications/harbormaster/step/__tests__/HarbormasterBuildStepImplementationTestCase.php @@ -0,0 +1,11 @@ +assertTrue(true); + } + +} diff --git a/src/applications/maniphest/export/__tests__/ManiphestExcelFormatTestCase.php b/src/applications/maniphest/export/__tests__/ManiphestExcelFormatTestCase.php new file mode 100644 index 0000000000..a3c312fcd2 --- /dev/null +++ b/src/applications/maniphest/export/__tests__/ManiphestExcelFormatTestCase.php @@ -0,0 +1,10 @@ +assertTrue(true); + } + +} diff --git a/src/applications/meta/panel/__tests__/PhabricatorApplicationConfigurationPanelTestCase.php b/src/applications/meta/panel/__tests__/PhabricatorApplicationConfigurationPanelTestCase.php new file mode 100644 index 0000000000..10aab23771 --- /dev/null +++ b/src/applications/meta/panel/__tests__/PhabricatorApplicationConfigurationPanelTestCase.php @@ -0,0 +1,11 @@ +assertTrue(true); + } + +} diff --git a/src/applications/metamta/command/__tests__/MetaMTAEmailTransactionCommandTestCase.php b/src/applications/metamta/command/__tests__/MetaMTAEmailTransactionCommandTestCase.php new file mode 100644 index 0000000000..3668594ca1 --- /dev/null +++ b/src/applications/metamta/command/__tests__/MetaMTAEmailTransactionCommandTestCase.php @@ -0,0 +1,10 @@ +assertTrue(true); + } + +} diff --git a/src/applications/nuance/source/__tests__/NuanceSourceDefinitionTestCase.php b/src/applications/nuance/source/__tests__/NuanceSourceDefinitionTestCase.php new file mode 100644 index 0000000000..39b0358f4c --- /dev/null +++ b/src/applications/nuance/source/__tests__/NuanceSourceDefinitionTestCase.php @@ -0,0 +1,10 @@ +assertTrue(true); + } + +} diff --git a/src/applications/passphrase/credentialtype/__tests__/PassphraseCredentialTypeTestCase.php b/src/applications/passphrase/credentialtype/__tests__/PassphraseCredentialTypeTestCase.php new file mode 100644 index 0000000000..0642ad132e --- /dev/null +++ b/src/applications/passphrase/credentialtype/__tests__/PassphraseCredentialTypeTestCase.php @@ -0,0 +1,10 @@ +assertTrue(true); + } + +} diff --git a/src/applications/phid/type/PhabricatorPHIDType.php b/src/applications/phid/type/PhabricatorPHIDType.php index 71a7613c04..7006d8bb4a 100644 --- a/src/applications/phid/type/PhabricatorPHIDType.php +++ b/src/applications/phid/type/PhabricatorPHIDType.php @@ -158,7 +158,7 @@ abstract class PhabricatorPHIDType extends Phobject { * * @return dict Map of type constants to types. */ - public static function getAllTypes() { + final public static function getAllTypes() { static $types; if ($types === null) { $objects = id(new PhutilSymbolLoader()) diff --git a/src/applications/phid/type/__tests__/PhabricatorPHIDTypeTestCase.php b/src/applications/phid/type/__tests__/PhabricatorPHIDTypeTestCase.php new file mode 100644 index 0000000000..e7707095ad --- /dev/null +++ b/src/applications/phid/type/__tests__/PhabricatorPHIDTypeTestCase.php @@ -0,0 +1,10 @@ +assertTrue(true); + } + +} diff --git a/src/applications/phortune/provider/__tests__/PhortunePaymentProviderTestCase.php b/src/applications/phortune/provider/__tests__/PhortunePaymentProviderTestCase.php new file mode 100644 index 0000000000..64ce50c556 --- /dev/null +++ b/src/applications/phortune/provider/__tests__/PhortunePaymentProviderTestCase.php @@ -0,0 +1,10 @@ +assertTrue(true); + } + +} diff --git a/src/applications/policy/capability/__tests__/PhabricatorPolicyCapabilityTestCase.php b/src/applications/policy/capability/__tests__/PhabricatorPolicyCapabilityTestCase.php new file mode 100644 index 0000000000..0def247621 --- /dev/null +++ b/src/applications/policy/capability/__tests__/PhabricatorPolicyCapabilityTestCase.php @@ -0,0 +1,11 @@ +assertTrue(true); + } + +} diff --git a/src/applications/search/engine/__tests__/PhabricatorApplicationSearchEngineTestCase.php b/src/applications/search/engine/__tests__/PhabricatorApplicationSearchEngineTestCase.php new file mode 100644 index 0000000000..488f4692ac --- /dev/null +++ b/src/applications/search/engine/__tests__/PhabricatorApplicationSearchEngineTestCase.php @@ -0,0 +1,11 @@ +assertTrue(true); + } + +} diff --git a/src/applications/search/engine/__tests__/PhabricatorSearchEngineTestCase.php b/src/applications/search/engine/__tests__/PhabricatorSearchEngineTestCase.php new file mode 100644 index 0000000000..bf997288b6 --- /dev/null +++ b/src/applications/search/engine/__tests__/PhabricatorSearchEngineTestCase.php @@ -0,0 +1,10 @@ +assertTrue(true); + } + +} diff --git a/src/infrastructure/edges/type/__tests__/PhabricatorEdgeTypeTestCase.php b/src/infrastructure/edges/type/__tests__/PhabricatorEdgeTypeTestCase.php new file mode 100644 index 0000000000..08a9fc126a --- /dev/null +++ b/src/infrastructure/edges/type/__tests__/PhabricatorEdgeTypeTestCase.php @@ -0,0 +1,10 @@ +assertTrue(true); + } + +} diff --git a/src/infrastructure/util/password/__tests__/PhabricatorIteratedMD5PasswordHasherTestCase.php b/src/infrastructure/util/password/__tests__/PhabricatorIteratedMD5PasswordHasherTestCase.php new file mode 100644 index 0000000000..b3644a5640 --- /dev/null +++ b/src/infrastructure/util/password/__tests__/PhabricatorIteratedMD5PasswordHasherTestCase.php @@ -0,0 +1,15 @@ +assertEqual( + 'md5:4824a35493d8b5dceab36f017d68425f', + $hasher->getPasswordHashForStorage( + new PhutilOpaqueEnvelope('quack'))->openEnvelope()); + } + +} diff --git a/src/infrastructure/util/password/__tests__/PhabricatorPasswordHasherTestCase.php b/src/infrastructure/util/password/__tests__/PhabricatorPasswordHasherTestCase.php index 053acea4fc..db1bfadf74 100644 --- a/src/infrastructure/util/password/__tests__/PhabricatorPasswordHasherTestCase.php +++ b/src/infrastructure/util/password/__tests__/PhabricatorPasswordHasherTestCase.php @@ -28,13 +28,9 @@ final class PhabricatorPasswordHasherTestCase extends PhabricatorTestCase { pht('Fictional hasher unavailable.')); } - public function testMD5Hasher() { - $hasher = new PhabricatorIteratedMD5PasswordHasher(); - - $this->assertEqual( - 'md5:4824a35493d8b5dceab36f017d68425f', - $hasher->getPasswordHashForStorage( - new PhutilOpaqueEnvelope('quack'))->openEnvelope()); + public function testGetAllHashers() { + PhabricatorPasswordHasher::getAllHashers(); + $this->assertTrue(true); } } From b95fc8ba5d9f9679519aa5ef4daba4b8f75b5e9e Mon Sep 17 00:00:00 2001 From: Joshua Spence Date: Mon, 15 Jun 2015 18:41:09 +1000 Subject: [PATCH 45/50] Fix another undeclared property This was reported in IRC, see https://secure.phabricator.com/chatlog/channel/6/?at=204524. Auditors: epriestley --- src/infrastructure/markup/PhabricatorMarkupEngine.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/infrastructure/markup/PhabricatorMarkupEngine.php b/src/infrastructure/markup/PhabricatorMarkupEngine.php index d3f575c4ca..1694d42db0 100644 --- a/src/infrastructure/markup/PhabricatorMarkupEngine.php +++ b/src/infrastructure/markup/PhabricatorMarkupEngine.php @@ -43,6 +43,7 @@ final class PhabricatorMarkupEngine extends Phobject { private $viewer; private $contextObject; private $version = 15; + private $engineCaches = array(); /* -( Markup Pipeline )---------------------------------------------------- */ From 62648237c25e51f15b16b3506aa4dcc930d181b8 Mon Sep 17 00:00:00 2001 From: Joshua Spence Date: Mon, 15 Jun 2015 18:55:04 +1000 Subject: [PATCH 46/50] Fix a few more undeclared properties Summary: Ref T8538. Ref T8539. Ref T8541. Test Plan: Eyeball it. Reviewers: epriestley, de_jean_7777, benoittgt, #blessed_reviewers Reviewed By: benoittgt Subscribers: epriestley, Korvin Maniphest Tasks: T8541, T8538, T8539 Differential Revision: https://secure.phabricator.com/D13293 --- .../diffusion/query/pathid/DiffusionPathIDQuery.php | 2 ++ src/applications/feed/builder/PhabricatorFeedBuilder.php | 1 + .../herald/adapter/HeraldDifferentialRevisionAdapter.php | 1 + .../PhabricatorMailImplementationPHPMailerLiteAdapter.php | 2 ++ .../releeph/view/branch/ReleephBranchTemplate.php | 5 +++++ 5 files changed, 11 insertions(+) diff --git a/src/applications/diffusion/query/pathid/DiffusionPathIDQuery.php b/src/applications/diffusion/query/pathid/DiffusionPathIDQuery.php index a36c0da816..7c9e721431 100644 --- a/src/applications/diffusion/query/pathid/DiffusionPathIDQuery.php +++ b/src/applications/diffusion/query/pathid/DiffusionPathIDQuery.php @@ -5,6 +5,8 @@ */ final class DiffusionPathIDQuery extends Phobject { + private $paths = array(); + public function __construct(array $paths) { $this->paths = $paths; } diff --git a/src/applications/feed/builder/PhabricatorFeedBuilder.php b/src/applications/feed/builder/PhabricatorFeedBuilder.php index d4aa23b38b..898f2aa6f7 100644 --- a/src/applications/feed/builder/PhabricatorFeedBuilder.php +++ b/src/applications/feed/builder/PhabricatorFeedBuilder.php @@ -2,6 +2,7 @@ final class PhabricatorFeedBuilder extends Phobject { + private $user; private $stories; private $framed; private $hovercards = false; diff --git a/src/applications/herald/adapter/HeraldDifferentialRevisionAdapter.php b/src/applications/herald/adapter/HeraldDifferentialRevisionAdapter.php index afd328b342..a731254870 100644 --- a/src/applications/herald/adapter/HeraldDifferentialRevisionAdapter.php +++ b/src/applications/herald/adapter/HeraldDifferentialRevisionAdapter.php @@ -3,6 +3,7 @@ final class HeraldDifferentialRevisionAdapter extends HeraldDifferentialAdapter { + protected $diff; protected $revision; protected $explicitReviewers; diff --git a/src/applications/metamta/adapter/PhabricatorMailImplementationPHPMailerLiteAdapter.php b/src/applications/metamta/adapter/PhabricatorMailImplementationPHPMailerLiteAdapter.php index e758832039..2a8b12b64a 100644 --- a/src/applications/metamta/adapter/PhabricatorMailImplementationPHPMailerLiteAdapter.php +++ b/src/applications/metamta/adapter/PhabricatorMailImplementationPHPMailerLiteAdapter.php @@ -6,6 +6,8 @@ class PhabricatorMailImplementationPHPMailerLiteAdapter extends PhabricatorMailImplementationAdapter { + protected $mailer; + /** * @phutil-external-symbol class PHPMailerLite */ diff --git a/src/applications/releeph/view/branch/ReleephBranchTemplate.php b/src/applications/releeph/view/branch/ReleephBranchTemplate.php index 2441d924c1..d1564c55bb 100644 --- a/src/applications/releeph/view/branch/ReleephBranchTemplate.php +++ b/src/applications/releeph/view/branch/ReleephBranchTemplate.php @@ -4,6 +4,11 @@ final class ReleephBranchTemplate extends Phobject { const KEY = 'releeph.default-branch-template'; + private $commitHandle; + private $branchDate; + private $projectName; + private $isSymbolic; + public static function getDefaultTemplate() { return PhabricatorEnv::getEnvConfig(self::KEY); } From 5878500e1f5ec75b54aabe1ba561b88b2d30520c Mon Sep 17 00:00:00 2001 From: epriestley Date: Mon, 15 Jun 2015 06:29:51 -0700 Subject: [PATCH 47/50] Fix missing property on PhabricatorYoutubeRemarkupRule Fixes T8545. Auditors: joshuaspence --- .../markup/rule/PhabricatorYoutubeRemarkupRule.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/infrastructure/markup/rule/PhabricatorYoutubeRemarkupRule.php b/src/infrastructure/markup/rule/PhabricatorYoutubeRemarkupRule.php index 43af8d3f01..bad8e0eacf 100644 --- a/src/infrastructure/markup/rule/PhabricatorYoutubeRemarkupRule.php +++ b/src/infrastructure/markup/rule/PhabricatorYoutubeRemarkupRule.php @@ -2,6 +2,8 @@ final class PhabricatorYoutubeRemarkupRule extends PhutilRemarkupRule { + private $uri; + public function getPriority() { return 350.0; } From 069568757242356b7fea284d9335742ae4fd60c0 Mon Sep 17 00:00:00 2001 From: epriestley Date: Mon, 15 Jun 2015 06:36:42 -0700 Subject: [PATCH 48/50] Fix an undefined property on HarbormasterBuildLogQuery Fixes T8546. Auditors: joshuaspence --- .../harbormaster/query/HarbormasterBuildLogQuery.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/applications/harbormaster/query/HarbormasterBuildLogQuery.php b/src/applications/harbormaster/query/HarbormasterBuildLogQuery.php index f0f2021fd8..3d45de686f 100644 --- a/src/applications/harbormaster/query/HarbormasterBuildLogQuery.php +++ b/src/applications/harbormaster/query/HarbormasterBuildLogQuery.php @@ -6,6 +6,7 @@ final class HarbormasterBuildLogQuery private $ids; private $phids; private $buildPHIDs; + private $buildTargetPHIDs; public function withIDs(array $ids) { $this->ids = $ids; From 0fd0f171f10f1573166f40301c281baa88f3cc35 Mon Sep 17 00:00:00 2001 From: epriestley Date: Mon, 15 Jun 2015 07:05:03 -0700 Subject: [PATCH 49/50] Fix an undeclared property on AphrontPlainTextResponse Auditors: joshuaspence --- src/aphront/response/AphrontPlainTextResponse.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/aphront/response/AphrontPlainTextResponse.php b/src/aphront/response/AphrontPlainTextResponse.php index a14b7367e9..d8289ab2f9 100644 --- a/src/aphront/response/AphrontPlainTextResponse.php +++ b/src/aphront/response/AphrontPlainTextResponse.php @@ -2,6 +2,8 @@ final class AphrontPlainTextResponse extends AphrontResponse { + private $content; + public function setContent($content) { $this->content = $content; return $this; From f87ffc41ce697929908a8710436c7c556bae3c60 Mon Sep 17 00:00:00 2001 From: Joshua Spence Date: Mon, 15 Jun 2015 07:54:12 -0700 Subject: [PATCH 50/50] Fix another undeclared property Summary: I think that I've caught the bulk of these issues now. Test Plan: Eyeball it. Reviewers: #blessed_reviewers, epriestley Reviewed By: #blessed_reviewers, epriestley Subscribers: epriestley, Korvin Differential Revision: https://secure.phabricator.com/D13296 --- .../drydock/util/DrydockBlueprintScopeGuard.php | 2 ++ .../releeph/view/branch/ReleephBranchTemplate.php | 7 +------ 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/applications/drydock/util/DrydockBlueprintScopeGuard.php b/src/applications/drydock/util/DrydockBlueprintScopeGuard.php index 6f4564789c..343428683b 100644 --- a/src/applications/drydock/util/DrydockBlueprintScopeGuard.php +++ b/src/applications/drydock/util/DrydockBlueprintScopeGuard.php @@ -2,6 +2,8 @@ final class DrydockBlueprintScopeGuard extends Phobject { + private $blueprint; + public function __construct(DrydockBlueprintImplementation $blueprint) { $this->blueprint = $blueprint; } diff --git a/src/applications/releeph/view/branch/ReleephBranchTemplate.php b/src/applications/releeph/view/branch/ReleephBranchTemplate.php index d1564c55bb..f29e7a9fc2 100644 --- a/src/applications/releeph/view/branch/ReleephBranchTemplate.php +++ b/src/applications/releeph/view/branch/ReleephBranchTemplate.php @@ -5,7 +5,7 @@ final class ReleephBranchTemplate extends Phobject { const KEY = 'releeph.default-branch-template'; private $commitHandle; - private $branchDate; + private $branchDate = null; private $projectName; private $isSymbolic; @@ -41,11 +41,6 @@ final class ReleephBranchTemplate extends Phobject { return $fake_handle; } - private $commitHandle; - private $branchDate = null; - private $projectName; - private $isSymbolic; - public function setCommitHandle(PhabricatorObjectHandle $handle) { $this->commitHandle = $handle; return $this;