]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - plugins/EmailRegistration/emailregister.php
Merge remote-tracking branch 'gitorious/1.0.x' into 1.0.x
[quix0rs-gnu-social.git] / plugins / EmailRegistration / 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 ($this->isPost()) {
83
84             $this->checkSessionToken();
85
86             $this->email = $this->trimmed('email');
87
88             if (!empty($this->email)) {
89                 $this->email = common_canonical_email($this->email);
90                 $this->state = self::NEWEMAIL;
91             } else {
92                 $this->state = self::SETPASSWORD;
93
94                 $this->code = $this->trimmed('code');
95
96                 if (empty($this->code)) {
97                     // TRANS: Client exception thrown when no confirmation code was provided.
98                     throw new ClientException(_m('No confirmation code.'));
99                 }
100
101                 $this->invitation = Invitation::staticGet('code', $this->code);
102
103                 if (empty($this->invitation)) {
104
105                     $this->confirmation = Confirm_address::staticGet('code', $this->code);
106
107                     if (empty($this->confirmation)) {
108                         // TRANS: Client exception thrown when given confirmation code was not issued.
109                         throw new ClientException(_m('No such confirmation code.'), 403);
110                     }
111                 }
112
113                 $this->password1 = $this->trimmed('password1');
114                 $this->password2 = $this->trimmed('password2');
115
116                 $this->tos = $this->boolean('tos');
117             }
118         } else { // GET
119             $this->code = $this->trimmed('code');
120
121             if (empty($this->code)) {
122                 $this->state = self::NEWREGISTER;
123             } else {
124                 $this->invitation = Invitation::staticGet('code', $this->code);
125                 if (!empty($this->invitation)) {
126                     $this->state = self::CONFIRMINVITE;
127                 } else {
128                     $this->state = self::CONFIRMREGISTER;
129                     $this->confirmation = Confirm_address::staticGet('code', $this->code);
130
131                     if (empty($this->confirmation)) {
132                         // TRANS: Client exception thrown when given confirmation code was not issued.
133                         throw new ClientException(_m('No such confirmation code.'), 405);
134                     }
135                 }
136             }
137         }
138
139         return true;
140     }
141
142     function title()
143     {
144         switch ($this->state) {
145         case self::NEWREGISTER:
146         case self::NEWEMAIL:
147             // TRANS: Title for registration page.
148             return _m('TITLE','Register');
149             break;
150         case self::SETPASSWORD:
151         case self::CONFIRMINVITE:
152         case self::CONFIRMREGISTER:
153             // TRANS: Title for page where to register with a confirmation code.
154             return _m('TITLE','Complete registration');
155             break;
156         }
157     }
158
159     /**
160      * Handler method
161      *
162      * @param array $argarray is ignored since it's now passed in in prepare()
163      *
164      * @return void
165      */
166
167     function handle($argarray=null)
168     {
169         $cur = common_current_user();
170
171         if (!empty($cur)) {
172             common_redirect(common_local_url('all', array('nickname' => $cur->nickname)));
173             return;
174         }
175
176         switch ($this->state) {
177         case self::NEWREGISTER:
178             $this->showRegistrationForm();
179             break;
180         case self::NEWEMAIL:
181             $this->registerUser();
182             break;
183         case self::CONFIRMINVITE:
184             $this->confirmRegistration();
185             break;
186         case self::CONFIRMREGISTER:
187             $this->confirmRegistration();
188             break;
189         case self::SETPASSWORD:
190             $this->setPassword();
191             break;
192         }
193         return;
194     }
195
196     function showRegistrationForm()
197     {
198         $this->form = new EmailRegistrationForm($this, $this->email);
199         $this->showPage();
200     }
201
202     function registerUser()
203     {
204         $old = User::staticGet('email', $this->email);
205
206         if (!empty($old)) {
207             // TRANS: Error text when trying to register with an already registered e-mail address.
208             $this->error = sprintf(_m('A user with that email address already exists. You can use the '.
209                                      '<a href="%s">password recovery</a> tool to recover a missing password.'),
210                                    common_local_url('recoverpassword'));
211             $this->showRegistrationForm();
212             return;
213         }
214
215         $valid = false;
216
217         try {
218             if (Event::handle('StartValidateUserEmail', array(null, $this->email, &$valid))) {
219                 $valid = Validate::email($this->email, common_config('email', 'check_domain'));
220                 Event::handle('EndValidateUserEmail', array(null, $this->email, &$valid));
221             }
222             if (!$valid) {
223                 // TRANS: Error text when trying to register with an invalid e-mail address.
224                 $this->error = _m('Not a valid email address.');
225                 $this->showRegistrationForm();
226                 return;
227             }
228         } catch (ClientException $e) {
229             $this->error = $e->getMessage();
230             $this->showRegistrationForm();
231             return;
232         }
233
234         $confirm = Confirm_address::getAddress($this->email, self::CONFIRMTYPE);
235
236         if (empty($confirm)) {
237             $confirm = Confirm_address::saveNew(null, $this->email, 'register');
238             // TRANS: Confirmation text after initial registration.
239             $prompt = sprintf(_m('An email was sent to %s to confirm that address. Check your email inbox for instructions.'),
240                               $this->email);
241         } else {
242             // TRANS: Confirmation text after re-requesting an e-mail confirmation code.
243             $prompt = sprintf(_m('The address %s was already registered but not confirmed. The confirmation code was resent.'),
244                               $this->email);
245         }
246
247         $this->sendConfirmEmail($confirm);
248
249         $this->complete = $prompt;
250
251         $this->showPage();
252     }
253
254     function confirmRegistration()
255     {
256         if (!empty($this->invitation)) {
257             $email = $this->invitation->address;
258         } else if (!empty($this->confirmation)) {
259             $email = $this->confirmation->address;
260         }
261
262         $nickname = $this->nicknameFromEmail($email);
263
264         $this->form = new ConfirmRegistrationForm($this,
265                                                   $nickname,
266                                                   $email,
267                                                   $this->code);
268         $this->showPage();
269     }
270
271     function setPassword()
272     {
273         if (!empty($this->invitation)) {
274             $email = $this->invitation->address;
275         } else if (!empty($this->confirmation)) {
276             $email = $this->confirmation->address;
277         } else {
278             throw new Exception('No confirmation thing.');
279         }
280
281         if (!$this->tos) {
282             $this->error = _('You must accept the terms of service and privacy policy to register.');
283             return;
284         } else if (empty($this->password1)) {
285             $this->error = _('You must set a password');
286         } else if (strlen($this->password1) < 6) {
287             $this->error = _('Password must be 6 or more characters.');
288         } else if ($this->password1 != $this->password2) {
289             $this->error = _('Passwords do not match.');
290         }
291
292         if (!empty($this->error)) {
293             $nickname = $this->nicknameFromEmail($email);
294             $this->form = new ConfirmRegistrationForm($this, $nickname, $this->email, $this->code);
295             $this->showPage();
296             return;
297         }
298
299         $nickname = $this->nicknameFromEmail($email);
300
301         try {
302             $this->user = User::register(array('nickname' => $nickname,
303                                                'email' => $email,
304                                                'password' => $this->password1,
305                                                'email_confirmed' => true));
306         } catch (ClientException $e) {
307             $this->error = $e->getMessage();
308             $nickname = $this->nicknameFromEmail($email);
309             $this->form = new ConfirmRegistrationForm($this, $nickname, $this->email, $this->code);
310             $this->showPage();
311             return;
312         }
313
314         if (empty($this->user)) {
315             throw new Exception("Failed to register user.");
316         }
317
318         common_set_user($this->user);
319         // this is a real login
320         common_real_login(true);
321
322         // Re-init language env in case it changed (not yet, but soon)
323         common_init_language();
324
325         if (!empty($this->invitation)) {
326             $inviter = User::staticGet('id', $this->invitation->user_id);
327             if (!empty($inviter)) {
328                 Subscription::start($inviter->getProfile(),
329                                     $this->user->getProfile());
330             }
331
332             $this->invitation->delete();
333         } else if (!empty($this->confirmation)) {
334             $this->confirmation->delete();
335         } else {
336             throw new Exception('No confirmation thing.');
337         }
338
339         common_redirect(common_local_url('doc', array('title' => 'welcome')),
340                         303);
341     }
342
343     function sendConfirmEmail($confirm)
344     {
345         $sitename = common_config('site', 'name');
346
347         $recipients = array($confirm->address);
348
349         $headers['From'] = mail_notify_from();
350         $headers['To'] = trim($confirm->address);
351          // TRANS: Subject for confirmation e-mail.
352          // TRANS: %s is the StatusNet sitename.
353         $headers['Subject'] = sprintf(_m('Confirm your registration on %s'), $sitename);
354
355         $confirmUrl = common_local_url('register', array('code' => $confirm->code));
356
357          // TRANS: Body for confirmation e-mail.
358          // TRANS: %1$s is the StatusNet sitename, %2$s is the confirmation URL.
359         $body = sprintf(_m('Someone (probably you) has requested an account on %1$s using this email address.'.
360                           "\n".
361                           'To confirm the address, click the following URL or copy it into the address bar of your browser.'.
362                           "\n".
363                           '%2$s'.
364                           "\n".
365                           'If it was not you, you can safely ignore this message.'),
366                         $sitename,
367                         $confirmUrl);
368
369         mail_send($recipients, $headers, $body);
370     }
371
372     function showContent()
373     {
374         if ($this->complete) {
375             $this->elementStart('p', 'success');
376             $this->raw($this->complete);
377             $this->elementEnd('p');
378         } else {
379             if ($this->error) {
380                 $this->elementStart('p', 'error');
381                 $this->raw($this->error);
382                 $this->elementEnd('p');
383             }
384
385             if (!empty($this->form)) {
386                 $this->form->show();
387             }
388         }
389     }
390
391     /**
392      * Return true if read only.
393      *
394      * MAY override
395      *
396      * @param array $args other arguments
397      *
398      * @return boolean is read only action?
399      */
400     function isReadOnly($args)
401     {
402         return false;
403     }
404
405     function nicknameFromEmail($email)
406     {
407         $parts = explode('@', $email);
408
409         $nickname = $parts[0];
410
411         $nickname = preg_replace('/[^A-Za-z0-9]/', '', $nickname);
412
413         $nickname = Nickname::normalize($nickname);
414
415         $original = $nickname;
416
417         $n = 0;
418
419         while (User::staticGet('nickname', $nickname)) {
420             $n++;
421             $nickname = $original . $n;
422         }
423
424         return $nickname;
425     }
426
427     /**
428      * A local menu
429      *
430      * Shows different login/register actions.
431      *
432      * @return void
433      */
434     function showLocalNav()
435     {
436         $nav = new LoginGroupNav($this);
437         $nav->show();
438     }
439 }