]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - plugins/EmailRegistration/actions/emailregister.php
Merge commit 'refs/merge-requests/199' of git://gitorious.org/statusnet/mainline...
[quix0rs-gnu-social.git] / plugins / EmailRegistration / actions / emailregister.php
1 <?php
2 /**
3  * StatusNet - the distributed open-source microblogging tool
4  * Copyright (C) 2011, StatusNet, Inc.
5  *
6  * Register a user by their email address
7  *
8  * PHP version 5
9  *
10  * This program is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU Affero General Public License as published by
12  * the Free Software Foundation, either version 3 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Affero General Public License for more details.
19  *
20  * You should have received a copy of the GNU Affero General Public License
21  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
22  *
23  * @category  Email registration
24  * @package   StatusNet
25  * @author    Evan Prodromou <evan@status.net>
26  * @copyright 2011 StatusNet, Inc.
27  * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
28  * @link      http://status.net/
29  */
30
31 if (!defined('STATUSNET')) {
32     // This check helps protect against security problems;
33     // your code file can't be executed directly from the web.
34     exit(1);
35 }
36
37 /**
38  * Email registration
39  *
40  * There are four cases where we're called:
41  *
42  * 1. GET, no arguments. Initial registration; ask for an email address.
43  * 2. POST, email address argument. Initial registration; send an email to confirm.
44  * 3. GET, code argument. Confirming an invitation or a registration; look them up,
45  *    create the relevant user if possible, login as that user, and
46  *    show a password-entry form.
47  * 4. POST, password argument. After confirmation, set the password for the new
48  *    user, and redirect to a registration complete action with some instructions.
49  *
50  * @category  Action
51  * @package   StatusNet
52  * @author    Evan Prodromou <evan@status.net>
53  * @copyright 2011 StatusNet, Inc.
54  * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
55  * @link      http://status.net/
56  */
57 class EmailregisterAction extends Action
58 {
59     const NEWEMAIL = 1;
60     const SETPASSWORD = 2;
61     const NEWREGISTER = 3;
62     const CONFIRMINVITE = 4;
63     const CONFIRMREGISTER = 5;
64
65     const CONFIRMTYPE = 'register';
66
67     protected $user;
68     protected $email;
69     protected $code;
70     protected $invitation;
71     protected $confirmation;
72     protected $password1;
73     protected $password2;
74     protected $state;
75     protected $error;
76     protected $complete;
77
78     function prepare($argarray)
79     {
80         parent::prepare($argarray);
81
82         if (common_config('site', 'closed')) {
83             // TRANS: Client exception trown when registration by e-mail is not allowed.
84             throw new ClientException(_m('Registration not allowed.'), 403);
85         }
86
87         if ($this->isPost()) {
88
89             $this->checkSessionToken();
90
91             $this->email = $this->trimmed('email');
92
93             if (!empty($this->email)) {
94                 if (common_config('site', 'inviteonly')) {
95                     // TRANS: Client exception trown when trying to register without an invitation.
96                     throw new ClientException(_m('Sorry, only invited people can register.'), 403);
97                 }
98                 $this->email = common_canonical_email($this->email);
99                 $this->state = self::NEWEMAIL;
100             } else {
101                 $this->state = self::SETPASSWORD;
102
103                 $this->code = $this->trimmed('code');
104
105                 if (empty($this->code)) {
106                     // TRANS: Client exception thrown when no confirmation code was provided.
107                     throw new ClientException(_m('No confirmation code.'));
108                 }
109
110                 $this->invitation = Invitation::getKV('code', $this->code);
111
112                 if (!empty($this->invitation)) {
113                     if (!empty($this->invitation->registered_user_id)) {
114                         // TRANS: Client exception trown when using an invitation multiple times.
115                         throw new ClientException(_m('Invitation already used.'), 403);
116                     }
117                 } else {
118
119                     $this->confirmation = Confirm_address::getKV('code', $this->code);
120
121                     if (empty($this->confirmation)) {
122                         // TRANS: Client exception thrown when given confirmation code was not issued.
123                         throw new ClientException(_m('No such confirmation code.'), 403);
124                     }
125                 }
126
127                 $this->password1 = $this->trimmed('password1');
128                 $this->password2 = $this->trimmed('password2');
129
130                 $this->tos = $this->boolean('tos');
131             }
132         } else { // GET
133             $this->code = $this->trimmed('code');
134
135             if (empty($this->code)) {
136                 if (common_config('site', 'inviteonly')) {
137                     // TRANS: Client exception trown when trying to register without an invitation.
138                     throw new ClientException(_m('Sorry, only invited people can register.'), 403);
139                 }
140                 $this->state = self::NEWREGISTER;
141             } else {
142                 $this->invitation = Invitation::getKV('code', $this->code);
143                 if (!empty($this->invitation)) {
144                     if (!empty($this->invitation->registered_user_id)) {
145                         // TRANS: Client exception trown when using an invitation multiple times.
146                         throw new ClientException(_m('Invitation already used.'), 403);
147                     }
148                     $this->state = self::CONFIRMINVITE;
149                 } else {
150                     $this->state = self::CONFIRMREGISTER;
151                     $this->confirmation = Confirm_address::getKV('code', $this->code);
152
153                     if (empty($this->confirmation)) {
154                         // TRANS: Client exception thrown when given confirmation code was not issued.
155                         throw new ClientException(_m('No such confirmation code.'), 405);
156                     }
157                 }
158             }
159         }
160
161         return true;
162     }
163
164     function title()
165     {
166         switch ($this->state) {
167         case self::NEWREGISTER:
168         case self::NEWEMAIL:
169             // TRANS: Title for registration page.
170             return _m('TITLE','Register');
171             break;
172         case self::SETPASSWORD:
173         case self::CONFIRMINVITE:
174         case self::CONFIRMREGISTER:
175             // TRANS: Title for page where to register with a confirmation code.
176             return _m('TITLE','Complete registration');
177             break;
178         }
179     }
180
181     /**
182      * Handler method
183      *
184      * @param array $argarray is ignored since it's now passed in in prepare()
185      *
186      * @return void
187      */
188     function handle($argarray=null)
189     {
190         $cur = common_current_user();
191
192         if (!empty($cur)) {
193             common_redirect(common_local_url('all', array('nickname' => $cur->nickname)));
194         }
195
196         switch ($this->state) {
197         case self::NEWREGISTER:
198             $this->showRegistrationForm();
199             break;
200         case self::NEWEMAIL:
201             $this->registerUser();
202             break;
203         case self::CONFIRMINVITE:
204             $this->confirmRegistration();
205             break;
206         case self::CONFIRMREGISTER:
207             $this->confirmRegistration();
208             break;
209         case self::SETPASSWORD:
210             $this->setPassword();
211             break;
212         }
213         return;
214     }
215
216     function showRegistrationForm()
217     {
218         $this->form = new EmailRegistrationForm($this, $this->email);
219         $this->showPage();
220     }
221
222     function registerUser()
223     {
224         try {
225             $confirm = EmailRegistrationPlugin::registerEmail($this->email);
226         } catch (ClientException $ce) {
227             $this->error = $ce->getMessage();
228             $this->showRegistrationForm();
229             return;
230         }
231
232         EmailRegistrationPlugin::sendConfirmEmail($confirm);
233
234         // TRANS: Confirmation text after initial registration.
235         // TRANS: %s an e-mail address.
236         $prompt = sprintf(_m('An email was sent to %s to confirm that address. Check your email inbox for instructions.'),
237                           $this->email);
238
239         $this->complete = $prompt;
240
241         $this->showPage();
242     }
243
244     function confirmRegistration()
245     {
246         if (!empty($this->invitation)) {
247             $email = $this->invitation->address;
248         } else if (!empty($this->confirmation)) {
249             $email = $this->confirmation->address;
250         }
251
252         $nickname = $this->nicknameFromEmail($email);
253
254         $this->form = new ConfirmRegistrationForm($this,
255                                                   $nickname,
256                                                   $email,
257                                                   $this->code);
258         $this->showPage();
259     }
260
261     function setPassword()
262     {
263         if (Event::handle('StartRegistrationTry', array($this))) {
264             if (!empty($this->invitation)) {
265                 $email = trim($this->invitation->address);
266             } else if (!empty($this->confirmation)) {
267                 $email = trim($this->confirmation->address);
268             } else {
269                 // TRANS: Client exception trown when trying to set password with an invalid confirmation code.
270                 throw new Exception(_m('No confirmation thing.'));
271             }
272
273             if (!$this->tos) {
274                 // TRANS: Error text when trying to register without agreeing to the terms.
275                 $this->error = _m('You must accept the terms of service and privacy policy to register.');
276             } else if (empty($this->password1)) {
277                 // TRANS: Error text when trying to register without a password.
278                 $this->error = _m('You must set a password');
279             } else if (strlen($this->password1) < 6) {
280                 // TRANS: Error text when trying to register with too short a password.
281                 $this->error = _m('Password must be 6 or more characters.');
282             } else if ($this->password1 != $this->password2) {
283                 // TRANS: Error text when trying to register without providing the same password twice.
284                 $this->error = _m('Passwords do not match.');
285             }
286
287             if (!empty($this->error)) {
288                 $nickname = $this->nicknameFromEmail($email);
289                 $this->form = new ConfirmRegistrationForm($this, $nickname, $email, $this->code);
290                 $this->showPage();
291                 return;
292             }
293
294             $nickname = $this->nicknameFromEmail($email);
295
296             try {
297                 $fields = array('nickname' => $nickname,
298                                 'email' => $email,
299                                 'password' => $this->password1,
300                                 'email_confirmed' => true);
301
302                 if (!empty($this->invitation)) {
303                     $fields['code'] = $this->invitation->code;
304                 }
305                 $this->user = User::register($fields);
306             } catch (ClientException $e) {
307                 $this->error = $e->getMessage();
308                 $nickname = $this->nicknameFromEmail($email);
309                 $this->form = new ConfirmRegistrationForm($this, $nickname, $email, $this->code);
310                 $this->showPage();
311                 return;
312             }
313
314             if (empty($this->user)) {
315                 // TRANS: Exception trown when using an invitation multiple times.
316                 throw new Exception(_m('Failed to register user.'));
317             }
318
319             common_set_user($this->user);
320             // this is a real login
321             common_real_login(true);
322
323             // Re-init language env in case it changed (not yet, but soon)
324             common_init_language();
325
326             if (!empty($this->confirmation)) {
327                 $this->confirmation->delete();
328             }
329
330             Event::handle('EndRegistrationTry', array($this));
331         }
332
333         if (Event::handle('StartRegisterSuccess', array($this))) {
334             Event::handle('EndRegisterSuccess', array($this));
335             common_redirect(common_local_url('doc', array('title' => 'welcome')), 303);
336             // common_redirect exits, so we can't run the event _after_ it of course.
337         }
338     }
339
340     function sendConfirmEmail($confirm)
341     {
342         $sitename = common_config('site', 'name');
343
344         $recipients = array($confirm->address);
345
346         $headers['From'] = mail_notify_from();
347         $headers['To'] = trim($confirm->address);
348          // TRANS: Subject for confirmation e-mail.
349          // TRANS: %s is the StatusNet sitename.
350         $headers['Subject'] = sprintf(_m('Confirm your registration on %s'), $sitename);
351
352         $confirmUrl = common_local_url('register', array('code' => $confirm->code));
353
354         // TRANS: Body for confirmation e-mail.
355         // TRANS: %1$s is the StatusNet sitename, %2$s is the confirmation URL.
356         $body = sprintf(_m('Someone (probably you) has requested an account on %1$s using this email address.'.
357                           "\n".
358                           'To confirm the address, click the following URL or copy it into the address bar of your browser.'.
359                           "\n".
360                           '%2$s'.
361                           "\n".
362                           'If it was not you, you can safely ignore this message.'),
363                         $sitename,
364                         $confirmUrl);
365
366         mail_send($recipients, $headers, $body);
367     }
368
369     function showContent()
370     {
371         if ($this->complete) {
372             $this->elementStart('p', 'success');
373             $this->raw($this->complete);
374             $this->elementEnd('p');
375         } else {
376             if ($this->error) {
377                 $this->elementStart('p', 'error');
378                 $this->raw($this->error);
379                 $this->elementEnd('p');
380             }
381
382             if (!empty($this->form)) {
383                 $this->form->show();
384             }
385         }
386     }
387
388     /**
389      * Return true if read only.
390      *
391      * MAY override
392      *
393      * @param array $args other arguments
394      *
395      * @return boolean is read only action?
396      */
397     function isReadOnly($args)
398     {
399         return false;
400     }
401
402     function nicknameFromEmail($email)
403     {
404         return EmailRegistrationPlugin::nicknameFromEmail($email);
405     }
406
407     /**
408      * A local menu
409      *
410      * Shows different login/register actions.
411      *
412      * @return void
413      */
414     function showLocalNav()
415     {
416         $nav = new LoginGroupNav($this);
417         $nav->show();
418     }
419 }