mirror of
https://github.com/BookStackApp/BookStack.git
synced 2024-08-26 12:16:07 +00:00
Merge branch 'user_list_control'
This commit is contained in:
commit
e43f679e62
@ -63,13 +63,16 @@ class UserRepo
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all the users with their permissions in a paginated format.
|
* Get all the users with their permissions in a paginated format.
|
||||||
|
* Note: Due to the use of email search this should only be used when
|
||||||
|
* user is assumed to be trusted. (Admin users).
|
||||||
|
* Email search can be abused to extract email addresses.
|
||||||
*/
|
*/
|
||||||
public function getAllUsersPaginatedAndSorted(int $count, array $sortData): LengthAwarePaginator
|
public function getAllUsersPaginatedAndSorted(int $count, array $sortData): LengthAwarePaginator
|
||||||
{
|
{
|
||||||
$sort = $sortData['sort'];
|
$sort = $sortData['sort'];
|
||||||
|
|
||||||
$query = User::query()->select(['*'])
|
$query = User::query()->select(['*'])
|
||||||
->withLastActivityAt()
|
->scopes(['withLastActivityAt'])
|
||||||
->with(['roles', 'avatar'])
|
->with(['roles', 'avatar'])
|
||||||
->withCount('mfaValues')
|
->withCount('mfaValues')
|
||||||
->orderBy($sort, $sortData['order']);
|
->orderBy($sort, $sortData['order']);
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
namespace BookStack\Http\Controllers;
|
namespace BookStack\Http\Controllers;
|
||||||
|
|
||||||
use BookStack\Auth\User;
|
use BookStack\Auth\User;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
class UserSearchController extends Controller
|
class UserSearchController extends Controller
|
||||||
@ -14,19 +13,27 @@ class UserSearchController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function forSelect(Request $request)
|
public function forSelect(Request $request)
|
||||||
{
|
{
|
||||||
|
$hasPermission = signedInUser() && (
|
||||||
|
userCan('users-manage')
|
||||||
|
|| userCan('restrictions-manage-own')
|
||||||
|
|| userCan('restrictions-manage-all')
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!$hasPermission) {
|
||||||
|
$this->showPermissionError();
|
||||||
|
}
|
||||||
|
|
||||||
$search = $request->get('search', '');
|
$search = $request->get('search', '');
|
||||||
$query = User::query()->orderBy('name', 'desc')
|
$query = User::query()
|
||||||
|
->orderBy('name', 'asc')
|
||||||
->take(20);
|
->take(20);
|
||||||
|
|
||||||
if (!empty($search)) {
|
if (!empty($search)) {
|
||||||
$query->where(function (Builder $query) use ($search) {
|
$query->where('name', 'like', '%' . $search . '%');
|
||||||
$query->where('email', 'like', '%' . $search . '%')
|
|
||||||
->orWhere('name', 'like', '%' . $search . '%');
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$users = $query->get();
|
return view('form.user-select-list', [
|
||||||
|
'users' => $query->get(),
|
||||||
return view('form.user-select-list', compact('users'));
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
<p>{{ trans('settings.users_delete_warning', ['userName' => $user->name]) }}</p>
|
<p>{{ trans('settings.users_delete_warning', ['userName' => $user->name]) }}</p>
|
||||||
|
|
||||||
|
@if(userCan('users-manage'))
|
||||||
<hr class="my-l">
|
<hr class="my-l">
|
||||||
|
|
||||||
<div class="grid half gap-xl v-center">
|
<div class="grid half gap-xl v-center">
|
||||||
@ -23,6 +24,7 @@
|
|||||||
@include('form.user-select', ['name' => 'new_owner_id', 'user' => null, 'compact' => false])
|
@include('form.user-select', ['name' => 'new_owner_id', 'user' => null, 'compact' => false])
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
<hr class="my-l">
|
<hr class="my-l">
|
||||||
|
|
||||||
|
@ -130,6 +130,21 @@ class UserManagementTest extends TestCase
|
|||||||
$resp->assertSee('new_owner_id');
|
$resp->assertSee('new_owner_id');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function test_migrate_option_hidden_if_user_cannot_manage_users()
|
||||||
|
{
|
||||||
|
$editor = $this->getEditor();
|
||||||
|
|
||||||
|
$resp = $this->asEditor()->get("settings/users/{$editor->id}/delete");
|
||||||
|
$resp->assertDontSee('Migrate Ownership');
|
||||||
|
$resp->assertDontSee('new_owner_id');
|
||||||
|
|
||||||
|
$this->giveUserPermissions($editor, ['users-manage']);
|
||||||
|
|
||||||
|
$resp = $this->asEditor()->get("settings/users/{$editor->id}/delete");
|
||||||
|
$resp->assertSee('Migrate Ownership');
|
||||||
|
$resp->assertSee('new_owner_id');
|
||||||
|
}
|
||||||
|
|
||||||
public function test_delete_with_new_owner_id_changes_ownership()
|
public function test_delete_with_new_owner_id_changes_ownership()
|
||||||
{
|
{
|
||||||
$page = Page::query()->first();
|
$page = Page::query()->first();
|
||||||
|
68
tests/User/UserSearchTest.php
Normal file
68
tests/User/UserSearchTest.php
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\User;
|
||||||
|
|
||||||
|
use BookStack\Auth\User;
|
||||||
|
use Tests\TestCase;
|
||||||
|
|
||||||
|
class UserSearchTest extends TestCase
|
||||||
|
{
|
||||||
|
|
||||||
|
public function test_select_search_matches_by_name()
|
||||||
|
{
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
$admin = $this->getAdmin();
|
||||||
|
$resp = $this->actingAs($admin)->get('/search/users/select?search=' . urlencode($viewer->name));
|
||||||
|
|
||||||
|
$resp->assertOk();
|
||||||
|
$resp->assertSee($viewer->name);
|
||||||
|
$resp->assertDontSee($admin->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_select_search_shows_first_by_name_without_search()
|
||||||
|
{
|
||||||
|
/** @var User $firstUser */
|
||||||
|
$firstUser = User::query()->orderBy('name', 'desc')->first();
|
||||||
|
$resp = $this->asAdmin()->get('/search/users/select');
|
||||||
|
|
||||||
|
$resp->assertOk();
|
||||||
|
$resp->assertSee($firstUser->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_select_search_does_not_match_by_email()
|
||||||
|
{
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
$editor = $this->getEditor();
|
||||||
|
$resp = $this->actingAs($editor)->get('/search/users/select?search=' . urlencode($viewer->email));
|
||||||
|
|
||||||
|
$resp->assertDontSee($viewer->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_select_requires_right_permission()
|
||||||
|
{
|
||||||
|
$permissions = ['users-manage', 'restrictions-manage-own', 'restrictions-manage-all'];
|
||||||
|
$user = $this->getViewer();
|
||||||
|
|
||||||
|
foreach ($permissions as $permission) {
|
||||||
|
$resp = $this->actingAs($user)->get('/search/users/select?search=a');
|
||||||
|
$this->assertPermissionError($resp);
|
||||||
|
|
||||||
|
$this->giveUserPermissions($user, [$permission]);
|
||||||
|
$resp = $this->actingAs($user)->get('/search/users/select?search=a');
|
||||||
|
$resp->assertOk();
|
||||||
|
$user->roles()->delete();
|
||||||
|
$user->clearPermissionCache();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_select_requires_logged_in_user()
|
||||||
|
{
|
||||||
|
$this->setSettings(['app-public' => true]);
|
||||||
|
$defaultUser = User::getDefault();
|
||||||
|
$this->giveUserPermissions($defaultUser, ['users-manage']);
|
||||||
|
|
||||||
|
$resp = $this->get('/search/users/select?search=a');
|
||||||
|
$this->assertPermissionError($resp);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user