@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

New Registration Workflow

Summary:
Currently, registration and authentication are pretty messy. Two concrete problems:

- The `PhabricatorLDAPRegistrationController` and `PhabricatorOAuthDefaultRegistrationController` controllers are giant copy/pastes of one another. This is really bad.
- We can't practically implement OpenID because we can't reissue the authentication request.

Additionally, the OAuth registration controller can be replaced wholesale by config, which is a huge API surface area and a giant mess.

Broadly, the problem right now is that registration does too much: we hand it some set of indirect credentials (like OAuth tokens) and expect it to take those the entire way to a registered user. Instead, break registration into smaller steps:

- User authenticates with remote service.
- Phabricator pulls information (remote account ID, username, email, real name, profile picture, etc) from the remote service and saves it as `PhabricatorUserCredentials`.
- Phabricator hands the `PhabricatorUserCredentials` to the registration form, which is agnostic about where they originate from: it can process LDAP credentials, OAuth credentials, plain old email credentials, HTTP basic auth credentials, etc.

This doesn't do anything yet -- there is no way to create credentials objects (and no storage patch), but I wanted to get any initial feedback, especially about the event call for T2394. In particular, I think the implementation would look something like this:

$profile = $event->getValue('profile')

$username = $profile->getDefaultUsername();
$is_employee = is_this_a_facebook_employee($username);
if (!$is_employee) {
throw new Exception("You are not employed at Facebook.");
}

$fbid = get_fbid_for_facebook_username($username);
$profile->setDefaultEmail($fbid);

$profile->setCanEditUsername(false);
$profile->setCanEditEmail(false);
$profile->setCanEditRealName(false);
$profile->setShouldVerifyEmail(true);

Seem reasonable?

Test Plan: N/A yet, probably fatals.

Reviewers: vrana, btrahan, codeblock, chad

Reviewed By: btrahan

CC: aran, asherkin, nh, wez

Maniphest Tasks: T1536, T2394

Differential Revision: https://secure.phabricator.com/D4647

+616
+4
src/__phutil_library_map__.php
··· 815 815 'PhabricatorAuditReplyHandler' => 'applications/audit/mail/PhabricatorAuditReplyHandler.php', 816 816 'PhabricatorAuditStatusConstants' => 'applications/audit/constants/PhabricatorAuditStatusConstants.php', 817 817 'PhabricatorAuthController' => 'applications/auth/controller/PhabricatorAuthController.php', 818 + 'PhabricatorAuthRegisterController' => 'applications/auth/controller/PhabricatorAuthRegisterController.php', 818 819 'PhabricatorAuthenticationConfigOptions' => 'applications/config/option/PhabricatorAuthenticationConfigOptions.php', 819 820 'PhabricatorBarePageExample' => 'applications/uiexample/examples/PhabricatorBarePageExample.php', 820 821 'PhabricatorBarePageView' => 'view/page/PhabricatorBarePageView.php', ··· 1335 1336 'PhabricatorRecaptchaConfigOptions' => 'applications/config/option/PhabricatorRecaptchaConfigOptions.php', 1336 1337 'PhabricatorRedirectController' => 'applications/base/controller/PhabricatorRedirectController.php', 1337 1338 'PhabricatorRefreshCSRFController' => 'applications/auth/controller/PhabricatorRefreshCSRFController.php', 1339 + 'PhabricatorRegistrationProfile' => 'applications/people/storage/PhabricatorRegistrationProfile.php', 1338 1340 'PhabricatorRemarkupControl' => 'view/form/control/PhabricatorRemarkupControl.php', 1339 1341 'PhabricatorRemarkupRuleEmbedFile' => 'applications/files/remarkup/PhabricatorRemarkupRuleEmbedFile.php', 1340 1342 'PhabricatorRemarkupRuleImageMacro' => 'applications/macro/remarkup/PhabricatorRemarkupRuleImageMacro.php', ··· 2667 2669 'PhabricatorAuditPreviewController' => 'PhabricatorAuditController', 2668 2670 'PhabricatorAuditReplyHandler' => 'PhabricatorMailReplyHandler', 2669 2671 'PhabricatorAuthController' => 'PhabricatorController', 2672 + 'PhabricatorAuthRegisterController' => 'PhabricatorAuthController', 2670 2673 'PhabricatorAuthenticationConfigOptions' => 'PhabricatorApplicationConfigOptions', 2671 2674 'PhabricatorBarePageExample' => 'PhabricatorUIExample', 2672 2675 'PhabricatorBarePageView' => 'AphrontPageView', ··· 3182 3185 'PhabricatorRecaptchaConfigOptions' => 'PhabricatorApplicationConfigOptions', 3183 3186 'PhabricatorRedirectController' => 'PhabricatorController', 3184 3187 'PhabricatorRefreshCSRFController' => 'PhabricatorAuthController', 3188 + 'PhabricatorRegistrationProfile' => 'Phobject', 3185 3189 'PhabricatorRemarkupControl' => 'AphrontFormTextAreaControl', 3186 3190 'PhabricatorRemarkupRuleEmbedFile' => 'PhutilRemarkupRule', 3187 3191 'PhabricatorRemarkupRuleImageMacro' => 'PhutilRemarkupRule',
+8
src/applications/auth/application/PhabricatorApplicationAuth.php
··· 29 29 return $items; 30 30 } 31 31 32 + public function getRoutes() { 33 + return array( 34 + '/auth/' => array( 35 + 'register/(?P<akey>[^/]+)/' => 'PhabricatorAuthRegisterController', 36 + ), 37 + ); 38 + } 39 + 32 40 }
+35
src/applications/auth/controller/PhabricatorAuthController.php
··· 14 14 return $response->setContent($page->render()); 15 15 } 16 16 17 + protected function renderErrorPage($title, array $messages) { 18 + $view = new AphrontErrorView(); 19 + $view->setTitle($title); 20 + $view->setErrors($messages); 21 + 22 + return $this->buildApplicationPage( 23 + $view, 24 + array( 25 + 'title' => $title, 26 + 'device' => true, 27 + 'dust' => true, 28 + )); 29 + 30 + } 31 + 32 + protected function establishWebSession(PhabricatorUser $user) { 33 + $session_key = $user->establishSession('web'); 34 + 35 + $request = $this->getRequest(); 36 + 37 + // NOTE: We allow disabled users to login and roadblock them later, so 38 + // there's no check for users being disabled here. 39 + 40 + $request->setCookie('phusr', $user->getUsername()); 41 + $request->setCookie('phsid', $session_key); 42 + $request->clearCookie('phreg'); 43 + } 44 + 45 + protected function buildLoginValidateResponse(PhabricatorUser $user) { 46 + $validate_uri = new PhutilURI($this->getApplicationURI('validate/')); 47 + $validate_uri->setQueryParam('phusr', $user->getUsername()); 48 + 49 + return id(new AphrontRedirectResponse())->setURI((string)$validate_uri); 50 + } 51 + 17 52 }
+483
src/applications/auth/controller/PhabricatorAuthRegisterController.php
··· 1 + <?php 2 + 3 + final class PhabricatorAuthRegisterController 4 + extends PhabricatorAuthController { 5 + 6 + private $accountKey; 7 + private $account; 8 + private $provider; 9 + 10 + public function shouldRequireLogin() { 11 + return false; 12 + } 13 + 14 + public function willProcessRequest(array $data) { 15 + $this->accountKey = idx($data, 'akey'); 16 + } 17 + 18 + public function processRequest() { 19 + $request = $this->getRequest(); 20 + 21 + if ($request->getUser()->isLoggedIn()) { 22 + return $this->renderError(pht('You are already logged in.')); 23 + } 24 + 25 + if (strlen($this->accountKey)) { 26 + $response = $this->loadAccount(); 27 + } else { 28 + $response = $this->loadDefaultAccount(); 29 + } 30 + 31 + if ($response) { 32 + return $response; 33 + } 34 + 35 + $account = $this->account; 36 + 37 + $user = new PhabricatorUser(); 38 + 39 + $default_username = $account->getUsername(); 40 + $default_realname = $account->getRealName(); 41 + $default_email = $account->getEmail(); 42 + if ($default_email) { 43 + // If the account source provided an email but it's not allowed by 44 + // the configuration, just pretend we didn't get an email at all. 45 + if (!PhabricatorUserEmail::isAllowedAddress($default_email)) { 46 + $default_email = null; 47 + } 48 + 49 + // If the account source provided an email, but another account already 50 + // has that email, just pretend we didn't get an email. 51 + 52 + // TODO: See T3340. 53 + 54 + if ($default_email) { 55 + $same_email = id(new PhabricatorUserEmail())->loadOneWhere( 56 + 'address = %s', 57 + $default_email); 58 + if ($same_email) { 59 + $default_email = null; 60 + } 61 + } 62 + } 63 + 64 + $profile = id(new PhabricatorRegistrationProfile()) 65 + ->setDefaultUsername($default_username) 66 + ->setDefaultEmail($default_email) 67 + ->setDefaultRealName($default_realname) 68 + ->setCanEditUsername(true) 69 + ->setCanEditEmail(($default_email === null)) 70 + ->setCanEditRealName(true) 71 + ->setShouldVerifyEmail(false); 72 + 73 + $event_type = PhabricatorEventType::TYPE_AUTH_WILLREGISTERUSER; 74 + $event_data = array( 75 + 'account' => $account, 76 + 'profile' => $profile, 77 + ); 78 + 79 + $event = id(new PhabricatorEvent($event_type, $event_data)) 80 + ->setUser($user); 81 + PhutilEventEngine::dispatchEvent($event); 82 + 83 + $default_username = $profile->getDefaultUsername(); 84 + $default_email = $profile->getDefaultEmail(); 85 + $default_realname = $profile->getDefaultRealName(); 86 + 87 + $can_edit_username = $profile->getCanEditUsername(); 88 + $can_edit_email = $profile->getCanEditEmail(); 89 + $can_edit_realname = $profile->getCanEditRealName(); 90 + 91 + $must_set_password = $this->provider->shouldRequireRegistrationPassword(); 92 + 93 + $can_edit_anything = $profile->getCanEditAnything() || $must_set_password; 94 + $force_verify = $profile->getShouldVerifyEmail(); 95 + 96 + $value_username = $default_username; 97 + $value_realname = $default_realname; 98 + $value_email = $default_email; 99 + $value_password = null; 100 + 101 + $errors = array(); 102 + 103 + $e_username = strlen($value_username) ? null : true; 104 + $e_realname = strlen($value_realname) ? null : true; 105 + $e_email = strlen($value_email) ? null : true; 106 + $e_password = true; 107 + 108 + $min_len = PhabricatorEnv::getEnvConfig('account.minimum-password-length'); 109 + $min_len = (int)$min_len; 110 + 111 + if ($request->isFormPost() || !$can_edit_anything) { 112 + $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); 113 + 114 + if ($can_edit_username) { 115 + $value_username = $request->getStr('username'); 116 + if (!strlen($value_username)) { 117 + $e_username = pht('Required'); 118 + $errors[] = pht('Username is required.'); 119 + } else if (!PhabricatorUser::validateUsername($value_username)) { 120 + $e_username = pht('Invalid'); 121 + $errors[] = PhabricatorUser::describeValidUsername(); 122 + } else { 123 + $e_username = null; 124 + } 125 + } 126 + 127 + if ($must_set_password) { 128 + $value_password = $request->getStr('password'); 129 + $value_confirm = $request->getStr('confirm'); 130 + if (!strlen($value_password)) { 131 + $e_password = pht('Required'); 132 + $errors[] = pht('You must choose a password.'); 133 + } else if ($value_password !== $value_confirm) { 134 + $e_password = pht('No Match'); 135 + $errors[] = pht('Password and confirmation must match.'); 136 + } else if (strlen($value_password) < $min_len) { 137 + $e_password = pht('Too Short'); 138 + $errors[] = pht( 139 + 'Password is too short (must be at least %d characters long).', 140 + $min_len); 141 + } else { 142 + $e_password = null; 143 + } 144 + } 145 + 146 + if ($can_edit_email) { 147 + $value_email = $request->getStr('email'); 148 + if (!strlen($value_email)) { 149 + $e_email = pht('Required'); 150 + $errors[] = pht('Email is required.'); 151 + } else if (!PhabricatorUserEmail::isAllowedAddress($value_email)) { 152 + $e_email = pht('Invalid'); 153 + $errors[] = PhabricatorUserEmail::describeAllowedAddresses(); 154 + } else { 155 + $e_email = null; 156 + } 157 + } 158 + 159 + if ($can_edit_realname) { 160 + $value_realname = $request->getStr('realName'); 161 + if (!strlen($value_realname)) { 162 + $e_realname = pht('Required'); 163 + $errors[] = pht('Real name is required.'); 164 + } else { 165 + $e_realname = null; 166 + } 167 + } 168 + 169 + if (!$errors) { 170 + $image = $this->loadProfilePicture($account); 171 + if ($image) { 172 + $user->setProfileImagePHID($image->getPHID()); 173 + } 174 + 175 + try { 176 + if ($force_verify) { 177 + $verify_email = true; 178 + } else { 179 + $verify_email = 180 + ($account->getEmailVerified()) && 181 + ($value_email === $default_email); 182 + } 183 + 184 + $email_obj = id(new PhabricatorUserEmail()) 185 + ->setAddress($value_email) 186 + ->setIsVerified((int)$verify_email); 187 + 188 + $user->setUsername($value_username); 189 + $user->setRealname($value_realname); 190 + 191 + $user->openTransaction(); 192 + 193 + $editor = id(new PhabricatorUserEditor()) 194 + ->setActor($user); 195 + 196 + $editor->createNewUser($user, $email_obj); 197 + if ($must_set_password) { 198 + $envelope = new PhutilOpaqueEnvelope($value_password); 199 + $editor->changePassword($user, $envelope); 200 + } 201 + 202 + $account->setUserPHID($user->getPHID()); 203 + $this->provider->willRegisterAccount($account); 204 + $account->save(); 205 + 206 + $user->saveTransaction(); 207 + 208 + $this->establishWebSession($user); 209 + 210 + if (!$email_obj->getIsVerified()) { 211 + $email_obj->sendVerificationEmail($user); 212 + } 213 + 214 + return $this->buildLoginValidateResponse($user); 215 + } catch (AphrontQueryDuplicateKeyException $exception) { 216 + $same_username = id(new PhabricatorUser())->loadOneWhere( 217 + 'userName = %s', 218 + $user->getUserName()); 219 + 220 + $same_email = id(new PhabricatorUserEmail())->loadOneWhere( 221 + 'address = %s', 222 + $value_email); 223 + 224 + if ($same_username) { 225 + $e_username = pht('Duplicate'); 226 + $errors[] = pht('Another user already has that username.'); 227 + } 228 + 229 + if ($same_email) { 230 + // TODO: See T3340. 231 + $e_email = pht('Duplicate'); 232 + $errors[] = pht('Another user already has that email.'); 233 + } 234 + 235 + if (!$same_username && !$same_email) { 236 + throw $exception; 237 + } 238 + } 239 + } 240 + 241 + unset($unguarded); 242 + } 243 + 244 + $error_view = null; 245 + if ($errors) { 246 + $error_view = new AphrontErrorView(); 247 + $error_view->setTitle(pht('Registration Failed')); 248 + $error_view->setErrors($errors); 249 + } 250 + 251 + $form = id(new AphrontFormView()) 252 + ->setUser($request->getUser()) 253 + ->appendChild( 254 + id(new AphrontFormTextControl()) 255 + ->setLabel(pht('Username')) 256 + ->setName('username') 257 + ->setValue($value_username) 258 + ->setError($e_username)); 259 + 260 + if ($must_set_password) { 261 + $form->appendChild( 262 + id(new AphrontFormPasswordControl()) 263 + ->setLabel(pht('Password')) 264 + ->setName('password') 265 + ->setError($e_password) 266 + ->setCaption( 267 + $min_len 268 + ? pht('Minimum length of %d characters.', $min_len) 269 + : null)); 270 + $form->appendChild( 271 + id(new AphrontFormPasswordControl()) 272 + ->setLabel(pht('Confirm Password')) 273 + ->setName('confirm') 274 + ->setError($e_password)); 275 + } 276 + 277 + if ($can_edit_email) { 278 + $form->appendChild( 279 + id(new AphrontFormTextControl()) 280 + ->setLabel(pht('Email')) 281 + ->setName('email') 282 + ->setValue($value_email) 283 + ->setCaption(PhabricatorUserEmail::describeAllowedAddresses()) 284 + ->setError($e_email)); 285 + } 286 + 287 + if ($can_edit_realname) { 288 + $form->appendChild( 289 + id(new AphrontFormTextControl()) 290 + ->setLabel(pht('Real Name')) 291 + ->setName('realName') 292 + ->setValue($value_realname) 293 + ->setError($e_realname)); 294 + } 295 + 296 + $form->appendChild( 297 + id(new AphrontFormSubmitControl()) 298 + ->setValue(pht('Create Account'))); 299 + 300 + $title = pht('Phabricator Registration'); 301 + 302 + $crumbs = $this->buildApplicationCrumbs(); 303 + $crumbs->addCrumb( 304 + id(new PhabricatorCrumbView()) 305 + ->setName(pht('Register'))); 306 + 307 + return $this->buildApplicationPage( 308 + array( 309 + $crumbs, 310 + $error_view, 311 + $form, 312 + ), 313 + array( 314 + 'title' => $title, 315 + 'device' => true, 316 + 'dust' => true, 317 + )); 318 + } 319 + 320 + private function loadAccount() { 321 + $request = $this->getRequest(); 322 + 323 + if (!$this->accountKey) { 324 + return $this->renderError(pht('Request did not include account key.')); 325 + } 326 + 327 + $account = id(new PhabricatorExternalAccount())->loadOneWhere( 328 + 'accountSecret = %s', 329 + $this->accountKey); 330 + 331 + if (!$account) { 332 + return $this->renderError(pht('No registration account.')); 333 + } 334 + 335 + if ($account->getUserPHID()) { 336 + return $this->renderError( 337 + pht( 338 + 'The account you are attempting to register with is already '. 339 + 'registered to another user.')); 340 + } 341 + 342 + $registration_key = $request->getCookie('phreg'); 343 + 344 + // NOTE: This registration key check is not strictly necessary, because 345 + // we're only creating new accounts, not linking existing accounts. It 346 + // might be more hassle than it is worth, especially for email. 347 + // 348 + // The attack this prevents is getting to the registration screen, then 349 + // copy/pasting the URL and getting someone else to click it and complete 350 + // the process. They end up with an account bound to credentials you 351 + // control. This doesn't really let you do anything meaningful, though, 352 + // since you could have simply completed the process yourself. 353 + 354 + if (!$registration_key) { 355 + return $this->renderError( 356 + pht( 357 + 'Your browser did not submit a registration key with the request. '. 358 + 'You must use the same browser to begin and complete registration. '. 359 + 'Check that cookies are enabled and try again.')); 360 + } 361 + 362 + if ($registration_key != $account->getProperty('registrationKey')) { 363 + return $this->renderError( 364 + pht( 365 + 'Your browser submitted a different registration key than the one '. 366 + 'associated with this account. You may need to clear your cookies.')); 367 + } 368 + 369 + $other_account = id(new PhabricatorExternalAccount())->loadAllWhere( 370 + 'accountType = %s AND accountDomain = %s AND accountID = %s 371 + AND id != %d', 372 + $account->getAccountType(), 373 + $account->getAccountDomain(), 374 + $account->getAccountID(), 375 + $account->getID()); 376 + 377 + if ($other_account) { 378 + return $this->renderError( 379 + pht( 380 + 'The account you are attempting to register with already belongs '. 381 + 'to another user.')); 382 + } 383 + 384 + $provider = PhabricatorAuthProvider::getEnabledProviderByKey( 385 + $account->getProviderKey()); 386 + 387 + if (!$provider) { 388 + return $this->renderError( 389 + pht( 390 + 'The account you are attempting to register with uses a nonexistent '. 391 + 'or disabled authentication provider (with key "%s"). An '. 392 + 'administrator may have recently disabled this provider.', 393 + $account->getProviderKey())); 394 + } 395 + 396 + if (!$provider->shouldAllowRegistration()) { 397 + 398 + // TODO: This is a routine error if you click "Login" on an external 399 + // auth source which doesn't allow registration. The error should be 400 + // more tailored. 401 + 402 + return $this->renderError( 403 + pht( 404 + 'The account you are attempting to register with uses an '. 405 + 'authentication provider ("%s") which does not allow registration. '. 406 + 'An administrator may have recently disabled registration with this '. 407 + 'provider.', 408 + $provider->getProviderName())); 409 + } 410 + 411 + $this->account = $account; 412 + $this->provider = $provider; 413 + 414 + return null; 415 + } 416 + 417 + private function loadDefaultAccount() { 418 + $providers = PhabricatorAuthProvider::getAllEnabledProviders(); 419 + foreach ($providers as $key => $provider) { 420 + if (!$provider->shouldAllowRegistration()) { 421 + unset($providers[$key]); 422 + continue; 423 + } 424 + if (!$provider->isDefaultRegistrationProvider()) { 425 + unset($providers[$key]); 426 + } 427 + } 428 + 429 + if (!$providers) { 430 + return $this->renderError( 431 + pht( 432 + "There are no configured default registration providers.")); 433 + } else if (count($providers) > 1) { 434 + return $this->renderError( 435 + pht( 436 + "There are too many configured default registration providers.")); 437 + } 438 + 439 + $this->account = $provider->getDefaultExternalAccount(); 440 + $this->provider = $provider; 441 + return null; 442 + } 443 + 444 + private function loadProfilePicture(PhabricatorExternalAccount $account) { 445 + $phid = $account->getProfileImagePHID(); 446 + if (!$phid) { 447 + return null; 448 + } 449 + 450 + // NOTE: Use of omnipotent user is okay here because the registering user 451 + // can not control the field value, and we can't use their user object to 452 + // do meaningful policy checks anyway since they have not registered yet. 453 + // Reaching this means the user holds the account secret key and the 454 + // registration secret key, and thus has permission to view the image. 455 + 456 + $file = id(new PhabricatorFileQuery()) 457 + ->setViewer(PhabricatorUser::getOmnipotentUser()) 458 + ->withPHIDs(array($phid)) 459 + ->executeOne(); 460 + if (!$file) { 461 + return null; 462 + } 463 + 464 + try { 465 + $xformer = new PhabricatorImageTransformer(); 466 + return $xformer->executeProfileTransform( 467 + $file, 468 + $width = 50, 469 + $min_height = 50, 470 + $max_height = 50); 471 + } catch (Exception $ex) { 472 + phlog($ex); 473 + return null; 474 + } 475 + } 476 + 477 + private function renderError($message) { 478 + return $this->renderErrorPage( 479 + pht('Registration Failed'), 480 + array($message)); 481 + } 482 + 483 + }
+84
src/applications/people/storage/PhabricatorRegistrationProfile.php
··· 1 + <?php 2 + 3 + final class PhabricatorRegistrationProfile extends Phobject { 4 + 5 + private $defaultUsername; 6 + private $defaultEmail; 7 + private $defaultRealName; 8 + private $canEditUsername; 9 + private $canEditEmail; 10 + private $canEditRealName; 11 + private $shouldVerifyEmail; 12 + 13 + public function setShouldVerifyEmail($should_verify_email) { 14 + $this->shouldVerifyEmail = $should_verify_email; 15 + return $this; 16 + } 17 + 18 + public function getShouldVerifyEmail() { 19 + return $this->shouldVerifyEmail; 20 + } 21 + 22 + public function setCanEditEmail($can_edit_email) { 23 + $this->canEditEmail = $can_edit_email; 24 + return $this; 25 + } 26 + 27 + public function getCanEditEmail() { 28 + return $this->canEditEmail; 29 + } 30 + 31 + public function setCanEditRealName($can_edit_real_name) { 32 + $this->canEditRealName = $can_edit_real_name; 33 + return $this; 34 + } 35 + 36 + public function getCanEditRealName() { 37 + return $this->canEditRealName; 38 + } 39 + 40 + 41 + public function setCanEditUsername($can_edit_username) { 42 + $this->canEditUsername = $can_edit_username; 43 + return $this; 44 + } 45 + 46 + public function getCanEditUsername() { 47 + return $this->canEditUsername; 48 + } 49 + 50 + public function setDefaultEmail($default_email) { 51 + $this->defaultEmail = $default_email; 52 + return $this; 53 + } 54 + 55 + public function getDefaultEmail() { 56 + return $this->defaultEmail; 57 + } 58 + 59 + public function setDefaultRealName($default_real_name) { 60 + $this->defaultRealName = $default_real_name; 61 + return $this; 62 + } 63 + 64 + public function getDefaultRealName() { 65 + return $this->defaultRealName; 66 + } 67 + 68 + 69 + public function setDefaultUsername($default_username) { 70 + $this->defaultUsername = $default_username; 71 + return $this; 72 + } 73 + 74 + public function getDefaultUsername() { 75 + return $this->defaultUsername; 76 + } 77 + 78 + public function getCanEditAnything() { 79 + return $this->getCanEditUsername() || 80 + $this->getCanEditEmail() || 81 + $this->getCanEditRealName(); 82 + } 83 + 84 + }
+2
src/infrastructure/events/constant/PhabricatorEventType.php
··· 36 36 const TYPE_UI_DIDRENDERHOVERCARD = 'ui.didRenderHovercard'; 37 37 38 38 const TYPE_PEOPLE_DIDRENDERMENU = 'people.didRenderMenu'; 39 + const TYPE_AUTH_WILLREGISTERUSER = 'auth.willRegisterUser'; 40 + 39 41 }