Files
BookStack/app/Users/Controllers/UserAccountController.php
T
Dan Brown 01b29515c8 Layouts: Updated view block ids/labels to be static
So that their metadata can be read without having to create instances
and fullfill dependancy injection just to list.

Also added title to interface prefs page.
2026-08-16 10:41:43 +01:00

261 lines
8.1 KiB
PHP

<?php
namespace BookStack\Users\Controllers;
use BookStack\Access\SocialDriverManager;
use BookStack\Http\Controller;
use BookStack\Permissions\Permission;
use BookStack\Permissions\PermissionApplicator;
use BookStack\Settings\UserNotificationPreferences;
use BookStack\Settings\UserShortcutMap;
use BookStack\Uploads\ImageRepo;
use BookStack\Users\UserRepo;
use BookStack\View\ViewBlockManager;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Validation\Rules\Password;
class UserAccountController extends Controller
{
public function __construct(
protected UserRepo $userRepo,
) {
$this->middleware(function (Request $request, Closure $next) {
$this->preventGuestAccess();
return $next($request);
});
}
/**
* Redirect the root my-account path to the main/first category.
* Required as a controller method, instead of the Route::redirect helper,
* to ensure the URL is generated correctly.
*/
public function redirect()
{
return redirect('/my-account/profile');
}
/**
* Show the profile form interface.
*/
public function showProfile()
{
$this->setPageTitle(trans('preferences.profile'));
return view('users.account.profile', [
'model' => user(),
'category' => 'profile',
]);
}
/**
* Handle the submission of the user profile form.
*/
public function updateProfile(Request $request, ImageRepo $imageRepo)
{
$this->preventAccessInDemoMode();
$user = user();
$validated = $this->validate($request, [
'name' => ['min:2', 'max:100'],
'email' => ['min:2', 'email', 'unique:users,email,' . $user->id],
'language' => ['string', 'max:15', 'alpha_dash'],
'profile_image' => array_merge(['nullable'], $this->getImageValidationRules()),
]);
$this->userRepo->update($user, $validated, userCan(Permission::UsersManage));
// Save the profile image if in request
if ($request->hasFile('profile_image')) {
$imageUpload = $request->file('profile_image');
$imageRepo->destroyImage($user->avatar);
$image = $imageRepo->saveNew($imageUpload, 'user', $user->id);
$user->image_id = $image->id;
$user->save();
}
// Delete the profile image if the reset option is in request
if ($request->has('profile_image_reset')) {
$imageRepo->destroyImage($user->avatar);
$user->image_id = 0;
$user->save();
}
return redirect('/my-account/profile');
}
/**
* Show the user-specific interface shortcuts.
*/
public function showShortcuts()
{
$shortcuts = UserShortcutMap::fromUserPreferences();
$enabled = setting()->getForCurrentUser('ui-shortcuts-enabled', false);
$this->setPageTitle(trans('preferences.shortcuts_interface'));
return view('users.account.shortcuts', [
'category' => 'shortcuts',
'shortcuts' => $shortcuts,
'enabled' => $enabled,
]);
}
/**
* Update the user-specific interface shortcuts.
*/
public function updateShortcuts(Request $request)
{
$enabled = $request->input('enabled') === 'true';
$providedShortcuts = $request->input('shortcut', []);
$shortcuts = new UserShortcutMap($providedShortcuts);
setting()->putForCurrentUser('ui-shortcuts', $shortcuts->toJson());
setting()->putForCurrentUser('ui-shortcuts-enabled', $enabled);
$this->showSuccessNotification(trans('preferences.shortcuts_update_success'));
return redirect('/my-account/shortcuts');
}
/**
* Show the notification preferences for the current user.
*/
public function showNotifications(PermissionApplicator $permissions)
{
$this->checkPermission(Permission::ReceiveNotifications);
$preferences = (new UserNotificationPreferences(user()));
$query = user()->watches()->getQuery();
$query = $permissions->restrictEntityRelationQuery($query, 'watches', 'watchable_id', 'watchable_type');
$query = $permissions->filterDeletedFromEntityRelationQuery($query, 'watches', 'watchable_id', 'watchable_type');
$watches = $query->with('watchable')->paginate(20);
$this->setPageTitle(trans('preferences.notifications'));
return view('users.account.notifications', [
'category' => 'notifications',
'preferences' => $preferences,
'watches' => $watches,
]);
}
/**
* Update the notification preferences for the current user.
*/
public function updateNotifications(Request $request)
{
$this->preventAccessInDemoMode();
$this->checkPermission(Permission::ReceiveNotifications);
$data = $this->validate($request, [
'preferences' => ['required', 'array'],
'preferences.*' => ['required', 'string'],
]);
$preferences = (new UserNotificationPreferences(user()));
$preferences->updateFromSettingsArray($data['preferences']);
$this->showSuccessNotification(trans('preferences.notifications_update_success'));
return redirect('/my-account/notifications');
}
/**
* Show the view for the "Interface Preferences" user account area.
*/
public function showInterface(ViewBlockManager $viewBlockManager)
{
$this->setPageTitle(trans('preferences.interface'));
return view('users.account.interface', [
'category' => 'interface',
'namedLocations' => $viewBlockManager->getNamedLocations(),
]);
}
/**
* Handle the submission of the interface preferences form.
*/
public function updateInterface(Request $request)
{
$this->preventAccessInDemoMode();
$user = user();
$validated = $this->validate($request, [
'language' => ['string', 'max:15', 'alpha_dash'],
'display_mode' => ['string', 'max:15', 'alpha_dash'],
]);
$this->userRepo->update($user, $validated, userCan(Permission::UsersManage));
return redirect('/my-account/interface');
}
/**
* Show the view for the "Access & Security" account options.
*/
public function showAuth(SocialDriverManager $socialDriverManager)
{
$mfaMethods = user()->mfaValues()->get()->groupBy('method');
$this->setPageTitle(trans('preferences.auth'));
return view('users.account.auth', [
'category' => 'auth',
'mfaMethods' => $mfaMethods,
'authMethod' => config('auth.method'),
'activeSocialDrivers' => $socialDriverManager->getActive(),
]);
}
/**
* Handle the submission for the auth change password form.
*/
public function updatePassword(Request $request)
{
$this->preventAccessInDemoMode();
if (config('auth.method') !== 'standard') {
$this->showPermissionError();
}
$validated = $this->validate($request, [
'password' => ['required_with:password_confirm', Password::default()],
'password-confirm' => ['same:password', 'required_with:password'],
]);
$this->userRepo->update(user(), $validated, false);
$this->showSuccessNotification(trans('preferences.auth_change_password_success'));
return redirect('/my-account/auth');
}
/**
* Show the user self-delete page.
*/
public function delete()
{
$this->setPageTitle(trans('preferences.delete_my_account'));
return view('users.account.delete', [
'category' => 'profile',
]);
}
/**
* Remove the current user from the system.
*/
public function destroy(Request $request)
{
$this->preventAccessInDemoMode();
$requestNewOwnerId = intval($request->input('new_owner_id')) ?: null;
$newOwnerId = userCan(Permission::UsersManage) ? $requestNewOwnerId : null;
$this->userRepo->destroy(user(), $newOwnerId);
return redirect('/');
}
}