]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - plugins/EmailRegistration/emailregister.php
Yoink the registration action
[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
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                     throw new ClientException(_('No confirmation code.'));
98                 }
99
100                 $this->invitation = Invitation::staticGet('code', $this->code);
101
102                 if (!empty($this->invitation)) {
103                     $this->state = self::CONFIRMINVITE;
104                 } else {
105                     $this->state = self::CONFIRMREGISTER;
106                     $this->confirmation = Confirm_address::staticGet('code', $this->code);
107
108                     if (empty($this->confirmation)) {
109                         throw new ClientException(_('No such confirmation code.'), 405);
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                         throw new ClientException(_('No such confirmation code.'), 405);
133                     }
134                 }
135             }
136         }
137
138         return true;
139     }
140
141     function title()
142     {
143         switch ($this->state) {
144         case self::NEWREGISTER:
145         case self::NEWEMAIL:
146             // TRANS: Title for registration page.
147             return _m('TITLE','Register');
148             break;
149         case self::SETPASSWORD:
150         case self::CONFIRMINVITE:
151         case self::CONFIRMREGISTER:
152             // TRANS: Title for page where to change password.
153             return _m('TITLE','Set password');
154             break;
155         }
156     }
157
158     /**
159      * Handler method
160      *
161      * @param array $argarray is ignored since it's now passed in in prepare()
162      *
163      * @return void
164      */
165
166     function handle($argarray=null)
167     {
168         switch ($this->state) {
169         case self::NEWREGISTER:
170             $this->showRegistrationForm();
171             break;
172         case self::NEWEMAIL:
173             $this->registerUser();
174             break;
175         case self::CONFIRMINVITE:
176             $this->confirmInvite();
177             break;
178         case self::CONFIRMREGISTER:
179             $this->confirmRegister();
180             break;
181         case self::SETPASSWORD:
182             $this->setPassword();
183             break;
184         }
185         return;
186     }
187
188     function showRegistrationForm()
189     {
190         $this->form = new EmailRegistrationForm($this, $this->email);
191         $this->showPage();
192     }
193
194     function registerUser()
195     {
196         $old = User::staticGet('email', $this->email);
197
198         if (!empty($old)) {
199             $this->error = sprintf(_('A user with that email address already exists. You can use the '.
200                                      '<a href="%s">password recovery</a> tool to recover a missing password.'),
201                                    common_local_url('recoverpassword'));
202             $this->showRegistrationForm();
203             break;
204         }
205
206         $valid = false;
207
208         if (Event::handle('StartValidateUserEmail', array(null, $this->email, &$valid))) {
209             $valid = Validate::email($this->email, common_config('email', 'check_domain'));
210             Event::handle('EndValidateUserEmail', array(null, $this->email, &$valid));
211         }
212
213         if (!$valid) {
214             $this->error = _('Not a valid email address.');
215             $this->showRegistrationForm();
216         }
217
218         $confirm = Confirm_address::getAddress($this->email, self::CONFIRMTYPE);
219
220         if (empty($confirm)) {
221             $confirm = Confirm_address::saveNew(null, $this->email, 'register');
222             $prompt = sprintf(_('An email was sent to %s to confirm that address. Check your email inbox for instructions.'),
223                               $this->email);
224         } else {
225             $prompt = sprintf(_('The address %s was already registered but not confirmed. The confirmation code was resent.'),
226                               $this->email);
227         }
228
229         $this->sendConfirmEmail($confirm);
230
231         $this->complete = $prompt;
232         
233         $this->showPage();
234     }
235
236     function confirmInvite()
237     {
238         $this->form = new ConfirmRegisterForm($this, $this->invitation->code);
239         $this->showPage();
240     }
241
242     function confirmRegister()
243     {
244         $this->form = new ConfirmRegisterForm($this, $this->confirmation->code);
245         $this->showPage();
246     }
247
248     function setPassword()
249     {
250         if (!$this->tos) {
251             $this->error = _('You must accept the terms of service and privacy policy to register.');
252             $this->form = new ConfirmRegisterForm($this, $this->code);
253             $this->showPage();
254             return;
255         }
256
257         if (!empty($this->invitation)) {
258             $email = $this->invitation->address;
259         } else if (!empty($this->confirmation)) {
260             $email = $this->confirmation->address;
261         } else {
262             throw new Exception('No confirmation thing.');
263         }
264
265         $nickname = $this->nicknameFromEmail($email);
266
267         $this->user = User::registerNew(array('nickname' => $nickname,
268                                               'email' => $email,
269                                               'email_confirmed' => true));
270
271         if (empty($this->user)) {
272             throw new Exception("Failed to register user.");
273         }
274
275         if (!empty($this->invitation)) {
276             $inviter = User::staticGet('id', $this->invitation->user_id);
277             if (!empty($inviter)) {
278                 Subscription::start($inviter->getProfile(),
279                                     $user->getProfile());
280             }
281
282             $this->invitation->delete();
283         } else if (!empty($this->confirmation)) {
284             $this->confirmation->delete();
285         } else {
286             throw new Exception('No confirmation thing.');
287         }
288
289         common_redirect(common_local_url('doc', array('file' => 'registered')),
290                         303);
291     }
292
293     function sendConfirmEmail($confirm, $new)
294     {
295         $sitename = common_config('site', 'name');
296
297         $recipients = array($confirm->address);
298
299         $headers['From'] = mail_notify_from();
300         $headers['To'] = trim($confirm->address);
301         $headers['Subject'] = sprintf(_('Confirm your registration on %1$s'), $sitename);
302
303         $body = sprintf(_('Someone (probably you) has requested an account on %1$s using this email address.'.
304                           "\n".
305                           'To confirm the address, click the following URL or copy it into the address bar of your browser.'.
306                           "\n".
307                           '%2$s'.
308                           "\n".
309                           'If it was not you, you can safely ignore this message.'),
310                         $sitename,
311                         common_local_url('register', array('code' => $confirm->code)));
312
313         mail_send($recipients, $headers, $body);
314     }
315
316     function showContent()
317     {
318         if ($this->complete) {
319             $this->elementStart('p', 'success');
320             $this->raw($this->complete);
321             $this->elementEnd('p');
322         } else {
323             if ($this->error) {
324                 $this->elementStart('p', 'error');
325                 $this->raw($this->error);
326                 $this->elementEnd('p');
327             }
328
329             if (!empty($this->form)) {
330                 $this->form->show();
331             }
332         }
333     }
334
335     /**
336      * Return true if read only.
337      *
338      * MAY override
339      *
340      * @param array $args other arguments
341      *
342      * @return boolean is read only action?
343      */
344
345     function isReadOnly($args)
346     {
347         return false;
348     }
349 }
350
351 class EmailRegistrationForm extends Form
352 {
353     protected $email;
354
355     function __construct($out, $email)
356     {
357         parent::__construct($out);
358         $this->email = $email;
359     }
360
361     function formData()
362     {
363         $this->out->element('p', 'instructions',
364                             _('Enter your email address to register for an account.'));
365                             
366         $this->out->elementStart('fieldset', array('id' => 'new_bookmark_data'));
367         $this->out->elementStart('ul', 'form_data');
368
369         $this->li();
370         $this->out->input('email',
371                           // TRANS: Field label on form for adding a new bookmark.
372                           _m('LABEL','E-mail address'),
373                           $this->email);
374         $this->unli();
375
376         $this->out->elementEnd('ul');
377         $this->out->elementEnd('fieldset');
378     }
379
380      function method()
381      {
382          return 'post';
383      }
384
385     /**
386      * Buttons for form actions
387      *
388      * Submit and cancel buttons (or whatever)
389      * Sub-classes should overload this to show their own buttons.
390      *
391      * @return void
392      */
393
394     function formActions()
395     {
396         // TRANS: Button text for action to save a new bookmark.
397         $this->out->submit('submit', _m('BUTTON', 'Register'));
398     }
399
400     /**
401      * ID of the form
402      *
403      * Should be unique on the page. Sub-classes should overload this
404      * to show their own IDs.
405      *
406      * @return int ID of the form
407      */
408
409     function id()
410     {
411         return 'form_email_registration';
412     }
413
414     /**
415      * Action of the form.
416      *
417      * URL to post to. Should be overloaded by subclasses to give
418      * somewhere to post to.
419      *
420      * @return string URL to post to
421      */
422
423     function action()
424     {
425         return common_local_url('register');
426     }
427
428     function formClass()
429     {
430         return 'form_email_registration';
431     }
432 }