mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-26 08:42:41 +01:00
Implement an approval queue
Summary: - Add an option for the queue. - By default, enable it. - Dump new users into the queue. - Send admins an email to approve them. Test Plan: - Registered new accounts with queue on and off. - As an admin, approved accounts and disabled the queue from email. Reviewers: btrahan Reviewed By: btrahan CC: aran Differential Revision: https://secure.phabricator.com/D7576
This commit is contained in:
parent
0fa411083f
commit
c0e1a63a63
8 changed files with 101 additions and 16 deletions
|
@ -181,6 +181,7 @@ $user->openTransaction();
|
||||||
$editor->createNewUser($user, $email);
|
$editor->createNewUser($user, $email);
|
||||||
} else {
|
} else {
|
||||||
if ($verify_email) {
|
if ($verify_email) {
|
||||||
|
$user->setIsEmailVerified(1);
|
||||||
$verify_email->setIsVerified($set_verified ? 1 : 0);
|
$verify_email->setIsVerified($set_verified ? 1 : 0);
|
||||||
}
|
}
|
||||||
$editor->updateUser($user, $verify_email);
|
$editor->updateUser($user, $verify_email);
|
||||||
|
|
|
@ -42,6 +42,7 @@ if ($existing_email) {
|
||||||
$user = new PhabricatorUser();
|
$user = new PhabricatorUser();
|
||||||
$user->setUsername($username);
|
$user->setUsername($username);
|
||||||
$user->setRealname($realname);
|
$user->setRealname($realname);
|
||||||
|
$user->setIsApproved(1);
|
||||||
|
|
||||||
$email_object = id(new PhabricatorUserEmail())
|
$email_object = id(new PhabricatorUserEmail())
|
||||||
->setAddress($email)
|
->setAddress($email)
|
||||||
|
|
|
@ -232,6 +232,19 @@ final class PhabricatorAuthRegisterController
|
||||||
$user->setUsername($value_username);
|
$user->setUsername($value_username);
|
||||||
$user->setRealname($value_realname);
|
$user->setRealname($value_realname);
|
||||||
|
|
||||||
|
if ($is_setup) {
|
||||||
|
$must_approve = false;
|
||||||
|
} else {
|
||||||
|
$must_approve = PhabricatorEnv::getEnvConfig(
|
||||||
|
'auth.require-approval');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($must_approve) {
|
||||||
|
$user->setIsApproved(0);
|
||||||
|
} else {
|
||||||
|
$user->setIsApproved(1);
|
||||||
|
}
|
||||||
|
|
||||||
$user->openTransaction();
|
$user->openTransaction();
|
||||||
|
|
||||||
$editor = id(new PhabricatorUserEditor())
|
$editor = id(new PhabricatorUserEditor())
|
||||||
|
@ -257,6 +270,10 @@ final class PhabricatorAuthRegisterController
|
||||||
$email_obj->sendVerificationEmail($user);
|
$email_obj->sendVerificationEmail($user);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($must_approve) {
|
||||||
|
$this->sendWaitingForApprovalEmail($user);
|
||||||
|
}
|
||||||
|
|
||||||
return $this->loginUser($user);
|
return $this->loginUser($user);
|
||||||
} catch (AphrontQueryDuplicateKeyException $exception) {
|
} catch (AphrontQueryDuplicateKeyException $exception) {
|
||||||
$same_username = id(new PhabricatorUser())->loadOneWhere(
|
$same_username = id(new PhabricatorUser())->loadOneWhere(
|
||||||
|
@ -506,4 +523,43 @@ final class PhabricatorAuthRegisterController
|
||||||
array($message));
|
array($message));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function sendWaitingForApprovalEmail(PhabricatorUser $user) {
|
||||||
|
$title = '[Phabricator] '.pht(
|
||||||
|
'New User "%s" Awaiting Approval',
|
||||||
|
$user->getUsername());
|
||||||
|
|
||||||
|
$body = new PhabricatorMetaMTAMailBody();
|
||||||
|
|
||||||
|
$body->addRawSection(
|
||||||
|
pht(
|
||||||
|
'Newly registered user "%s" is awaiting account approval by an '.
|
||||||
|
'administrator.',
|
||||||
|
$user->getUsername()));
|
||||||
|
|
||||||
|
$body->addTextSection(
|
||||||
|
pht('APPROVAL QUEUE'),
|
||||||
|
PhabricatorEnv::getProductionURI(
|
||||||
|
'/people/query/approval/'));
|
||||||
|
|
||||||
|
$body->addTextSection(
|
||||||
|
pht('DISABLE APPROVAL QUEUE'),
|
||||||
|
PhabricatorEnv::getProductionURI(
|
||||||
|
'/config/edit/auth.require-approval/'));
|
||||||
|
|
||||||
|
$admins = id(new PhabricatorPeopleQuery())
|
||||||
|
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||||
|
->withIsAdmin(true)
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
if (!$admins) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$mail = id(new PhabricatorMetaMTAMail())
|
||||||
|
->addTos(mpull($admins, 'getPHID'))
|
||||||
|
->setSubject($title)
|
||||||
|
->setBody($body->render())
|
||||||
|
->saveAndSend();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -490,7 +490,7 @@ final class PhabricatorConfigEditController
|
||||||
|
|
||||||
$table[] = phutil_tag('tr', array(), array(
|
$table[] = phutil_tag('tr', array(), array(
|
||||||
phutil_tag('th', array(), $description),
|
phutil_tag('th', array(), $description),
|
||||||
phutil_tag('th', array(), $value),
|
phutil_tag('td', array(), $value),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ final class PhabricatorAuthenticationConfigOptions
|
||||||
"Maximum number of simultaneous web sessions each user is ".
|
"Maximum number of simultaneous web sessions each user is ".
|
||||||
"permitted to have. Setting this to '1' will prevent a user from ".
|
"permitted to have. Setting this to '1' will prevent a user from ".
|
||||||
"logging in on more than one browser at the same time.")),
|
"logging in on more than one browser at the same time.")),
|
||||||
$this->newOption('auth.sessions.conduit', 'int', 5)
|
$this->newOption('auth.sessions.conduit', 'int', 5)
|
||||||
->setSummary(
|
->setSummary(
|
||||||
pht(
|
pht(
|
||||||
"Number of simultaneous Conduit sessions each user is permitted."))
|
"Number of simultaneous Conduit sessions each user is permitted."))
|
||||||
|
@ -29,7 +29,7 @@ final class PhabricatorAuthenticationConfigOptions
|
||||||
pht(
|
pht(
|
||||||
"Maximum number of simultaneous Conduit sessions each user is ".
|
"Maximum number of simultaneous Conduit sessions each user is ".
|
||||||
"permitted to have.")),
|
"permitted to have.")),
|
||||||
$this->newOption('auth.require-email-verification', 'bool', false)
|
$this->newOption('auth.require-email-verification', 'bool', false)
|
||||||
->setBoolOptions(
|
->setBoolOptions(
|
||||||
array(
|
array(
|
||||||
pht("Require email verification"),
|
pht("Require email verification"),
|
||||||
|
@ -41,24 +41,47 @@ final class PhabricatorAuthenticationConfigOptions
|
||||||
pht(
|
pht(
|
||||||
"If true, email addresses must be verified (by clicking a link ".
|
"If true, email addresses must be verified (by clicking a link ".
|
||||||
"in an email) before a user can login. By default, verification ".
|
"in an email) before a user can login. By default, verification ".
|
||||||
"is optional unless 'auth.email-domains' is nonempty.")),
|
"is optional unless {{auth.email-domains}} is nonempty.")),
|
||||||
$this->newOption('auth.email-domains', 'list<string>', array())
|
$this->newOption('auth.require-approval', 'bool', true)
|
||||||
|
->setBoolOptions(
|
||||||
|
array(
|
||||||
|
pht("Require Administrators to Approve Accounts"),
|
||||||
|
pht("Don't Require Manual Approval"),
|
||||||
|
))
|
||||||
|
->setSummary(
|
||||||
|
pht("Require administrators to approve new accounts."))
|
||||||
|
->setDescription(
|
||||||
|
pht(
|
||||||
|
"Newly registered Phabricator accounts can either be placed ".
|
||||||
|
"into a manual approval queue for administrative review, or ".
|
||||||
|
"automatically activated immediately. The approval queue is ".
|
||||||
|
"enabled by default because it gives you greater control over ".
|
||||||
|
"who can register an account and access Phabricator.\n\n".
|
||||||
|
"If your install is completely public, or on a VPN, or users can ".
|
||||||
|
"only register with a trusted provider like LDAP, or you've ".
|
||||||
|
"otherwise configured Phabricator to prevent unauthorized ".
|
||||||
|
"registration, you can disable the queue to reduce administrative ".
|
||||||
|
"overhead.\n\n".
|
||||||
|
"NOTE: Before you disable the queue, make sure ".
|
||||||
|
"{{auth.email-domains}} is configured correctly for your ".
|
||||||
|
"install!")),
|
||||||
|
$this->newOption('auth.email-domains', 'list<string>', array())
|
||||||
->setSummary(pht("Only allow registration from particular domains."))
|
->setSummary(pht("Only allow registration from particular domains."))
|
||||||
->setDescription(
|
->setDescription(
|
||||||
pht(
|
pht(
|
||||||
"You can restrict allowed email addresses to certain domains ".
|
"You can restrict allowed email addresses to certain domains ".
|
||||||
"(like 'yourcompany.com') by setting a list of allowed domains ".
|
"(like `yourcompany.com`) by setting a list of allowed domains ".
|
||||||
"here. Users will only be allowed to register using email ".
|
"here.\n\nUsers will only be allowed to register using email ".
|
||||||
"addresses at one of the domains, and will only be able to add ".
|
"addresses at one of the domains, and will only be able to add ".
|
||||||
"new email addresses for these domains. If you configure this, ".
|
"new email addresses for these domains. If you configure this, ".
|
||||||
"it implies 'auth.require-email-verification'.\n\n".
|
"it implies {{auth.require-email-verification}}.\n\n".
|
||||||
"You should omit the '@' from domains. Note that the domain must ".
|
"You should omit the `@` from domains. Note that the domain must ".
|
||||||
"match exactly. If you allow 'yourcompany.com', that permits ".
|
"match exactly. If you allow `yourcompany.com`, that permits ".
|
||||||
"'joe@yourcompany.com' but rejects 'joe@mail.yourcompany.com'."))
|
"`joe@yourcompany.com` but rejects `joe@mail.yourcompany.com`."))
|
||||||
->addExample(
|
->addExample(
|
||||||
"yourcompany.com\nmail.yourcompany.com",
|
"yourcompany.com\nmail.yourcompany.com",
|
||||||
pht('Valid Setting')),
|
pht('Valid Setting')),
|
||||||
$this->newOption('auth.login-message', 'string', null)
|
$this->newOption('auth.login-message', 'string', null)
|
||||||
->setLocked(true)
|
->setLocked(true)
|
||||||
->setSummary(pht("A block of HTML displayed on the login screen."))
|
->setSummary(pht("A block of HTML displayed on the login screen."))
|
||||||
->setDescription(
|
->setDescription(
|
||||||
|
@ -66,7 +89,7 @@ final class PhabricatorAuthenticationConfigOptions
|
||||||
"You can provide an arbitrary block of HTML here, which will ".
|
"You can provide an arbitrary block of HTML here, which will ".
|
||||||
"appear on the login screen. Normally, you'd use this to provide ".
|
"appear on the login screen. Normally, you'd use this to provide ".
|
||||||
"login or registration instructions to users.")),
|
"login or registration instructions to users.")),
|
||||||
$this->newOption('account.editable', 'bool', true)
|
$this->newOption('account.editable', 'bool', true)
|
||||||
->setBoolOptions(
|
->setBoolOptions(
|
||||||
array(
|
array(
|
||||||
pht("Allow editing"),
|
pht("Allow editing"),
|
||||||
|
@ -83,7 +106,7 @@ final class PhabricatorAuthenticationConfigOptions
|
||||||
"synchronize account information from some other authoritative ".
|
"synchronize account information from some other authoritative ".
|
||||||
"system, you can disable this to ensure information remains ".
|
"system, you can disable this to ensure information remains ".
|
||||||
"consistent across both systems.")),
|
"consistent across both systems.")),
|
||||||
$this->newOption('account.minimum-password-length', 'int', 8)
|
$this->newOption('account.minimum-password-length', 'int', 8)
|
||||||
->setSummary(pht("Minimum password length."))
|
->setSummary(pht("Minimum password length."))
|
||||||
->setDescription(
|
->setDescription(
|
||||||
pht(
|
pht(
|
||||||
|
|
|
@ -182,6 +182,9 @@ final class PhabricatorPeopleEditController
|
||||||
->setAddress($new_email)
|
->setAddress($new_email)
|
||||||
->setIsVerified(0);
|
->setIsVerified(0);
|
||||||
|
|
||||||
|
// Automatically approve the user, since an admin is creating them.
|
||||||
|
$user->setIsApproved(1);
|
||||||
|
|
||||||
id(new PhabricatorUserEditor())
|
id(new PhabricatorUserEditor())
|
||||||
->setActor($admin)
|
->setActor($admin)
|
||||||
->createNewUser($user, $email);
|
->createNewUser($user, $email);
|
||||||
|
|
|
@ -30,7 +30,7 @@ final class PhabricatorUser
|
||||||
protected $isAdmin = 0;
|
protected $isAdmin = 0;
|
||||||
protected $isDisabled = 0;
|
protected $isDisabled = 0;
|
||||||
protected $isEmailVerified = 0;
|
protected $isEmailVerified = 0;
|
||||||
protected $isApproved = 1;
|
protected $isApproved = 0;
|
||||||
|
|
||||||
private $profileImage = null;
|
private $profileImage = null;
|
||||||
private $profile = null;
|
private $profile = null;
|
||||||
|
|
|
@ -181,7 +181,8 @@ abstract class PhabricatorTestCase extends ArcanistPhutilTestCase {
|
||||||
|
|
||||||
$user = id(new PhabricatorUser())
|
$user = id(new PhabricatorUser())
|
||||||
->setRealName("Test User {$seed}}")
|
->setRealName("Test User {$seed}}")
|
||||||
->setUserName("test{$seed}");
|
->setUserName("test{$seed}")
|
||||||
|
->setIsApproved(1);
|
||||||
|
|
||||||
$email = id(new PhabricatorUserEmail())
|
$email = id(new PhabricatorUserEmail())
|
||||||
->setAddress("testuser{$seed}@example.com")
|
->setAddress("testuser{$seed}@example.com")
|
||||||
|
|
Loading…
Reference in a new issue