Page MenuHomestyx hydra

No OneTemporary

diff --git a/src/applications/people/controller/edit/PhabricatorPeopleEditController.php b/src/applications/people/controller/edit/PhabricatorPeopleEditController.php
index b1ea4edff9..50de1f7b81 100644
--- a/src/applications/people/controller/edit/PhabricatorPeopleEditController.php
+++ b/src/applications/people/controller/edit/PhabricatorPeopleEditController.php
@@ -1,462 +1,485 @@
<?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 Role',
+ '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;
$request = $this->getRequest();
if ($request->isFormPost()) {
$welcome_checked = $request->getInt('welcome');
if (!$user->getID()) {
$user->setUsername($request->getStr('username'));
$user->setEmail($request->getStr('email'));
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 (!strlen($user->getEmail())) {
$errors[] = 'Email is required.';
$e_email = 'Required';
} else {
$e_email = null;
}
if (!$errors) {
try {
$is_new = !$user->getID();
$user->save();
if ($is_new) {
$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 PhabricatorUser())
->loadOneWhere('email = %s', $user->getEmail());
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))
->appendChild(
id(new AphrontFormTextControl())
->setLabel('Email')
->setName('email')
->setDisabled($is_immutable)
->setValue($user->getEmail())
->setError($e_email))
->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('Role')
- ->setValue(
- $user->getIsSystemAgent()
- ? 'System Agent'
- : 'Normal User'));
+ ->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,
- 'Admin: wields absolute power.',
+ 'Administrator',
$user->getIsAdmin())
->setDisabled($is_self))
->appendChild(
id(new AphrontFormCheckboxControl())
->addCheckbox(
'is_disabled',
1,
- 'Disabled: can not login.',
+ 'Disabled',
$user->getIsDisabled())
- ->setDisabled($is_self));
+ ->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>';
}
}
diff --git a/src/docs/userguide/users.diviner b/src/docs/userguide/users.diviner
index a7895ad949..11b4d9b4f7 100644
--- a/src/docs/userguide/users.diviner
+++ b/src/docs/userguide/users.diviner
@@ -1,64 +1,69 @@
@title User Guide: Account Roles
@group userguide
Describes account roles like "Administrator", "Disabled" and "System Agent".
= Overview =
When you create a user account, you can set roles like "Administrator",
"Disabled" or "System Agent". This document explains what these roles mean.
= Administrators =
**Administrators** are normal users with extra capabilities. They have access
to some tools and workflows that normal users don't, which they can use to
debug and configure Phabricator. For example, they have access to:
- **Account Management**: The primary function of administrators is adding,
disabling, and managing user accounts. Administrators can create and edit
accounts and view access logs.
- **MetaMTA**: Administrators can send test email via MetaMTA. This isn't
available to normal users to prevent Phabricator from serving as a partially
open relay if used by open source projects.
- **Repositories**: Administrators can configure repositories. This isn't
normally available because it is specialized and complicated to configure.
Administrators have a few other minor capabilities in other tools. When you are
in an administrative interface, the menu bar is red.
Administrators are **not** in complete control of the system. Administrators
**can not** login as other users or act on behalf of other users. Administrators
**can not** bypass object privacy policies.
NOTE: Administrators currently //can// act on behalf of other users via Conduit.
This will be locked down at some point.
= System Agents =
**System Agents** are accounts for bots and scripts which need to interface
with the system but are not regular users. Generally, when you write scripts
that use Conduit (like the IRC bot), you should create a System Agent account
for them. System agents:
- **can not login** (they //can// access API methods via Conduit);
- **can not review diffs or own tasks**;
- **do not appear in CC tokenzers**.
+Currently, the **System Agent** role for an account can not be changed after the
+account is created. This prevents administrators form changing a normal user
+into a system agent, retrieving their Conduit certificate, and then changing
+them back (which would allow administrators to gain other users' credentials).
+
= Disabled Users =
**Disabled Users** are accounts that are no longer active. Generally, when
someone leaves a project (e.g., leaves your company, or their internship or
contract ends) you should disable their account to terminate their access to the
system. Disabled users:
- **can not login**;
- **can not access Conduit**;
- **do not receive email**;
- **do not appear in owner/reviewer/CC tokenizers**.
Users can only be disabled (not deleted) because there are a number of workflows
that don't make sense if their account is completely deleted, like: finding old
revisions or tasks that they were responsible for (so you can get someone else
to take care of them); identifying them as the author of their changes; and
restoring all their data if they rejoin the project (e.g., they are later
re-hired, maybe as a full time employee after an internship).

File Metadata

Mime Type
text/x-diff
Expires
Tue, Jun 10, 12:39 PM (1 d, 2 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
140380
Default Alt Text
(17 KB)

Event Timeline