]> BookStack Code Mirror - bookstack/blob - app/Http/Controllers/UserController.php
Merge branch 'unicode' of git://github.com/kostasdizas/BookStack into kostasdizas...
[bookstack] / app / Http / Controllers / UserController.php
1 <?php namespace BookStack\Http\Controllers;
2
3 use BookStack\Auth\Access\SocialAuthService;
4 use BookStack\Auth\Access\UserInviteService;
5 use BookStack\Auth\User;
6 use BookStack\Auth\UserRepo;
7 use BookStack\Exceptions\UserUpdateException;
8 use BookStack\Uploads\ImageRepo;
9 use Illuminate\Http\Request;
10 use Illuminate\Http\Response;
11
12 class UserController extends Controller
13 {
14
15     protected $user;
16     protected $userRepo;
17     protected $inviteService;
18     protected $imageRepo;
19
20     /**
21      * UserController constructor.
22      * @param User $user
23      * @param UserRepo $userRepo
24      * @param UserInviteService $inviteService
25      * @param ImageRepo $imageRepo
26      */
27     public function __construct(User $user, UserRepo $userRepo, UserInviteService $inviteService, ImageRepo $imageRepo)
28     {
29         $this->user = $user;
30         $this->userRepo = $userRepo;
31         $this->inviteService = $inviteService;
32         $this->imageRepo = $imageRepo;
33         parent::__construct();
34     }
35
36     /**
37      * Display a listing of the users.
38      * @param Request $request
39      * @return Response
40      */
41     public function index(Request $request)
42     {
43         $this->checkPermission('users-manage');
44         $listDetails = [
45             'order' => $request->get('order', 'asc'),
46             'search' => $request->get('search', ''),
47             'sort' => $request->get('sort', 'name'),
48         ];
49         $users = $this->userRepo->getAllUsersPaginatedAndSorted(20, $listDetails);
50         $this->setPageTitle(trans('settings.users'));
51         $users->appends($listDetails);
52         return view('users.index', ['users' => $users, 'listDetails' => $listDetails]);
53     }
54
55     /**
56      * Show the form for creating a new user.
57      * @return Response
58      */
59     public function create()
60     {
61         $this->checkPermission('users-manage');
62         $authMethod = config('auth.method');
63         $roles = $this->userRepo->getAllRoles();
64         return view('users.create', ['authMethod' => $authMethod, 'roles' => $roles]);
65     }
66
67     /**
68      * Store a newly created user in storage.
69      * @param  Request $request
70      * @return Response
71      * @throws UserUpdateException
72      */
73     public function store(Request $request)
74     {
75         $this->checkPermission('users-manage');
76         $validationRules = [
77             'name'             => 'required',
78             'email'            => 'required|email|unique:users,email'
79         ];
80
81         $authMethod = config('auth.method');
82         $sendInvite = ($request->get('send_invite', 'false') === 'true');
83
84         if ($authMethod === 'standard' && !$sendInvite) {
85             $validationRules['password'] = 'required|min:6';
86             $validationRules['password-confirm'] = 'required|same:password';
87         } elseif ($authMethod === 'ldap') {
88             $validationRules['external_auth_id'] = 'required';
89         }
90         $this->validate($request, $validationRules);
91
92         $user = $this->user->fill($request->all());
93
94         if ($authMethod === 'standard') {
95             $user->password = bcrypt($request->get('password', str_random(32)));
96         } elseif ($authMethod === 'ldap') {
97             $user->external_auth_id = $request->get('external_auth_id');
98         }
99
100         $user->save();
101
102         if ($sendInvite) {
103             $this->inviteService->sendInvitation($user);
104         }
105
106         if ($request->filled('roles')) {
107             $roles = $request->get('roles');
108             $this->userRepo->setUserRoles($user, $roles);
109         }
110
111         $this->userRepo->downloadAndAssignUserAvatar($user);
112
113         return redirect('/settings/users');
114     }
115
116     /**
117      * Show the form for editing the specified user.
118      * @param  int              $id
119      * @param \BookStack\Auth\Access\SocialAuthService $socialAuthService
120      * @return Response
121      */
122     public function edit($id, SocialAuthService $socialAuthService)
123     {
124         $this->checkPermissionOrCurrentUser('users-manage', $id);
125
126         $user = $this->user->findOrFail($id);
127
128         $authMethod = ($user->system_name) ? 'system' : config('auth.method');
129
130         $activeSocialDrivers = $socialAuthService->getActiveDrivers();
131         $this->setPageTitle(trans('settings.user_profile'));
132         $roles = $this->userRepo->getAllRoles();
133         return view('users.edit', ['user' => $user, 'activeSocialDrivers' => $activeSocialDrivers, 'authMethod' => $authMethod, 'roles' => $roles]);
134     }
135
136     /**
137      * Update the specified user in storage.
138      * @param Request $request
139      * @param int $id
140      * @return Response
141      * @throws UserUpdateException
142      * @throws \BookStack\Exceptions\ImageUploadException
143      */
144     public function update(Request $request, $id)
145     {
146         $this->preventAccessForDemoUsers();
147         $this->checkPermissionOrCurrentUser('users-manage', $id);
148
149         $this->validate($request, [
150             'name'             => 'min:2',
151             'email'            => 'min:2|email|unique:users,email,' . $id,
152             'password'         => 'min:6|required_with:password_confirm',
153             'password-confirm' => 'same:password|required_with:password',
154             'setting'          => 'array',
155             'profile_image'    => $this->imageRepo->getImageValidationRules(),
156         ]);
157
158         $user = $this->userRepo->getById($id);
159         $user->fill($request->except(['email']));
160
161         // Email updates
162         if (userCan('users-manage') && $request->filled('email')) {
163             $user->email = $request->get('email');
164         }
165
166         // Role updates
167         if (userCan('users-manage') && $request->filled('roles')) {
168             $roles = $request->get('roles');
169             $this->userRepo->setUserRoles($user, $roles);
170         }
171
172         // Password updates
173         if ($request->filled('password')) {
174             $password = $request->get('password');
175             $user->password = bcrypt($password);
176         }
177
178         // External auth id updates
179         if ($this->currentUser->can('users-manage') && $request->filled('external_auth_id')) {
180             $user->external_auth_id = $request->get('external_auth_id');
181         }
182
183         // Save an user-specific settings
184         if ($request->filled('setting')) {
185             foreach ($request->get('setting') as $key => $value) {
186                 setting()->putUser($user, $key, $value);
187             }
188         }
189
190         // Save profile image if in request
191         if ($request->has('profile_image')) {
192             $imageUpload = $request->file('profile_image');
193             $this->imageRepo->destroyImage($user->avatar);
194             $image = $this->imageRepo->saveNew($imageUpload, 'user', $user->id);
195             $user->image_id = $image->id;
196         }
197
198         // Delete the profile image if set to
199         if ($request->has('profile_image_reset')) {
200             $this->imageRepo->destroyImage($user->avatar);
201         }
202
203         $user->save();
204         session()->flash('success', trans('settings.users_edit_success'));
205
206         $redirectUrl = userCan('users-manage') ? '/settings/users' : ('/settings/users/' . $user->id);
207         return redirect($redirectUrl);
208     }
209
210     /**
211      * Show the user delete page.
212      * @param int $id
213      * @return \Illuminate\View\View
214      */
215     public function delete($id)
216     {
217         $this->checkPermissionOrCurrentUser('users-manage', $id);
218
219         $user = $this->userRepo->getById($id);
220         $this->setPageTitle(trans('settings.users_delete_named', ['userName' => $user->name]));
221         return view('users.delete', ['user' => $user]);
222     }
223
224     /**
225      * Remove the specified user from storage.
226      * @param  int $id
227      * @return Response
228      * @throws \Exception
229      */
230     public function destroy($id)
231     {
232         $this->preventAccessForDemoUsers();
233         $this->checkPermissionOrCurrentUser('users-manage', $id);
234
235         $user = $this->userRepo->getById($id);
236
237         if ($this->userRepo->isOnlyAdmin($user)) {
238             session()->flash('error', trans('errors.users_cannot_delete_only_admin'));
239             return redirect($user->getEditUrl());
240         }
241
242         if ($user->system_name === 'public') {
243             session()->flash('error', trans('errors.users_cannot_delete_guest'));
244             return redirect($user->getEditUrl());
245         }
246
247         $this->userRepo->destroy($user);
248         session()->flash('success', trans('settings.users_delete_success'));
249
250         return redirect('/settings/users');
251     }
252
253     /**
254      * Show the user profile page
255      * @param $id
256      * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
257      */
258     public function showProfilePage($id)
259     {
260         $user = $this->userRepo->getById($id);
261
262         $userActivity = $this->userRepo->getActivity($user);
263         $recentlyCreated = $this->userRepo->getRecentlyCreated($user, 5, 0);
264         $assetCounts = $this->userRepo->getAssetCounts($user);
265
266         return view('users.profile', [
267             'user' => $user,
268             'activity' => $userActivity,
269             'recentlyCreated' => $recentlyCreated,
270             'assetCounts' => $assetCounts
271         ]);
272     }
273
274     /**
275      * Update the user's preferred book-list display setting.
276      * @param $id
277      * @param Request $request
278      * @return \Illuminate\Http\RedirectResponse
279      */
280     public function switchBookView($id, Request $request)
281     {
282         return $this->switchViewType($id, $request, 'books');
283     }
284
285     /**
286      * Update the user's preferred shelf-list display setting.
287      * @param $id
288      * @param Request $request
289      * @return \Illuminate\Http\RedirectResponse
290      */
291     public function switchShelfView($id, Request $request)
292     {
293         return $this->switchViewType($id, $request, 'bookshelves');
294     }
295
296     /**
297      * For a type of list, switch with stored view type for a user.
298      * @param integer $userId
299      * @param Request $request
300      * @param string $listName
301      * @return \Illuminate\Http\RedirectResponse
302      */
303     protected function switchViewType($userId, Request $request, string $listName)
304     {
305         $this->checkPermissionOrCurrentUser('users-manage', $userId);
306
307         $viewType = $request->get('view_type');
308         if (!in_array($viewType, ['grid', 'list'])) {
309             $viewType = 'list';
310         }
311
312         $user = $this->userRepo->getById($userId);
313         $key = $listName . '_view_type';
314         setting()->putUser($user, $key, $viewType);
315
316         return redirect()->back(302, [], "/settings/users/$userId");
317     }
318
319     /**
320      * Change the stored sort type for a particular view.
321      * @param string $id
322      * @param string $type
323      * @param Request $request
324      * @return \Illuminate\Http\RedirectResponse
325      */
326     public function changeSort(string $id, string $type, Request $request)
327     {
328         $validSortTypes = ['books', 'bookshelves'];
329         if (!in_array($type, $validSortTypes)) {
330             return redirect()->back(500);
331         }
332         return $this->changeListSort($id, $request, $type);
333     }
334
335     /**
336      * Update the stored section expansion preference for the given user.
337      * @param string $id
338      * @param string $key
339      * @param Request $request
340      * @return \Illuminate\Contracts\Routing\ResponseFactory|\Symfony\Component\HttpFoundation\Response
341      */
342     public function updateExpansionPreference(string $id, string $key, Request $request)
343     {
344         $this->checkPermissionOrCurrentUser('users-manage', $id);
345         $keyWhitelist = ['home-details'];
346         if (!in_array($key, $keyWhitelist)) {
347             return response("Invalid key", 500);
348         }
349
350         $newState = $request->get('expand', 'false');
351
352         $user = $this->user->findOrFail($id);
353         setting()->putUser($user, 'section_expansion#' . $key, $newState);
354         return response("", 204);
355     }
356
357     /**
358      * Changed the stored preference for a list sort order.
359      * @param int $userId
360      * @param Request $request
361      * @param string $listName
362      * @return \Illuminate\Http\RedirectResponse
363      */
364     protected function changeListSort(int $userId, Request $request, string $listName)
365     {
366         $this->checkPermissionOrCurrentUser('users-manage', $userId);
367
368         $sort = $request->get('sort');
369         if (!in_array($sort, ['name', 'created_at', 'updated_at'])) {
370             $sort = 'name';
371         }
372
373         $order = $request->get('order');
374         if (!in_array($order, ['asc', 'desc'])) {
375             $order = 'asc';
376         }
377
378         $user = $this->user->findOrFail($userId);
379         $sortKey = $listName . '_sort';
380         $orderKey = $listName . '_sort_order';
381         setting()->putUser($user, $sortKey, $sort);
382         setting()->putUser($user, $orderKey, $order);
383
384         return redirect()->back(302, [], "/settings/users/$userId");
385     }
386 }