]> BookStack Code Mirror - bookstack/blob - app/Http/Controllers/Auth/RegisterController.php
Standardised view referencing to dot-notation
[bookstack] / app / Http / Controllers / Auth / RegisterController.php
1 <?php
2
3 namespace BookStack\Http\Controllers\Auth;
4
5 use BookStack\Auth\SocialAccount;
6 use BookStack\Auth\User;
7 use BookStack\Auth\UserRepo;
8 use BookStack\Exceptions\SocialSignInAccountNotUsed;
9 use BookStack\Exceptions\SocialSignInException;
10 use BookStack\Exceptions\UserRegistrationException;
11 use BookStack\Http\Controllers\Controller;
12 use Exception;
13 use Illuminate\Foundation\Auth\RegistersUsers;
14 use Illuminate\Http\Request;
15 use Illuminate\Http\Response;
16 use Laravel\Socialite\Contracts\User as SocialUser;
17 use Validator;
18
19 class RegisterController extends Controller
20 {
21     /*
22     |--------------------------------------------------------------------------
23     | Register Controller
24     |--------------------------------------------------------------------------
25     |
26     | This controller handles the registration of new users as well as their
27     | validation and creation. By default this controller uses a trait to
28     | provide this functionality without requiring any additional code.
29     |
30     */
31
32     use RegistersUsers;
33
34     protected $socialAuthService;
35     protected $emailConfirmationService;
36     protected $userRepo;
37
38     /**
39      * Where to redirect users after login / registration.
40      *
41      * @var string
42      */
43     protected $redirectTo = '/';
44     protected $redirectPath = '/';
45
46     /**
47      * Create a new controller instance.
48      *
49      * @param \BookStack\Auth\Access\SocialAuthService $socialAuthService
50      * @param \BookStack\Auth\EmailConfirmationService $emailConfirmationService
51      * @param \BookStack\Auth\UserRepo $userRepo
52      */
53     public function __construct(\BookStack\Auth\Access\SocialAuthService $socialAuthService, \BookStack\Auth\Access\EmailConfirmationService $emailConfirmationService, UserRepo $userRepo)
54     {
55         $this->middleware('guest')->only(['getRegister', 'postRegister', 'socialRegister']);
56         $this->socialAuthService = $socialAuthService;
57         $this->emailConfirmationService = $emailConfirmationService;
58         $this->userRepo = $userRepo;
59         $this->redirectTo = baseUrl('/');
60         $this->redirectPath = baseUrl('/');
61         parent::__construct();
62     }
63
64     /**
65      * Get a validator for an incoming registration request.
66      *
67      * @param  array $data
68      * @return \Illuminate\Contracts\Validation\Validator
69      */
70     protected function validator(array $data)
71     {
72         return Validator::make($data, [
73             'name' => 'required|max:255',
74             'email' => 'required|email|max:255|unique:users',
75             'password' => 'required|min:6',
76         ]);
77     }
78
79     /**
80      * Check whether or not registrations are allowed in the app settings.
81      * @throws UserRegistrationException
82      */
83     protected function checkRegistrationAllowed()
84     {
85         if (!setting('registration-enabled')) {
86             throw new UserRegistrationException(trans('auth.registrations_disabled'), '/login');
87         }
88     }
89
90     /**
91      * Show the application registration form.
92      * @return Response
93      * @throws UserRegistrationException
94      */
95     public function getRegister()
96     {
97         $this->checkRegistrationAllowed();
98         $socialDrivers = $this->socialAuthService->getActiveDrivers();
99         return view('auth.register', ['socialDrivers' => $socialDrivers]);
100     }
101
102     /**
103      * Handle a registration request for the application.
104      * @param Request|\Illuminate\Http\Request $request
105      * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
106      * @throws UserRegistrationException
107      */
108     public function postRegister(Request $request)
109     {
110         $this->checkRegistrationAllowed();
111         $this->validator($request->all())->validate();
112
113         $userData = $request->all();
114         return $this->registerUser($userData);
115     }
116
117     /**
118      * Create a new user instance after a valid registration.
119      * @param  array  $data
120      * @return \BookStack\Auth\User
121      */
122     protected function create(array $data)
123     {
124         return User::create([
125             'name' => $data['name'],
126             'email' => $data['email'],
127             'password' => bcrypt($data['password']),
128         ]);
129     }
130
131     /**
132      * The registrations flow for all users.
133      * @param array $userData
134      * @param bool|false|SocialAccount $socialAccount
135      * @param bool $emailVerified
136      * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
137      * @throws UserRegistrationException
138      */
139     protected function registerUser(array $userData, $socialAccount = false, $emailVerified = false)
140     {
141         $registrationRestrict = setting('registration-restrict');
142
143         if ($registrationRestrict) {
144             $restrictedEmailDomains = explode(',', str_replace(' ', '', $registrationRestrict));
145             $userEmailDomain = $domain = substr(strrchr($userData['email'], "@"), 1);
146             if (!in_array($userEmailDomain, $restrictedEmailDomains)) {
147                 throw new UserRegistrationException(trans('auth.registration_email_domain_invalid'), '/register');
148             }
149         }
150
151         $newUser = $this->userRepo->registerNew($userData, $emailVerified);
152         if ($socialAccount) {
153             $newUser->socialAccounts()->save($socialAccount);
154         }
155
156         if ((setting('registration-confirmation') || $registrationRestrict) && !$emailVerified) {
157             $newUser->save();
158
159             try {
160                 $this->emailConfirmationService->sendConfirmation($newUser);
161             } catch (Exception $e) {
162                 session()->flash('error', trans('auth.email_confirm_send_error'));
163             }
164
165             return redirect('/register/confirm');
166         }
167
168         auth()->login($newUser);
169         session()->flash('success', trans('auth.register_success'));
170         return redirect($this->redirectPath());
171     }
172
173     /**
174      * Show the page to tell the user to check their email
175      * and confirm their address.
176      */
177     public function getRegisterConfirmation()
178     {
179         return view('auth.register-confirm');
180     }
181
182     /**
183      * Confirms an email via a token and logs the user into the system.
184      * @param $token
185      * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
186      * @throws UserRegistrationException
187      */
188     public function confirmEmail($token)
189     {
190         $confirmation = $this->emailConfirmationService->getEmailConfirmationFromToken($token);
191         $user = $confirmation->user;
192         $user->email_confirmed = true;
193         $user->save();
194         auth()->login($user);
195         session()->flash('success', trans('auth.email_confirm_success'));
196         $this->emailConfirmationService->deleteConfirmationsByUser($user);
197         return redirect($this->redirectPath);
198     }
199
200     /**
201      * Shows a notice that a user's email address has not been confirmed,
202      * Also has the option to re-send the confirmation email.
203      * @return \Illuminate\View\View
204      */
205     public function showAwaitingConfirmation()
206     {
207         return view('auth.user-unconfirmed');
208     }
209
210     /**
211      * Resend the confirmation email
212      * @param Request $request
213      * @return \Illuminate\View\View
214      */
215     public function resendConfirmation(Request $request)
216     {
217         $this->validate($request, [
218             'email' => 'required|email|exists:users,email'
219         ]);
220         $user = $this->userRepo->getByEmail($request->get('email'));
221
222         try {
223             $this->emailConfirmationService->sendConfirmation($user);
224         } catch (Exception $e) {
225             session()->flash('error', trans('auth.email_confirm_send_error'));
226             return redirect('/register/confirm');
227         }
228
229         session()->flash('success', trans('auth.email_confirm_resent'));
230         return redirect('/register/confirm');
231     }
232
233     /**
234      * Redirect to the social site for authentication intended to register.
235      * @param $socialDriver
236      * @return mixed
237      * @throws UserRegistrationException
238      * @throws \BookStack\Exceptions\SocialDriverNotConfigured
239      */
240     public function socialRegister($socialDriver)
241     {
242         $this->checkRegistrationAllowed();
243         session()->put('social-callback', 'register');
244         return $this->socialAuthService->startRegister($socialDriver);
245     }
246
247     /**
248      * The callback for social login services.
249      * @param $socialDriver
250      * @param Request $request
251      * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
252      * @throws SocialSignInException
253      * @throws UserRegistrationException
254      * @throws \BookStack\Exceptions\SocialDriverNotConfigured
255      */
256     public function socialCallback($socialDriver, Request $request)
257     {
258         if (!session()->has('social-callback')) {
259             throw new SocialSignInException(trans('errors.social_no_action_defined'), '/login');
260         }
261
262         // Check request for error information
263         if ($request->has('error') && $request->has('error_description')) {
264             throw new SocialSignInException(trans('errors.social_login_bad_response', [
265                 'socialAccount' => $socialDriver,
266                 'error' => $request->get('error_description'),
267             ]), '/login');
268         }
269
270         $action = session()->pull('social-callback');
271
272         // Attempt login or fall-back to register if allowed.
273         $socialUser = $this->socialAuthService->getSocialUser($socialDriver);
274         if ($action == 'login') {
275             try {
276                 return $this->socialAuthService->handleLoginCallback($socialDriver, $socialUser);
277             } catch (SocialSignInAccountNotUsed $exception) {
278                 if ($this->socialAuthService->driverAutoRegisterEnabled($socialDriver)) {
279                     return $this->socialRegisterCallback($socialDriver, $socialUser);
280                 }
281                 throw $exception;
282             }
283         }
284
285         if ($action == 'register') {
286             return $this->socialRegisterCallback($socialDriver, $socialUser);
287         }
288
289         return redirect()->back();
290     }
291
292     /**
293      * Detach a social account from a user.
294      * @param $socialDriver
295      * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
296      */
297     public function detachSocialAccount($socialDriver)
298     {
299         return $this->socialAuthService->detachSocialAccount($socialDriver);
300     }
301
302     /**
303      * Register a new user after a registration callback.
304      * @param string $socialDriver
305      * @param SocialUser $socialUser
306      * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
307      * @throws UserRegistrationException
308      */
309     protected function socialRegisterCallback(string $socialDriver, SocialUser $socialUser)
310     {
311         $socialUser = $this->socialAuthService->handleRegistrationCallback($socialDriver, $socialUser);
312         $socialAccount = $this->socialAuthService->fillSocialAccount($socialDriver, $socialUser);
313         $emailVerified = $this->socialAuthService->driverAutoConfirmEmailEnabled($socialDriver);
314
315         // Create an array of the user data to create a new user instance
316         $userData = [
317             'name' => $socialUser->getName(),
318             'email' => $socialUser->getEmail(),
319             'password' => str_random(30)
320         ];
321         return $this->registerUser($userData, $socialAccount, $emailVerified);
322     }
323 }