Support invites in the registration and login flow
Summary:
Ref T7152. This substantially completes the upstream login flow. Basically, we just cookie you and push you through normal registration, with slight changes:
- All providers allow registration if you have an invite.
- Most providers get minor text changes to say "Register" instead of "Login" or "Login or Register".
- The Username/Password provider changes to just a "choose a username" form.
- We show the user that they're accepting an invite, and who invited them.
Then on actual registration:
- Accepting an invite auto-verifies the address.
- Accepting an invite auto-approves the account.
- Your email is set to the invite email and locked.
- Invites get to reassign nonprimary, unverified addresses from other accounts.
But 98% of the code is the same.
Test Plan:
- Accepted an invite.
- Verified a new address on an existing account via invite.
- Followed a bad invite link.
- Tried to accept a verified invite.
- Reassigned an email by accepting an unverified, nonprimary invite on a new account.
- Verified that reassigns appear in the activity log.
{F291493}
{F291494}
{F291495}
{F291496}
{F291497}
{F291498}
{F291499}
Reviewers: btrahan
Reviewed By: btrahan
Subscribers: epriestley
Maniphest Tasks: T7152
Differential Revision: https://secure.phabricator.com/D11737
This commit is contained in:
@@ -108,6 +108,9 @@ abstract class PhabricatorAuthController extends PhabricatorController {
|
||||
|
||||
// Clear the client ID / OAuth state key.
|
||||
$request->clearCookie(PhabricatorCookies::COOKIE_CLIENTID);
|
||||
|
||||
// Clear the invite cookie.
|
||||
$request->clearCookie(PhabricatorCookies::COOKIE_INVITE);
|
||||
}
|
||||
|
||||
private function buildLoginValidateResponse(PhabricatorUser $user) {
|
||||
@@ -246,4 +249,57 @@ abstract class PhabricatorAuthController extends PhabricatorController {
|
||||
return array($account, $provider, null);
|
||||
}
|
||||
|
||||
protected function loadInvite() {
|
||||
$invite_cookie = PhabricatorCookies::COOKIE_INVITE;
|
||||
$invite_code = $this->getRequest()->getCookie($invite_cookie);
|
||||
if (!$invite_code) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$engine = id(new PhabricatorAuthInviteEngine())
|
||||
->setViewer($this->getViewer())
|
||||
->setUserHasConfirmedVerify(true);
|
||||
|
||||
try {
|
||||
return $engine->processInviteCode($invite_code);
|
||||
} catch (Exception $ex) {
|
||||
// If this fails for any reason, just drop the invite. In normal
|
||||
// circumstances, we gave them a detailed explanation of any error
|
||||
// before they jumped into this workflow.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
protected function renderInviteHeader(PhabricatorAuthInvite $invite) {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$invite_author = id(new PhabricatorPeopleQuery())
|
||||
->setViewer($viewer)
|
||||
->withPHIDs(array($invite->getAuthorPHID()))
|
||||
->needProfileImage(true)
|
||||
->executeOne();
|
||||
|
||||
// If we can't load the author for some reason, just drop this message.
|
||||
// We lose the value of contextualizing things without author details.
|
||||
if (!$invite_author) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$invite_item = id(new PHUIObjectItemView())
|
||||
->setHeader(pht('Welcome to Phabricator!'))
|
||||
->setImageURI($invite_author->getProfileImageURI())
|
||||
->addAttribute(
|
||||
pht(
|
||||
'%s has invited you to join Phabricator.',
|
||||
$invite_author->getFullName()));
|
||||
|
||||
$invite_list = id(new PHUIObjectItemListView())
|
||||
->addItem($invite_item)
|
||||
->setFlush(true);
|
||||
|
||||
return id(new PHUIBoxView())
|
||||
->addMargin(PHUI::MARGIN_LARGE)
|
||||
->appendChild($invite_list);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user