Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F15457584
D20724.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
15 KB
Referenced Files
None
Subscribers
None
D20724.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D20724: Replace "bin/people profileimage" with "bin/user enable|empower"
Attached
Detach File
Event Timeline
Log In to Comment