mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-11 17:32:41 +01:00
77f546c572
Summary: Allow installs to require users to verify email addresses before they can use Phabricator. If a user logs in without a verified email address, they're given instructions to verify their address. This isn't too useful on its own since we don't actually have arbitrary email registration, but the next step is to allow installs to restrict email to only some domains (e.g., @mycompany.com). Test Plan: - Verification - Set verification requirement to `true`. - Tried to use Phabricator with an unverified account, was told to verify. - Tried to use Conduit, was given a verification error. - Verified account, used Phabricator. - Unverified account, reset password, verified implicit verification, used Phabricator. - People Admin Interface - Viewed as admin. Clicked "Administrate User". - Viewed as non-admin - Sanity Checks - Used Conduit normally from web/CLI with a verified account. - Logged in/out. - Sent password reset email. - Created a new user. - Logged in with an unverified user but with the configuration set to off. Reviewers: btrahan, vrana, jungejason Reviewed By: btrahan CC: aran, csilvers Maniphest Tasks: T1184 Differential Revision: https://secure.phabricator.com/D2520
505 lines
13 KiB
PHP
505 lines
13 KiB
PHP
<?php
|
|
|
|
/*
|
|
* Copyright 2012 Facebook, Inc.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
final class PhabricatorPeopleEditController
|
|
extends PhabricatorPeopleController {
|
|
|
|
public function shouldRequireAdmin() {
|
|
return true;
|
|
}
|
|
|
|
private $id;
|
|
private $view;
|
|
|
|
public function willProcessRequest(array $data) {
|
|
$this->id = idx($data, 'id');
|
|
$this->view = idx($data, 'view');
|
|
}
|
|
|
|
public function processRequest() {
|
|
|
|
$request = $this->getRequest();
|
|
$admin = $request->getUser();
|
|
|
|
if ($this->id) {
|
|
$user = id(new PhabricatorUser())->load($this->id);
|
|
if (!$user) {
|
|
return new Aphront404Response();
|
|
}
|
|
} else {
|
|
$user = new PhabricatorUser();
|
|
}
|
|
|
|
$views = array(
|
|
'basic' => 'Basic Information',
|
|
'role' => 'Edit Roles',
|
|
'cert' => 'Conduit Certificate',
|
|
);
|
|
|
|
if (!$user->getID()) {
|
|
$view = 'basic';
|
|
} else if (isset($views[$this->view])) {
|
|
$view = $this->view;
|
|
} else {
|
|
$view = 'basic';
|
|
}
|
|
|
|
$content = array();
|
|
|
|
if ($request->getStr('saved')) {
|
|
$notice = new AphrontErrorView();
|
|
$notice->setSeverity(AphrontErrorView::SEVERITY_NOTICE);
|
|
$notice->setTitle('Changes Saved');
|
|
$notice->appendChild('<p>Your changes were saved.</p>');
|
|
$content[] = $notice;
|
|
}
|
|
|
|
switch ($view) {
|
|
case 'basic':
|
|
$response = $this->processBasicRequest($user);
|
|
break;
|
|
case 'role':
|
|
$response = $this->processRoleRequest($user);
|
|
break;
|
|
case 'cert':
|
|
$response = $this->processCertificateRequest($user);
|
|
break;
|
|
}
|
|
|
|
if ($response instanceof AphrontResponse) {
|
|
return $response;
|
|
}
|
|
|
|
$content[] = $response;
|
|
|
|
if ($user->getID()) {
|
|
$side_nav = new AphrontSideNavView();
|
|
$side_nav->appendChild($content);
|
|
foreach ($views as $key => $name) {
|
|
$side_nav->addNavItem(
|
|
phutil_render_tag(
|
|
'a',
|
|
array(
|
|
'href' => '/people/edit/'.$user->getID().'/'.$key.'/',
|
|
'class' => ($key == $view)
|
|
? 'aphront-side-nav-selected'
|
|
: null,
|
|
),
|
|
phutil_escape_html($name)));
|
|
}
|
|
$content = $side_nav;
|
|
}
|
|
|
|
return $this->buildStandardPageResponse(
|
|
$content,
|
|
array(
|
|
'title' => 'Edit User',
|
|
));
|
|
}
|
|
|
|
private function processBasicRequest(PhabricatorUser $user) {
|
|
$request = $this->getRequest();
|
|
$admin = $request->getUser();
|
|
|
|
$e_username = true;
|
|
$e_realname = true;
|
|
$e_email = true;
|
|
$errors = array();
|
|
|
|
$welcome_checked = true;
|
|
|
|
$new_email = null;
|
|
|
|
$request = $this->getRequest();
|
|
if ($request->isFormPost()) {
|
|
$welcome_checked = $request->getInt('welcome');
|
|
|
|
if (!$user->getID()) {
|
|
$user->setUsername($request->getStr('username'));
|
|
|
|
$new_email = $request->getStr('email');
|
|
if (!strlen($new_email)) {
|
|
$errors[] = 'Email is required.';
|
|
$e_email = 'Required';
|
|
}
|
|
|
|
if ($request->getStr('role') == 'agent') {
|
|
$user->setIsSystemAgent(true);
|
|
}
|
|
}
|
|
$user->setRealName($request->getStr('realname'));
|
|
|
|
if (!strlen($user->getUsername())) {
|
|
$errors[] = "Username is required.";
|
|
$e_username = 'Required';
|
|
} else if (!PhabricatorUser::validateUsername($user->getUsername())) {
|
|
$errors[] = "Username must consist of only numbers and letters.";
|
|
$e_username = 'Invalid';
|
|
} else {
|
|
$e_username = null;
|
|
}
|
|
|
|
if (!strlen($user->getRealName())) {
|
|
$errors[] = 'Real name is required.';
|
|
$e_realname = 'Required';
|
|
} else {
|
|
$e_realname = null;
|
|
}
|
|
|
|
if (!$errors) {
|
|
try {
|
|
$is_new = !$user->getID();
|
|
|
|
$user->save();
|
|
|
|
if ($is_new) {
|
|
|
|
$email = id(new PhabricatorUserEmail())
|
|
->setUserPHID($user->getPHID())
|
|
->setAddress($new_email)
|
|
->setIsPrimary(1)
|
|
->setIsVerified(0)
|
|
->save();
|
|
|
|
$log = PhabricatorUserLog::newLog(
|
|
$admin,
|
|
$user,
|
|
PhabricatorUserLog::ACTION_CREATE);
|
|
$log->save();
|
|
|
|
if ($welcome_checked) {
|
|
$user->sendWelcomeEmail($admin);
|
|
}
|
|
}
|
|
|
|
$response = id(new AphrontRedirectResponse())
|
|
->setURI('/people/edit/'.$user->getID().'/?saved=true');
|
|
return $response;
|
|
} catch (AphrontQueryDuplicateKeyException $ex) {
|
|
$errors[] = 'Username and email must be unique.';
|
|
|
|
$same_username = id(new PhabricatorUser())
|
|
->loadOneWhere('username = %s', $user->getUsername());
|
|
$same_email = id(new PhabricatorUserEmail())
|
|
->loadOneWhere('address = %s', $new_email);
|
|
|
|
if ($same_username) {
|
|
$e_username = 'Duplicate';
|
|
}
|
|
|
|
if ($same_email) {
|
|
$e_email = 'Duplicate';
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
$error_view = null;
|
|
if ($errors) {
|
|
$error_view = id(new AphrontErrorView())
|
|
->setTitle('Form Errors')
|
|
->setErrors($errors);
|
|
}
|
|
|
|
$form = new AphrontFormView();
|
|
$form->setUser($admin);
|
|
if ($user->getID()) {
|
|
$form->setAction('/people/edit/'.$user->getID().'/');
|
|
} else {
|
|
$form->setAction('/people/edit/');
|
|
}
|
|
|
|
if ($user->getID()) {
|
|
$is_immutable = true;
|
|
} else {
|
|
$is_immutable = false;
|
|
}
|
|
|
|
$form
|
|
->appendChild(
|
|
id(new AphrontFormTextControl())
|
|
->setLabel('Username')
|
|
->setName('username')
|
|
->setValue($user->getUsername())
|
|
->setError($e_username)
|
|
->setDisabled($is_immutable)
|
|
->setCaption('Usernames are permanent and can not be changed later!'))
|
|
->appendChild(
|
|
id(new AphrontFormTextControl())
|
|
->setLabel('Real Name')
|
|
->setName('realname')
|
|
->setValue($user->getRealName())
|
|
->setError($e_realname));
|
|
|
|
if (!$user->getID()) {
|
|
$form->appendChild(
|
|
id(new AphrontFormTextControl())
|
|
->setLabel('Email')
|
|
->setName('email')
|
|
->setDisabled($is_immutable)
|
|
->setValue($new_email)
|
|
->setError($e_email));
|
|
} else {
|
|
$form->appendChild(
|
|
id(new AphrontFormStaticControl())
|
|
->setLabel('Email')
|
|
->setValue(
|
|
$user->loadPrimaryEmail()->getIsVerified()
|
|
? 'Verified'
|
|
: 'Unverified'));
|
|
}
|
|
|
|
$form->appendChild($this->getRoleInstructions());
|
|
|
|
if (!$user->getID()) {
|
|
$form
|
|
->appendChild(
|
|
id(new AphrontFormSelectControl())
|
|
->setLabel('Role')
|
|
->setName('role')
|
|
->setValue('user')
|
|
->setOptions(
|
|
array(
|
|
'user' => 'Normal User',
|
|
'agent' => 'System Agent',
|
|
))
|
|
->setCaption(
|
|
'You can create a "system agent" account for bots, scripts, '.
|
|
'etc.'))
|
|
->appendChild(
|
|
id(new AphrontFormCheckboxControl())
|
|
->addCheckbox(
|
|
'welcome',
|
|
1,
|
|
'Send "Welcome to Phabricator" email.',
|
|
$welcome_checked));
|
|
} else {
|
|
$roles = array();
|
|
|
|
if ($user->getIsSystemAgent()) {
|
|
$roles[] = 'System Agent';
|
|
}
|
|
if ($user->getIsAdmin()) {
|
|
$roles[] = 'Admin';
|
|
}
|
|
if ($user->getIsDisabled()) {
|
|
$roles[] = 'Disabled';
|
|
}
|
|
|
|
if (!$roles) {
|
|
$roles[] = 'Normal User';
|
|
}
|
|
|
|
$roles = implode(', ', $roles);
|
|
|
|
$form->appendChild(
|
|
id(new AphrontFormStaticControl())
|
|
->setLabel('Roles')
|
|
->setValue($roles));
|
|
}
|
|
|
|
$form
|
|
->appendChild(
|
|
id(new AphrontFormSubmitControl())
|
|
->setValue('Save'));
|
|
|
|
$panel = new AphrontPanelView();
|
|
if ($user->getID()) {
|
|
$panel->setHeader('Edit User');
|
|
} else {
|
|
$panel->setHeader('Create New User');
|
|
}
|
|
|
|
$panel->appendChild($form);
|
|
$panel->setWidth(AphrontPanelView::WIDTH_FORM);
|
|
|
|
return array($error_view, $panel);
|
|
}
|
|
|
|
private function processRoleRequest(PhabricatorUser $user) {
|
|
$request = $this->getRequest();
|
|
$admin = $request->getUser();
|
|
|
|
$is_self = ($user->getID() == $admin->getID());
|
|
|
|
$errors = array();
|
|
|
|
if ($request->isFormPost()) {
|
|
|
|
$log_template = PhabricatorUserLog::newLog(
|
|
$admin,
|
|
$user,
|
|
null);
|
|
|
|
$logs = array();
|
|
|
|
if ($is_self) {
|
|
$errors[] = "You can not edit your own role.";
|
|
} else {
|
|
$new_admin = (bool)$request->getBool('is_admin');
|
|
$old_admin = (bool)$user->getIsAdmin();
|
|
if ($new_admin != $old_admin) {
|
|
$log = clone $log_template;
|
|
$log->setAction(PhabricatorUserLog::ACTION_ADMIN);
|
|
$log->setOldValue($old_admin);
|
|
$log->setNewValue($new_admin);
|
|
$user->setIsAdmin($new_admin);
|
|
$logs[] = $log;
|
|
}
|
|
|
|
$new_disabled = (bool)$request->getBool('is_disabled');
|
|
$old_disabled = (bool)$user->getIsDisabled();
|
|
if ($new_disabled != $old_disabled) {
|
|
$log = clone $log_template;
|
|
$log->setAction(PhabricatorUserLog::ACTION_DISABLE);
|
|
$log->setOldValue($old_disabled);
|
|
$log->setNewValue($new_disabled);
|
|
$user->setIsDisabled($new_disabled);
|
|
$logs[] = $log;
|
|
}
|
|
}
|
|
|
|
if (!$errors) {
|
|
$user->save();
|
|
foreach ($logs as $log) {
|
|
$log->save();
|
|
}
|
|
return id(new AphrontRedirectResponse())
|
|
->setURI($request->getRequestURI()->alter('saved', 'true'));
|
|
}
|
|
}
|
|
|
|
$error_view = null;
|
|
if ($errors) {
|
|
$error_view = id(new AphrontErrorView())
|
|
->setTitle('Form Errors')
|
|
->setErrors($errors);
|
|
}
|
|
|
|
|
|
$form = id(new AphrontFormView())
|
|
->setUser($admin)
|
|
->setAction($request->getRequestURI()->alter('saved', null));
|
|
|
|
if ($is_self) {
|
|
$form->appendChild(
|
|
'<p class="aphront-form-instructions">NOTE: You can not edit your own '.
|
|
'role.</p>');
|
|
}
|
|
|
|
$form
|
|
->appendChild($this->getRoleInstructions())
|
|
->appendChild(
|
|
id(new AphrontFormCheckboxControl())
|
|
->addCheckbox(
|
|
'is_admin',
|
|
1,
|
|
'Administrator',
|
|
$user->getIsAdmin())
|
|
->setDisabled($is_self))
|
|
->appendChild(
|
|
id(new AphrontFormCheckboxControl())
|
|
->addCheckbox(
|
|
'is_disabled',
|
|
1,
|
|
'Disabled',
|
|
$user->getIsDisabled())
|
|
->setDisabled($is_self))
|
|
->appendChild(
|
|
id(new AphrontFormCheckboxControl())
|
|
->addCheckbox(
|
|
'is_agent',
|
|
1,
|
|
'System Agent (Bot/Script User)',
|
|
$user->getIsSystemAgent())
|
|
->setDisabled(true));
|
|
|
|
if (!$is_self) {
|
|
$form
|
|
->appendChild(
|
|
id(new AphrontFormSubmitControl())
|
|
->setValue('Edit Role'));
|
|
}
|
|
|
|
$panel = new AphrontPanelView();
|
|
$panel->setHeader('Edit Role');
|
|
$panel->setWidth(AphrontPanelView::WIDTH_FORM);
|
|
$panel->appendChild($form);
|
|
|
|
return array($error_view, $panel);
|
|
}
|
|
|
|
private function processCertificateRequest($user) {
|
|
$request = $this->getRequest();
|
|
$admin = $request->getUser();
|
|
|
|
|
|
$form = new AphrontFormView();
|
|
$form
|
|
->setUser($admin)
|
|
->setAction($request->getRequestURI())
|
|
->appendChild(
|
|
'<p class="aphront-form-instructions">You can use this certificate '.
|
|
'to write scripts or bots which interface with Phabricator over '.
|
|
'Conduit.</p>');
|
|
|
|
if ($user->getIsSystemAgent()) {
|
|
$form
|
|
->appendChild(
|
|
id(new AphrontFormTextControl())
|
|
->setLabel('Username')
|
|
->setValue($user->getUsername()))
|
|
->appendChild(
|
|
id(new AphrontFormTextAreaControl())
|
|
->setLabel('Certificate')
|
|
->setValue($user->getConduitCertificate()));
|
|
} else {
|
|
$form->appendChild(
|
|
id(new AphrontFormStaticControl())
|
|
->setLabel('Certificate')
|
|
->setValue(
|
|
'You may only view the certificates of System Agents.'));
|
|
}
|
|
|
|
$panel = new AphrontPanelView();
|
|
$panel->setHeader('Conduit Certificate');
|
|
$panel->setWidth(AphrontPanelView::WIDTH_FORM);
|
|
|
|
$panel->appendChild($form);
|
|
|
|
return array($panel);
|
|
}
|
|
|
|
private function getRoleInstructions() {
|
|
$roles_link = phutil_render_tag(
|
|
'a',
|
|
array(
|
|
'href' => PhabricatorEnv::getDoclink(
|
|
'article/User_Guide_Account_Roles.html'),
|
|
'target' => '_blank',
|
|
),
|
|
'User Guide: Account Roles');
|
|
|
|
return
|
|
'<p class="aphront-form-instructions">'.
|
|
'For a detailed explanation of account roles, see '.
|
|
$roles_link.'.'.
|
|
'</p>';
|
|
}
|
|
|
|
}
|