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