Page MenuHomePhabricator

D20724.diff
No OneTemporary

D20724.diff

diff --git a/bin/people b/bin/people
deleted file mode 120000
--- a/bin/people
+++ /dev/null
@@ -1 +0,0 @@
-../scripts/people/manage_people.php
\ No newline at end of file
diff --git a/bin/user b/bin/user
new file mode 120000
--- /dev/null
+++ b/bin/user
@@ -0,0 +1 @@
+../scripts/setup/manage_user.php
\ No newline at end of file
diff --git a/scripts/people/manage_people.php b/scripts/setup/manage_user.php
rename from scripts/people/manage_people.php
rename to scripts/setup/manage_user.php
--- a/scripts/people/manage_people.php
+++ b/scripts/setup/manage_user.php
@@ -6,8 +6,8 @@
$args = new PhutilArgumentParser($argv);
$args->setSynopsis(<<<EOSYNOPSIS
-**people** __command__ [__options__]
- Manage user profiles and accounts.
+**user** __command__ [__options__]
+ Modify user accounts to regain access to an install.
EOSYNOPSIS
);
diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -4051,6 +4051,8 @@
'PhabricatorPeopleMailEngine' => 'applications/people/mail/PhabricatorPeopleMailEngine.php',
'PhabricatorPeopleMailEngineException' => 'applications/people/mail/PhabricatorPeopleMailEngineException.php',
'PhabricatorPeopleManageProfileMenuItem' => 'applications/people/menuitem/PhabricatorPeopleManageProfileMenuItem.php',
+ 'PhabricatorPeopleManagementEmpowerWorkflow' => 'applications/people/management/PhabricatorPeopleManagementEmpowerWorkflow.php',
+ 'PhabricatorPeopleManagementEnableWorkflow' => 'applications/people/management/PhabricatorPeopleManagementEnableWorkflow.php',
'PhabricatorPeopleManagementWorkflow' => 'applications/people/management/PhabricatorPeopleManagementWorkflow.php',
'PhabricatorPeopleNewController' => 'applications/people/controller/PhabricatorPeopleNewController.php',
'PhabricatorPeopleNoOwnerDatasource' => 'applications/people/typeahead/PhabricatorPeopleNoOwnerDatasource.php',
@@ -4060,7 +4062,6 @@
'PhabricatorPeopleProfileCommitsController' => 'applications/people/controller/PhabricatorPeopleProfileCommitsController.php',
'PhabricatorPeopleProfileController' => 'applications/people/controller/PhabricatorPeopleProfileController.php',
'PhabricatorPeopleProfileEditController' => 'applications/people/controller/PhabricatorPeopleProfileEditController.php',
- 'PhabricatorPeopleProfileImageWorkflow' => 'applications/people/management/PhabricatorPeopleProfileImageWorkflow.php',
'PhabricatorPeopleProfileManageController' => 'applications/people/controller/PhabricatorPeopleProfileManageController.php',
'PhabricatorPeopleProfileMenuEngine' => 'applications/people/engine/PhabricatorPeopleProfileMenuEngine.php',
'PhabricatorPeopleProfilePictureController' => 'applications/people/controller/PhabricatorPeopleProfilePictureController.php',
@@ -10332,6 +10333,8 @@
'PhabricatorPeopleMailEngine' => 'Phobject',
'PhabricatorPeopleMailEngineException' => 'Exception',
'PhabricatorPeopleManageProfileMenuItem' => 'PhabricatorProfileMenuItem',
+ 'PhabricatorPeopleManagementEmpowerWorkflow' => 'PhabricatorPeopleManagementWorkflow',
+ 'PhabricatorPeopleManagementEnableWorkflow' => 'PhabricatorPeopleManagementWorkflow',
'PhabricatorPeopleManagementWorkflow' => 'PhabricatorManagementWorkflow',
'PhabricatorPeopleNewController' => 'PhabricatorPeopleController',
'PhabricatorPeopleNoOwnerDatasource' => 'PhabricatorTypeaheadDatasource',
@@ -10341,7 +10344,6 @@
'PhabricatorPeopleProfileCommitsController' => 'PhabricatorPeopleProfileController',
'PhabricatorPeopleProfileController' => 'PhabricatorPeopleController',
'PhabricatorPeopleProfileEditController' => 'PhabricatorPeopleProfileController',
- 'PhabricatorPeopleProfileImageWorkflow' => 'PhabricatorPeopleManagementWorkflow',
'PhabricatorPeopleProfileManageController' => 'PhabricatorPeopleProfileController',
'PhabricatorPeopleProfileMenuEngine' => 'PhabricatorProfileMenuEngine',
'PhabricatorPeopleProfilePictureController' => 'PhabricatorPeopleProfileController',
diff --git a/src/applications/people/management/PhabricatorPeopleManagementEmpowerWorkflow.php b/src/applications/people/management/PhabricatorPeopleManagementEmpowerWorkflow.php
new file mode 100644
--- /dev/null
+++ b/src/applications/people/management/PhabricatorPeopleManagementEmpowerWorkflow.php
@@ -0,0 +1,44 @@
+<?php
+
+final class PhabricatorPeopleManagementEmpowerWorkflow
+ extends PhabricatorPeopleManagementWorkflow {
+
+ protected function didConstruct() {
+ $arguments = array_merge(
+ $this->getUserSelectionArguments(),
+ array());
+
+ $this
+ ->setName('empower')
+ ->setExamples('**empower** --user __username__')
+ ->setSynopsis(pht('Turn a user account into an administrator account.'))
+ ->setArguments($arguments);
+ }
+
+ public function execute(PhutilArgumentParser $args) {
+ $user = $this->selectUser($args);
+ $display_name = $user->getUsername();
+
+ if ($user->getIsAdmin()) {
+ throw new PhutilArgumentUsageException(
+ pht(
+ 'User account "%s" is already an administrator. You can only '.
+ 'empower accounts that are not yet administrators.',
+ $display_name));
+ }
+
+ $xactions = array();
+ $xactions[] = $user->getApplicationTransactionTemplate()
+ ->setTransactionType(PhabricatorUserEmpowerTransaction::TRANSACTIONTYPE)
+ ->setNewValue(true);
+
+ $this->applyTransactions($user, $xactions);
+
+ $this->logOkay(
+ pht('DONE'),
+ pht('Empowered user account "%s".', $display_name));
+
+ return 0;
+ }
+
+}
diff --git a/src/applications/people/management/PhabricatorPeopleManagementEnableWorkflow.php b/src/applications/people/management/PhabricatorPeopleManagementEnableWorkflow.php
new file mode 100644
--- /dev/null
+++ b/src/applications/people/management/PhabricatorPeopleManagementEnableWorkflow.php
@@ -0,0 +1,44 @@
+<?php
+
+final class PhabricatorPeopleManagementEnableWorkflow
+ extends PhabricatorPeopleManagementWorkflow {
+
+ protected function didConstruct() {
+ $arguments = array_merge(
+ $this->getUserSelectionArguments(),
+ array());
+
+ $this
+ ->setName('enable')
+ ->setExamples('**enable** --user __username__')
+ ->setSynopsis(pht('Enable a disabled user account.'))
+ ->setArguments($arguments);
+ }
+
+ public function execute(PhutilArgumentParser $args) {
+ $user = $this->selectUser($args);
+ $display_name = $user->getUsername();
+
+ if (!$user->getIsDisabled()) {
+ throw new PhutilArgumentUsageException(
+ pht(
+ 'User account "%s" is not disabled. You can only enable accounts '.
+ 'that are disabled.',
+ $display_name));
+ }
+
+ $xactions = array();
+ $xactions[] = $user->getApplicationTransactionTemplate()
+ ->setTransactionType(PhabricatorUserDisableTransaction::TRANSACTIONTYPE)
+ ->setNewValue(false);
+
+ $this->applyTransactions($user, $xactions);
+
+ $this->logOkay(
+ pht('DONE'),
+ pht('Enabled user account "%s".', $display_name));
+
+ return 0;
+ }
+
+}
diff --git a/src/applications/people/management/PhabricatorPeopleManagementWorkflow.php b/src/applications/people/management/PhabricatorPeopleManagementWorkflow.php
--- a/src/applications/people/management/PhabricatorPeopleManagementWorkflow.php
+++ b/src/applications/people/management/PhabricatorPeopleManagementWorkflow.php
@@ -3,45 +3,55 @@
abstract class PhabricatorPeopleManagementWorkflow
extends PhabricatorManagementWorkflow {
- protected function buildIterator(PhutilArgumentParser $args) {
- $usernames = $args->getArg('users');
-
- if ($args->getArg('all')) {
- if ($usernames) {
- throw new PhutilArgumentUsageException(
- pht(
- 'Specify either a list of users or `%s`, but not both.',
- '--all'));
- }
- return new LiskMigrationIterator(new PhabricatorUser());
+ final protected function getUserSelectionArguments() {
+ return array(
+ array(
+ 'name' => 'user',
+ 'param' => 'username',
+ 'help' => pht('User account to act on.'),
+ ),
+ );
+ }
+
+ final protected function selectUser(PhutilArgumentParser $argv) {
+ $username = $argv->getArg('user');
+
+ if (!strlen($username)) {
+ throw new PhutilArgumentUsageException(
+ pht(
+ 'Select a user account to act on with "--user <username>".'));
}
- if ($usernames) {
- return $this->loadUsersWithUsernames($usernames);
+ $user = id(new PhabricatorPeopleQuery())
+ ->setViewer($this->getViewer())
+ ->withUsernames(array($username))
+ ->executeOne();
+ if (!$user) {
+ throw new PhutilArgumentUsageException(
+ pht(
+ 'No user with username "%s" exists.',
+ $username));
}
- return null;
+ return $user;
}
- protected function loadUsersWithUsernames(array $usernames) {
- $users = array();
- foreach($usernames as $username) {
- $query = id(new PhabricatorPeopleQuery())
- ->setViewer($this->getViewer())
- ->withUsernames(array($username))
- ->executeOne();
-
- if (!$query) {
- throw new PhutilArgumentUsageException(
- pht(
- '"%s" is not a valid username.',
- $username));
- }
- $users[] = $query;
- }
+ final protected function applyTransactions(
+ PhabricatorUser $user,
+ array $xactions) {
+ assert_instances_of($xactions, 'PhabricatorUserTransaction');
- return $users;
- }
+ $viewer = $this->getViewer();
+ $application = id(new PhabricatorPeopleApplication())->getPHID();
+ $content_source = $this->newContentSource();
+
+ $editor = $user->getApplicationTransactionEditor()
+ ->setActor($viewer)
+ ->setActingAsPHID($application)
+ ->setContentSource($content_source)
+ ->setContinueOnMissingFields(true);
+ return $editor->applyTransactions($user, $xactions);
+ }
}
diff --git a/src/applications/people/management/PhabricatorPeopleProfileImageWorkflow.php b/src/applications/people/management/PhabricatorPeopleProfileImageWorkflow.php
deleted file mode 100644
--- a/src/applications/people/management/PhabricatorPeopleProfileImageWorkflow.php
+++ /dev/null
@@ -1,85 +0,0 @@
-<?php
-
-final class PhabricatorPeopleProfileImageWorkflow
- extends PhabricatorPeopleManagementWorkflow {
-
- protected function didConstruct() {
- $this
- ->setName('profileimage')
- ->setExamples('**profileimage** --users __username__')
- ->setSynopsis(pht('Generate default profile images.'))
- ->setArguments(
- array(
- array(
- 'name' => 'all',
- 'help' => pht(
- 'Generate default profile images for all users.'),
- ),
- array(
- 'name' => 'force',
- 'short' => 'f',
- 'help' => pht(
- 'Force a default profile image to be replaced.'),
- ),
- array(
- 'name' => 'users',
- 'wildcard' => true,
- ),
- ));
- }
-
- public function execute(PhutilArgumentParser $args) {
- $console = PhutilConsole::getConsole();
-
- $is_force = $args->getArg('force');
- $is_all = $args->getArg('all');
-
- $gd = function_exists('imagecreatefromstring');
- if (!$gd) {
- throw new PhutilArgumentUsageException(
- pht(
- 'GD is not installed for php-cli. Aborting.'));
- }
-
- $iterator = $this->buildIterator($args);
- if (!$iterator) {
- throw new PhutilArgumentUsageException(
- pht(
- 'Either specify a list of users to update, or use `%s` '.
- 'to update all users.',
- '--all'));
- }
-
- $version = PhabricatorFilesComposeAvatarBuiltinFile::VERSION;
- $generator = new PhabricatorFilesComposeAvatarBuiltinFile();
-
- foreach ($iterator as $user) {
- $username = $user->getUsername();
- $default_phid = $user->getDefaultProfileImagePHID();
- $gen_version = $user->getDefaultProfileImageVersion();
-
- $generate = false;
- if ($gen_version != $version) {
- $generate = true;
- }
-
- if ($default_phid == null || $is_force || $generate) {
- $console->writeOut(
- "%s\n",
- pht(
- 'Generating profile image for "%s".',
- $username));
-
- $generator->updateUser($user);
- } else {
- $console->writeOut(
- "%s\n",
- pht(
- 'Default profile image "%s" already set for "%s".',
- $version,
- $username));
- }
- }
- }
-
-}
diff --git a/src/docs/user/userguide/unlocking.diviner b/src/docs/user/userguide/unlocking.diviner
new file mode 100644
--- /dev/null
+++ b/src/docs/user/userguide/unlocking.diviner
@@ -0,0 +1,116 @@
+@title User Guide: Unlocking Objects
+@group userguide
+
+Explains how to access locked or invisible objects and accounts.
+
+Overview
+========
+
+Phabricator tries to make it difficult for users to lock themselves out of
+things, but you can occasionally end up in situations where no one has access
+to an object that you need access to.
+
+For example, sometimes the only user who had edit permission for something has
+left the organization, or you configured a "Phase of the Moon" policy rule and
+the stars aren't currently aligned.
+
+You can use various CLI tools to unlock objects and accounts if you need to
+regain access.
+
+
+Unlocking Accounts
+==================
+
+If you need to regain access to an object, the easiest approach is usually to
+recover access to the account which owns it, then change the object policies
+to be more open using the web UI.
+
+For example, if an important task was accidentally locked so that only a user
+who is currently on vacation can edit it, you can log in as that user and
+change the edit policy to something more permissive.
+
+To regain access to an account:
+
+```
+$ ./bin/auth recover <username>
+```
+
+If the account you're recovering access to has MFA or other session prompts,
+use the `--force-full-session` to bypass them:
+
+```
+$ ./bin/auth recover <username> --force-full-session
+```
+
+In either case, the command will give you a link you a one-time link you can
+use to access the account from the web UI. From there, you can open up objects
+or change settings.
+
+
+Unlocking MFA
+=============
+
+You can completely strip MFA from a user account with:
+
+```
+$ ./bin/auth strip --user <username> ...
+```
+
+For detailed help on managing and stripping MFA, see the instructions in
+@{article:User Guide: Multi-Factor Authentication}
+
+
+Unlocking Objects
+=================
+
+If you aren't sure who owns an object, or no user account has access to an
+object, you can directly change object policies from the CLI:
+
+```
+$ ./bin/policy unlock <object> [--view ...] [--edit ...] [--owner ...]
+```
+
+To identify the object you want to unlock, you can specify an object name (like
+`T123`) or a PHID as the `<object>` parameter.
+
+Use the `--view` and `--edit` flags (and, for some objects, the `--owner`
+flag) to specify new policies for the object.
+
+For example, to make task `T123` editable by user `@alice`, run:
+
+```
+$ ./bin/policy unlock T123 --edit alice
+```
+
+Not every object has mutable view and edit policies, and not every object has
+an owner, so each flag only works on some types of objects.
+
+From here, you can log in to the web UI and change the relevant policies to
+whatever you want to set them to.
+
+
+No Enabled Users
+================
+
+If you accidentally disabled all administrator accounts, you can enable a
+disabled account from the CLI like this:
+
+```
+$ ./bin/user enable --user <username>
+```
+
+From here, recover the account or log in normally.
+
+
+No Administrators
+=================
+
+If you accidentally deleted all the administrator accounts, you can empower
+a user as an administrator from the CLI like this:
+
+```
+$ ./bin/user empower --user <username>
+```
+
+This will upgrade the user account from a regular account to an administrator
+account.

File Metadata

Mime Type
text/plain
Expires
Mon, Mar 31, 5:18 PM (1 w, 2 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7227837
Default Alt Text
D20724.diff (15 KB)

Event Timeline