1
0
mirror of https://github.com/BookStackApp/BookStack.git synced 2025-07-28 17:02:04 +03:00

Added user-update API endpoint

- Required changing the docs generator to handle more complex
  object-style rules. Bit of a hack for some types (password).
- Extracted core update logic to repo for sharing with API.
- Moved user update language string to align with activity/logging
  system.
- Added tests to cover.
This commit is contained in:
Dan Brown
2022-02-03 16:52:28 +00:00
parent 2cd7a48044
commit 9e1c8ec82a
11 changed files with 185 additions and 72 deletions

View File

@ -10,7 +10,6 @@ use Illuminate\Http\JsonResponse;
abstract class ApiController extends Controller
{
protected $rules = [];
protected $fieldsToExpose = [];
/**
* Provide a paginated listing JSON response in a standard format
@ -31,7 +30,7 @@ abstract class ApiController extends Controller
* Get the validation rules for this controller.
* Defaults to a $rules property but can be a rules() method.
*/
public function getValdationRules(): array
public function getValidationRules(): array
{
if (method_exists($this, 'rules')) {
return $this->rules();

View File

@ -6,6 +6,8 @@ use BookStack\Auth\User;
use BookStack\Auth\UserRepo;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Validation\Rules\Password;
use Illuminate\Validation\Rules\Unique;
class UserApiController extends ApiController
{
@ -15,21 +17,35 @@ class UserApiController extends ApiController
'email', 'created_at', 'updated_at', 'last_activity_at', 'external_auth_id'
];
protected $rules = [
'create' => [
],
'update' => [
],
'delete' => [
'migrate_ownership_id' => ['integer', 'exists:users,id'],
],
];
public function __construct(UserRepo $userRepo)
{
$this->userRepo = $userRepo;
}
protected function rules(int $userId = null): array
{
return [
'create' => [
],
'update' => [
'name' => ['min:2'],
'email' => [
'min:2',
'email',
(new Unique('users', 'email'))->ignore($userId ?? null)
],
'external_auth_id' => ['string'],
'language' => ['string'],
'password' => [Password::default()],
'roles' => ['array'],
'roles.*' => ['integer'],
],
'delete' => [
'migrate_ownership_id' => ['integer', 'exists:users,id'],
],
];
}
/**
* Get a listing of users in the system.
* Requires permission to manage users.
@ -54,10 +70,26 @@ class UserApiController extends ApiController
{
$this->checkPermission('users-manage');
$singleUser = $this->userRepo->getById($id);
$this->singleFormatter($singleUser);
$user = $this->userRepo->getById($id);
$this->singleFormatter($user);
return response()->json($singleUser);
return response()->json($user);
}
/**
* Update an existing user in the system.
* @throws \BookStack\Exceptions\UserUpdateException
*/
public function update(Request $request, string $id)
{
$this->checkPermission('users-manage');
$data = $this->validate($request, $this->rules($id)['update']);
$user = $this->userRepo->getById($id);
$this->userRepo->update($user, $data, userCan('users-manage'));
$this->singleFormatter($user);
return response()->json($user);
}
/**

View File

@ -168,51 +168,19 @@ class UserController extends Controller
$this->preventAccessInDemoMode();
$this->checkPermissionOrCurrentUser('users-manage', $id);
$this->validate($request, [
$validated = $this->validate($request, [
'name' => ['min:2'],
'email' => ['min:2', 'email', 'unique:users,email,' . $id],
'password' => ['required_with:password_confirm', Password::default()],
'password-confirm' => ['same:password', 'required_with:password'],
'setting' => ['array'],
'language' => ['string'],
'roles' => ['array'],
'roles.*' => ['integer'],
'profile_image' => array_merge(['nullable'], $this->getImageValidationRules()),
]);
$user = $this->userRepo->getById($id);
$user->fill($request->except(['email']));
// Email updates
if (userCan('users-manage') && $request->filled('email')) {
$user->email = $request->get('email');
}
// Refresh the slug if the user's name has changed
if ($user->isDirty('name')) {
$user->refreshSlug();
}
// Role updates
if (userCan('users-manage') && $request->filled('roles')) {
$roles = $request->get('roles');
$this->userRepo->setUserRoles($user, $roles);
}
// Password updates
if ($request->filled('password')) {
$password = $request->get('password');
$user->password = bcrypt($password);
}
// External auth id updates
if (user()->can('users-manage') && $request->filled('external_auth_id')) {
$user->external_auth_id = $request->get('external_auth_id');
}
// Save user-specific settings
if ($request->filled('setting')) {
foreach ($request->get('setting') as $key => $value) {
setting()->putUser($user, $key, $value);
}
}
$this->userRepo->update($user, $validated, userCan('users-manage'));
// Save profile image if in request
if ($request->hasFile('profile_image')) {
@ -220,6 +188,7 @@ class UserController extends Controller
$this->imageRepo->destroyImage($user->avatar);
$image = $this->imageRepo->saveNew($imageUpload, 'user', $user->id);
$user->image_id = $image->id;
$user->save();
}
// Delete the profile image if reset option is in request
@ -227,11 +196,7 @@ class UserController extends Controller
$this->imageRepo->destroyImage($user->avatar);
}
$user->save();
$this->showSuccessNotification(trans('settings.users_edit_success'));
$this->logActivity(ActivityType::USER_UPDATE, $user);
$redirectUrl = userCan('users-manage') ? '/settings/users' : ('/settings/users/' . $user->id);
$redirectUrl = userCan('users-manage') ? '/settings/users' : "/settings/users/{$user->id}";
return redirect($redirectUrl);
}