]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - actions/profilesettings.php
Merge branch '0.9.x' into 1.0.x
[quix0rs-gnu-social.git] / actions / profilesettings.php
1 <?php
2 /**
3  * StatusNet, the distributed open-source microblogging tool
4  *
5  * Change profile settings
6  *
7  * PHP version 5
8  *
9  * LICENCE: This program is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU Affero General Public License as published by
11  * the Free Software Foundation, either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU Affero General Public License for more details.
18  *
19  * You should have received a copy of the GNU Affero General Public License
20  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21  *
22  * @category  Settings
23  * @package   StatusNet
24  * @author    Evan Prodromou <evan@status.net>
25  * @author    Zach Copley <zach@status.net>
26  * @author    Sarven Capadisli <csarven@status.net>
27  * @copyright 2008-2009 StatusNet, Inc.
28  * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
29  * @link      http://status.net/
30  */
31
32 if (!defined('STATUSNET') && !defined('LACONICA')) {
33     exit(1);
34 }
35
36
37
38 /**
39  * Change profile settings
40  *
41  * @category Settings
42  * @package  StatusNet
43  * @author   Evan Prodromou <evan@status.net>
44  * @author   Zach Copley <zach@status.net>
45  * @author   Sarven Capadisli <csarven@status.net>
46  * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
47  * @link     http://status.net/
48  */
49
50 class ProfilesettingsAction extends SettingsAction
51 {
52     /**
53      * Title of the page
54      *
55      * @return string Title of the page
56      */
57     function title()
58     {
59         // TRANS: Page title for profile settings.
60         return _('Profile settings');
61     }
62
63     /**
64      * Instructions for use
65      *
66      * @return instructions for use
67      */
68     function getInstructions()
69     {
70         // TRANS: Usage instructions for profile settings.
71         return _('You can update your personal profile info here '.
72                  'so people know more about you.');
73     }
74
75     function showScripts()
76     {
77         parent::showScripts();
78         $this->autofocus('nickname');
79     }
80
81     /**
82      * Content area of the page
83      *
84      * Shows a form for uploading an avatar.
85      *
86      * @return void
87      */
88     function showContent()
89     {
90         $user = common_current_user();
91         $profile = $user->getProfile();
92
93         $this->elementStart('form', array('method' => 'post',
94                                           'id' => 'form_settings_profile',
95                                           'class' => 'form_settings',
96                                           'action' => common_local_url('profilesettings')));
97         $this->elementStart('fieldset');
98         // TRANS: Profile settings form legend.
99         $this->element('legend', null, _('Profile information'));
100         $this->hidden('token', common_session_token());
101
102         // too much common patterns here... abstractable?
103         $this->elementStart('ul', 'form_data');
104         if (Event::handle('StartProfileFormData', array($this))) {
105             $this->elementStart('li');
106             // TRANS: Field label in form for profile settings.
107             $this->input('nickname', _('Nickname'),
108                          ($this->arg('nickname')) ? $this->arg('nickname') : $profile->nickname,
109                          // TRANS: Tooltip for field label in form for profile settings.
110                          _('1-64 lowercase letters or numbers, no punctuation or spaces.'));
111             $this->elementEnd('li');
112             $this->elementStart('li');
113             // TRANS: Field label in form for profile settings.
114             $this->input('fullname', _('Full name'),
115                          ($this->arg('fullname')) ? $this->arg('fullname') : $profile->fullname);
116             $this->elementEnd('li');
117             $this->elementStart('li');
118             // TRANS: Field label in form for profile settings.
119             $this->input('homepage', _('Homepage'),
120                          ($this->arg('homepage')) ? $this->arg('homepage') : $profile->homepage,
121                          // TRANS: Tooltip for field label in form for profile settings.
122                          _('URL of your homepage, blog, or profile on another site.'));
123             $this->elementEnd('li');
124             $this->elementStart('li');
125             $maxBio = Profile::maxBio();
126             if ($maxBio > 0) {
127                 // TRANS: Tooltip for field label in form for profile settings. Plural
128                 // TRANS: is decided by the number of characters available for the
129                 // TRANS: biography (%d).
130                 $bioInstr = sprintf(_m('Describe yourself and your interests in %d character',
131                                        'Describe yourself and your interests in %d characters',
132                                        $maxBio),
133                                     $maxBio);
134             } else {
135                 // TRANS: Tooltip for field label in form for profile settings.
136                 $bioInstr = _('Describe yourself and your interests');
137             }
138             // TRANS: Text area label in form for profile settings where users can provide.
139             // TRANS: their biography.
140             $this->textarea('bio', _('Bio'),
141                             ($this->arg('bio')) ? $this->arg('bio') : $profile->bio,
142                             $bioInstr);
143             $this->elementEnd('li');
144             $this->elementStart('li');
145             // TRANS: Field label in form for profile settings.
146             $this->input('location', _('Location'),
147                          ($this->arg('location')) ? $this->arg('location') : $profile->location,
148                          // TRANS: Tooltip for field label in form for profile settings.
149                          _('Where you are, like "City, State (or Region), Country"'));
150             $this->elementEnd('li');
151             if (common_config('location', 'share') == 'user') {
152                 $this->elementStart('li');
153                 // TRANS: Checkbox label in form for profile settings.
154                 $this->checkbox('sharelocation', _('Share my current location when posting notices'),
155                                 ($this->arg('sharelocation')) ?
156                                 $this->arg('sharelocation') : $user->shareLocation());
157                 $this->elementEnd('li');
158             }
159             Event::handle('EndProfileFormData', array($this));
160             $this->elementStart('li');
161             // TRANS: Field label in form for profile settings.
162             $this->input('tags', _('Tags'),
163                          ($this->arg('tags')) ? $this->arg('tags') : implode(' ', $user->getSelfTags()),
164                          // TRANS: Tooltip for field label in form for profile settings.
165                          _('Tags for yourself (letters, numbers, -, ., and _), comma- or space- separated.'));
166             $this->elementEnd('li');
167             $this->elementStart('li');
168             $language = common_language();
169             // TRANS: Dropdownlist label in form for profile settings.
170             $this->dropdown('language', _('Language'),
171                          // TRANS: Tooltip for dropdown list label in form for profile settings.
172                             get_nice_language_list(), _('Preferred language.'),
173                             false, $language);
174             $this->elementEnd('li');
175             $timezone = common_timezone();
176             $timezones = array();
177             foreach(DateTimeZone::listIdentifiers() as $k => $v) {
178                 $timezones[$v] = $v;
179             }
180             $this->elementStart('li');
181             // TRANS: Dropdownlist label in form for profile settings.
182             $this->dropdown('timezone', _('Timezone'),
183                          // TRANS: Tooltip for dropdown list label in form for profile settings.
184                             $timezones, _('What timezone are you normally in?'),
185                             true, $timezone);
186             $this->elementEnd('li');
187             $this->elementStart('li');
188             $this->checkbox('autosubscribe',
189                             // TRANS: Checkbox label in form for profile settings.
190                             _('Automatically subscribe to whoever '.
191                               'subscribes to me (best for non-humans).'),
192                             ($this->arg('autosubscribe')) ?
193                             $this->boolean('autosubscribe') : $user->autosubscribe);
194             $this->elementEnd('li');
195         }
196         $this->elementEnd('ul');
197         // TRANS: Button to save input in profile settings.
198         $this->submit('save', _m('BUTTON','Save'));
199
200         $this->elementEnd('fieldset');
201         $this->elementEnd('form');
202     }
203
204     /**
205      * Handle a post
206      *
207      * Validate input and save changes. Reload the form with a success
208      * or error message.
209      *
210      * @return void
211      */
212     function handlePost()
213     {
214         // CSRF protection
215         $token = $this->trimmed('token');
216         if (!$token || $token != common_session_token()) {
217             // TRANS: Form validation error.
218             $this->showForm(_('There was a problem with your session token. '.
219                               'Try again, please.'));
220             return;
221         }
222
223         if (Event::handle('StartProfileSaveForm', array($this))) {
224
225             try {
226                 $nickname = Nickname::normalize($this->trimmed('nickname'));
227             } catch (NicknameException $e) {
228                 $this->showForm($e->getMessage());
229                 return;
230             }
231
232             $fullname = $this->trimmed('fullname');
233             $homepage = $this->trimmed('homepage');
234             $bio = $this->trimmed('bio');
235             $location = $this->trimmed('location');
236             $autosubscribe = $this->boolean('autosubscribe');
237             $language = $this->trimmed('language');
238             $timezone = $this->trimmed('timezone');
239             $tagstring = $this->trimmed('tags');
240
241             // Some validation
242             if (!User::allowed_nickname($nickname)) {
243                 // TRANS: Validation error in form for profile settings.
244                 $this->showForm(_('Not a valid nickname.'));
245                 return;
246             } else if (!is_null($homepage) && (strlen($homepage) > 0) &&
247                        !Validate::uri($homepage, array('allowed_schemes' => array('http', 'https')))) {
248                 // TRANS: Validation error in form for profile settings.
249                 $this->showForm(_('Homepage is not a valid URL.'));
250                 return;
251             } else if (!is_null($fullname) && mb_strlen($fullname) > 255) {
252                 // TRANS: Validation error in form for profile settings.
253                 $this->showForm(_('Full name is too long (maximum 255 characters).'));
254                 return;
255             } else if (Profile::bioTooLong($bio)) {
256                 // TRANS: Validation error in form for profile settings.
257                 // TRANS: Plural form is used based on the maximum number of allowed
258                 // TRANS: characters for the biography (%d).
259                 $this->showForm(sprintf(_m('Bio is too long (maximum %d character).',
260                                            'Bio is too long (maximum %d characters).',
261                                            Profile::maxBio()),
262                                         Profile::maxBio()));
263                 return;
264             } else if (!is_null($location) && mb_strlen($location) > 255) {
265                 // TRANS: Validation error in form for profile settings.
266                 $this->showForm(_('Location is too long (maximum 255 characters).'));
267                 return;
268             }  else if (is_null($timezone) || !in_array($timezone, DateTimeZone::listIdentifiers())) {
269                 // TRANS: Validation error in form for profile settings.
270                 $this->showForm(_('Timezone not selected.'));
271                 return;
272             } else if ($this->nicknameExists($nickname)) {
273                 // TRANS: Validation error in form for profile settings.
274                 $this->showForm(_('Nickname already in use. Try another one.'));
275                 return;
276             } else if (!is_null($language) && strlen($language) > 50) {
277                 // TRANS: Validation error in form for profile settings.
278                 $this->showForm(_('Language is too long (maximum 50 characters).'));
279                 return;
280             }
281
282             if ($tagstring) {
283                 $tags = array_map('common_canonical_tag', preg_split('/[\s,]+/', $tagstring));
284             } else {
285                 $tags = array();
286             }
287
288             foreach ($tags as $tag) {
289                 if (!common_valid_profile_tag($tag)) {
290                     // TRANS: Validation error in form for profile settings.
291                     // TRANS: %s is an invalid tag.
292                     $this->showForm(sprintf(_('Invalid tag: "%s".'), $tag));
293                     return;
294                 }
295             }
296
297             $user = common_current_user();
298
299             $user->query('BEGIN');
300
301             if ($user->nickname != $nickname ||
302                 $user->language != $language ||
303                 $user->timezone != $timezone) {
304
305                 common_debug('Updating user nickname from ' . $user->nickname . ' to ' . $nickname,
306                              __FILE__);
307                 common_debug('Updating user language from ' . $user->language . ' to ' . $language,
308                              __FILE__);
309                 common_debug('Updating user timezone from ' . $user->timezone . ' to ' . $timezone,
310                              __FILE__);
311
312                 $original = clone($user);
313
314                 $user->nickname = $nickname;
315                 $user->language = $language;
316                 $user->timezone = $timezone;
317
318                 $result = $user->updateKeys($original);
319
320                 if ($result === false) {
321                     common_log_db_error($user, 'UPDATE', __FILE__);
322                     // TRANS: Server error thrown when user profile settings could not be updated.
323                     $this->serverError(_('Could not update user.'));
324                     return;
325                 } else {
326                     // Re-initialize language environment if it changed
327                     common_init_language();
328                     // Clear the site owner, in case nickname changed
329                     if ($user->hasRole(Profile_role::OWNER)) {
330                         User::blow('user:site_owner');
331                     }
332                 }
333             }
334
335             // XXX: XOR
336             if ($user->autosubscribe ^ $autosubscribe) {
337
338                 $original = clone($user);
339
340                 $user->autosubscribe = $autosubscribe;
341
342                 $result = $user->update($original);
343
344                 if ($result === false) {
345                     common_log_db_error($user, 'UPDATE', __FILE__);
346                     // TRANS: Server error thrown when user profile settings could not be updated to
347                     // TRANS: automatically subscribe to any subscriber.
348                     $this->serverError(_('Could not update user for autosubscribe.'));
349                     return;
350                 }
351             }
352
353             $profile = $user->getProfile();
354
355             $orig_profile = clone($profile);
356
357             $profile->nickname = $user->nickname;
358             $profile->fullname = $fullname;
359             $profile->homepage = $homepage;
360             $profile->bio = $bio;
361             $profile->location = $location;
362
363             $loc = Location::fromName($location);
364
365             if (empty($loc)) {
366                 $profile->lat         = null;
367                 $profile->lon         = null;
368                 $profile->location_id = null;
369                 $profile->location_ns = null;
370             } else {
371                 $profile->lat         = $loc->lat;
372                 $profile->lon         = $loc->lon;
373                 $profile->location_id = $loc->location_id;
374                 $profile->location_ns = $loc->location_ns;
375             }
376
377             $profile->profileurl = common_profile_url($nickname);
378
379             if (common_config('location', 'share') == 'user') {
380
381                 $exists = false;
382
383                 $prefs = User_location_prefs::staticGet('user_id', $user->id);
384
385                 if (empty($prefs)) {
386                     $prefs = new User_location_prefs();
387
388                     $prefs->user_id = $user->id;
389                     $prefs->created = common_sql_now();
390                 } else {
391                     $exists = true;
392                     $orig = clone($prefs);
393                 }
394
395                 $prefs->share_location = $this->boolean('sharelocation');
396
397                 if ($exists) {
398                     $result = $prefs->update($orig);
399                 } else {
400                     $result = $prefs->insert();
401                 }
402
403                 if ($result === false) {
404                     common_log_db_error($prefs, ($exists) ? 'UPDATE' : 'INSERT', __FILE__);
405                     // TRANS: Server error thrown when user profile location preference settings could not be updated.
406                     $this->serverError(_('Could not save location prefs.'));
407                     return;
408                 }
409             }
410
411             common_debug('Old profile: ' . common_log_objstring($orig_profile), __FILE__);
412             common_debug('New profile: ' . common_log_objstring($profile), __FILE__);
413
414             $result = $profile->update($orig_profile);
415
416             if ($result === false) {
417                 common_log_db_error($profile, 'UPDATE', __FILE__);
418                 // TRANS: Server error thrown when user profile settings could not be saved.
419                 $this->serverError(_('Could not save profile.'));
420                 return;
421             }
422
423             // Set the user tags
424             $result = $user->setSelfTags($tags);
425
426             if (!$result) {
427                 // TRANS: Server error thrown when user profile settings tags could not be saved.
428                 $this->serverError(_('Could not save tags.'));
429                 return;
430             }
431
432             $user->query('COMMIT');
433             Event::handle('EndProfileSaveForm', array($this));
434             common_broadcast_profile($profile);
435
436             // TRANS: Confirmation shown when user profile settings are saved.
437             $this->showForm(_('Settings saved.'), true);
438
439         }
440     }
441
442     function nicknameExists($nickname)
443     {
444         $user = common_current_user();
445         $other = User::staticGet('nickname', $nickname);
446         if (!$other) {
447             return false;
448         } else {
449             return $other->id != $user->id;
450         }
451     }
452
453     function showAside() {
454         $user = common_current_user();
455
456         $this->elementStart('div', array('id' => 'aside_primary',
457                                          'class' => 'aside'));
458
459         $this->elementStart('div', array('id' => 'account_actions',
460                                          'class' => 'section'));
461         $this->elementStart('ul');
462         if (Event::handle('StartProfileSettingsActions', array($this))) {
463             if ($user->hasRight(Right::BACKUPACCOUNT)) {
464                 $this->elementStart('li');
465                 $this->element('a',
466                                array('href' => common_local_url('backupaccount')),
467                                // TRANS: Option in profile settings to create a backup of the account of the currently logged in user.
468                                _('Backup account'));
469                 $this->elementEnd('li');
470             }
471             if ($user->hasRight(Right::DELETEACCOUNT)) {
472                 $this->elementStart('li');
473                 $this->element('a',
474                                array('href' => common_local_url('deleteaccount')),
475                                // TRANS: Option in profile settings to delete the account of the currently logged in user.
476                                _('Delete account'));
477                 $this->elementEnd('li');
478             }
479             if ($user->hasRight(Right::RESTOREACCOUNT)) {
480                 $this->elementStart('li');
481                 $this->element('a',
482                                array('href' => common_local_url('restoreaccount')),
483                                // TRANS: Option in profile settings to restore the account of the currently logged in user from a backup.
484                                _('Restore account'));
485                 $this->elementEnd('li');
486             }
487             Event::handle('EndProfileSettingsActions', array($this));
488         }
489         $this->elementEnd('ul');
490         $this->elementEnd('div');
491         $this->elementEnd('div');
492     }
493 }