X-Git-Url: http://source.bookstackapp.com/bookstack/blobdiff_plain/a9d0f3676629053422ee5340f8c83888af18d766..refs/pull/5681/head:/app/Users/Controllers/UserAccountController.php diff --git a/app/Users/Controllers/UserAccountController.php b/app/Users/Controllers/UserAccountController.php index 9152eb5e8..708a91e9d 100644 --- a/app/Users/Controllers/UserAccountController.php +++ b/app/Users/Controllers/UserAccountController.php @@ -2,31 +2,85 @@ namespace BookStack\Users\Controllers; +use BookStack\Access\SocialDriverManager; use BookStack\Http\Controller; use BookStack\Permissions\PermissionApplicator; use BookStack\Settings\UserNotificationPreferences; use BookStack\Settings\UserShortcutMap; +use BookStack\Uploads\ImageRepo; use BookStack\Users\UserRepo; +use Closure; use Illuminate\Http\Request; +use Illuminate\Validation\Rules\Password; class UserAccountController extends Controller { public function __construct( - protected UserRepo $userRepo + protected UserRepo $userRepo, ) { + $this->middleware(function (Request $request, Closure $next) { + $this->preventGuestAccess(); + return $next($request); + }); } /** - * Show the overview for user preferences. + * 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 index() + public function redirect() { - $guest = user()->isGuest(); - $mfaMethods = $guest ? [] : user()->mfaValues->groupBy('method'); + return redirect('/my-account/profile'); + } - return view('users.account.index', [ - 'mfaMethods' => $mfaMethods, + /** + * 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('users-manage')); + + // Save 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 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'); } /** @@ -40,6 +94,7 @@ class UserAccountController extends Controller $this->setPageTitle(trans('preferences.shortcuts_interface')); return view('users.account.shortcuts', [ + 'category' => 'shortcuts', 'shortcuts' => $shortcuts, 'enabled' => $enabled, ]); @@ -68,7 +123,6 @@ class UserAccountController extends Controller public function showNotifications(PermissionApplicator $permissions) { $this->checkPermission('receive-notifications'); - $this->preventGuestAccess(); $preferences = (new UserNotificationPreferences(user())); @@ -79,6 +133,7 @@ class UserAccountController extends Controller $this->setPageTitle(trans('preferences.notifications')); return view('users.account.notifications', [ + 'category' => 'notifications', 'preferences' => $preferences, 'watches' => $watches, ]); @@ -89,8 +144,8 @@ class UserAccountController extends Controller */ public function updateNotifications(Request $request) { + $this->preventAccessInDemoMode(); $this->checkPermission('receive-notifications'); - $this->preventGuestAccess(); $data = $this->validate($request, [ 'preferences' => ['required', 'array'], 'preferences.*' => ['required', 'string'], @@ -102,4 +157,71 @@ class UserAccountController extends Controller return redirect('/my-account/notifications'); } + + /** + * 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->get('new_owner_id')) ?: null; + $newOwnerId = userCan('users-manage') ? $requestNewOwnerId : null; + + $this->userRepo->destroy(user(), $newOwnerId); + + return redirect('/'); + } }