]> BookStack Code Mirror - bookstack/blob - app/Users/Controllers/UserAccountController.php
Permissions: Fixed check method to allow enum usage
[bookstack] / app / Users / Controllers / UserAccountController.php
1 <?php
2
3 namespace BookStack\Users\Controllers;
4
5 use BookStack\Access\SocialDriverManager;
6 use BookStack\Http\Controller;
7 use BookStack\Permissions\Permission;
8 use BookStack\Permissions\PermissionApplicator;
9 use BookStack\Settings\UserNotificationPreferences;
10 use BookStack\Settings\UserShortcutMap;
11 use BookStack\Uploads\ImageRepo;
12 use BookStack\Users\UserRepo;
13 use Closure;
14 use Illuminate\Http\Request;
15 use Illuminate\Validation\Rules\Password;
16
17 class UserAccountController extends Controller
18 {
19     public function __construct(
20         protected UserRepo $userRepo,
21     ) {
22         $this->middleware(function (Request $request, Closure $next) {
23             $this->preventGuestAccess();
24             return $next($request);
25         });
26     }
27
28     /**
29      * Redirect the root my-account path to the main/first category.
30      * Required as a controller method, instead of the Route::redirect helper,
31      * to ensure the URL is generated correctly.
32      */
33     public function redirect()
34     {
35         return redirect('/my-account/profile');
36     }
37
38     /**
39      * Show the profile form interface.
40      */
41     public function showProfile()
42     {
43         $this->setPageTitle(trans('preferences.profile'));
44
45         return view('users.account.profile', [
46             'model' => user(),
47             'category' => 'profile',
48         ]);
49     }
50
51     /**
52      * Handle the submission of the user profile form.
53      */
54     public function updateProfile(Request $request, ImageRepo $imageRepo)
55     {
56         $this->preventAccessInDemoMode();
57
58         $user = user();
59         $validated = $this->validate($request, [
60             'name'             => ['min:2', 'max:100'],
61             'email'            => ['min:2', 'email', 'unique:users,email,' . $user->id],
62             'language'         => ['string', 'max:15', 'alpha_dash'],
63             'profile_image'    => array_merge(['nullable'], $this->getImageValidationRules()),
64         ]);
65
66         $this->userRepo->update($user, $validated, userCan(\BookStack\Permissions\Permission::UsersManage));
67
68         // Save profile image if in request
69         if ($request->hasFile('profile_image')) {
70             $imageUpload = $request->file('profile_image');
71             $imageRepo->destroyImage($user->avatar);
72             $image = $imageRepo->saveNew($imageUpload, 'user', $user->id);
73             $user->image_id = $image->id;
74             $user->save();
75         }
76
77         // Delete the profile image if reset option is in request
78         if ($request->has('profile_image_reset')) {
79             $imageRepo->destroyImage($user->avatar);
80             $user->image_id = 0;
81             $user->save();
82         }
83
84         return redirect('/my-account/profile');
85     }
86
87     /**
88      * Show the user-specific interface shortcuts.
89      */
90     public function showShortcuts()
91     {
92         $shortcuts = UserShortcutMap::fromUserPreferences();
93         $enabled = setting()->getForCurrentUser('ui-shortcuts-enabled', false);
94
95         $this->setPageTitle(trans('preferences.shortcuts_interface'));
96
97         return view('users.account.shortcuts', [
98             'category' => 'shortcuts',
99             'shortcuts' => $shortcuts,
100             'enabled' => $enabled,
101         ]);
102     }
103
104     /**
105      * Update the user-specific interface shortcuts.
106      */
107     public function updateShortcuts(Request $request)
108     {
109         $enabled = $request->get('enabled') === 'true';
110         $providedShortcuts = $request->get('shortcut', []);
111         $shortcuts = new UserShortcutMap($providedShortcuts);
112
113         setting()->putForCurrentUser('ui-shortcuts', $shortcuts->toJson());
114         setting()->putForCurrentUser('ui-shortcuts-enabled', $enabled);
115
116         $this->showSuccessNotification(trans('preferences.shortcuts_update_success'));
117
118         return redirect('/my-account/shortcuts');
119     }
120
121     /**
122      * Show the notification preferences for the current user.
123      */
124     public function showNotifications(PermissionApplicator $permissions)
125     {
126         $this->checkPermission(Permission::ReceiveNotifications);
127
128         $preferences = (new UserNotificationPreferences(user()));
129
130         $query = user()->watches()->getQuery();
131         $query = $permissions->restrictEntityRelationQuery($query, 'watches', 'watchable_id', 'watchable_type');
132         $query = $permissions->filterDeletedFromEntityRelationQuery($query, 'watches', 'watchable_id', 'watchable_type');
133         $watches = $query->with('watchable')->paginate(20);
134
135         $this->setPageTitle(trans('preferences.notifications'));
136         return view('users.account.notifications', [
137             'category' => 'notifications',
138             'preferences' => $preferences,
139             'watches' => $watches,
140         ]);
141     }
142
143     /**
144      * Update the notification preferences for the current user.
145      */
146     public function updateNotifications(Request $request)
147     {
148         $this->preventAccessInDemoMode();
149         $this->checkPermission(Permission::ReceiveNotifications);
150         $data = $this->validate($request, [
151            'preferences' => ['required', 'array'],
152            'preferences.*' => ['required', 'string'],
153         ]);
154
155         $preferences = (new UserNotificationPreferences(user()));
156         $preferences->updateFromSettingsArray($data['preferences']);
157         $this->showSuccessNotification(trans('preferences.notifications_update_success'));
158
159         return redirect('/my-account/notifications');
160     }
161
162     /**
163      * Show the view for the "Access & Security" account options.
164      */
165     public function showAuth(SocialDriverManager $socialDriverManager)
166     {
167         $mfaMethods = user()->mfaValues()->get()->groupBy('method');
168
169         $this->setPageTitle(trans('preferences.auth'));
170
171         return view('users.account.auth', [
172             'category' => 'auth',
173             'mfaMethods' => $mfaMethods,
174             'authMethod' => config('auth.method'),
175             'activeSocialDrivers' => $socialDriverManager->getActive(),
176         ]);
177     }
178
179     /**
180      * Handle the submission for the auth change password form.
181      */
182     public function updatePassword(Request $request)
183     {
184         $this->preventAccessInDemoMode();
185
186         if (config('auth.method') !== 'standard') {
187             $this->showPermissionError();
188         }
189
190         $validated = $this->validate($request, [
191             'password'         => ['required_with:password_confirm', Password::default()],
192             'password-confirm' => ['same:password', 'required_with:password'],
193         ]);
194
195         $this->userRepo->update(user(), $validated, false);
196
197         $this->showSuccessNotification(trans('preferences.auth_change_password_success'));
198
199         return redirect('/my-account/auth');
200     }
201
202     /**
203      * Show the user self-delete page.
204      */
205     public function delete()
206     {
207         $this->setPageTitle(trans('preferences.delete_my_account'));
208
209         return view('users.account.delete', [
210             'category' => 'profile',
211         ]);
212     }
213
214     /**
215      * Remove the current user from the system.
216      */
217     public function destroy(Request $request)
218     {
219         $this->preventAccessInDemoMode();
220
221         $requestNewOwnerId = intval($request->get('new_owner_id')) ?: null;
222         $newOwnerId = userCan(\BookStack\Permissions\Permission::UsersManage) ? $requestNewOwnerId : null;
223
224         $this->userRepo->destroy(user(), $newOwnerId);
225
226         return redirect('/');
227     }
228 }