1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* This file has the primary job of showing and editing people's profiles. |
5
|
|
|
* It also allows the user to change some of their or another's preferences, |
6
|
|
|
* and such things. |
7
|
|
|
* |
8
|
|
|
* @name ElkArte Forum |
9
|
|
|
* @copyright ElkArte Forum contributors |
10
|
|
|
* @license BSD http://opensource.org/licenses/BSD-3-Clause |
11
|
|
|
* |
12
|
|
|
* This file contains code covered by: |
13
|
|
|
* copyright: 2011 Simple Machines (http://www.simplemachines.org) |
14
|
|
|
* license: BSD, See included LICENSE.TXT for terms and conditions. |
15
|
|
|
* |
16
|
|
|
* @version 2.0 dev |
17
|
|
|
* |
18
|
|
|
*/ |
19
|
|
|
|
20
|
|
|
/** |
21
|
|
|
* Profile_Controller class |
22
|
|
|
* Has the job of showing and editing people's profiles. |
23
|
|
|
*/ |
24
|
|
|
class Profile_Controller extends Action_Controller |
25
|
|
|
{ |
26
|
|
|
/** |
27
|
|
|
* If the save was successful or not |
28
|
|
|
* @var boolean |
29
|
|
|
*/ |
30
|
|
|
private $_completed_save = false; |
31
|
|
|
|
32
|
|
|
/** |
33
|
|
|
* If this was a request to save an update |
34
|
|
|
* @var null |
35
|
|
|
*/ |
36
|
|
|
private $_saving = null; |
37
|
|
|
|
38
|
|
|
/** |
39
|
|
|
* What it says, on completion |
40
|
|
|
* @var bool |
41
|
|
|
*/ |
42
|
|
|
private $_force_redirect; |
43
|
|
|
|
44
|
|
|
/** |
45
|
|
|
* Holds the output of createMenu for the profile areas |
46
|
|
|
* @var array|boolean |
47
|
|
|
*/ |
48
|
|
|
private $_profile_include_data; |
49
|
|
|
|
50
|
|
|
/** |
51
|
|
|
* The current area chosen from the menu |
52
|
|
|
* @var string |
53
|
|
|
*/ |
54
|
|
|
private $_current_area; |
55
|
|
|
|
56
|
|
|
/** |
57
|
|
|
* Member id for the history being viewed |
58
|
|
|
* @var int |
59
|
|
|
*/ |
60
|
|
|
private $_memID = 0; |
61
|
|
|
|
62
|
|
|
/** |
63
|
|
|
* The array from $user_profile stored here to avoid some global |
64
|
|
|
* @var mixed[] |
65
|
|
|
*/ |
66
|
|
|
private $_profile = []; |
67
|
|
|
|
68
|
|
|
/** |
69
|
|
|
* Called before all other methods when coming from the dispatcher or |
70
|
|
|
* action class. |
71
|
|
|
*/ |
72
|
1 |
View Code Duplication |
public function pre_dispatch() |
73
|
|
|
{ |
74
|
1 |
|
global $user_profile; |
75
|
|
|
|
76
|
1 |
|
require_once(SUBSDIR . '/Menu.subs.php'); |
77
|
1 |
|
require_once(SUBSDIR . '/Profile.subs.php'); |
78
|
|
|
|
79
|
1 |
|
$this->_memID = currentMemberID(); |
80
|
1 |
|
$this->_profile = $user_profile[$this->_memID]; |
81
|
1 |
|
} |
82
|
|
|
|
83
|
|
|
/** |
84
|
|
|
* Allow the change or view of profiles. |
85
|
|
|
* |
86
|
|
|
* - Fires the pre_load event |
87
|
|
|
* |
88
|
|
|
* @see Action_Controller::action_index() |
89
|
|
|
*/ |
90
|
1 |
|
public function action_index() |
91
|
|
|
{ |
92
|
1 |
|
global $txt, $user_info, $context, $cur_profile, $memberContext; |
93
|
1 |
|
global $profile_vars, $post_errors; |
94
|
|
|
|
95
|
|
|
// Don't reload this as we may have processed error strings. |
96
|
1 |
|
if (empty($post_errors)) |
97
|
1 |
|
theme()->getTemplates()->loadLanguageFile('Profile'); |
98
|
1 |
|
theme()->getTemplates()->load('Profile'); |
99
|
|
|
|
100
|
|
|
// Trigger profile pre-load event |
101
|
1 |
|
$this->_events->trigger('pre_load', array('post_errors' => $post_errors)); |
102
|
|
|
|
103
|
|
|
// A little bit about this member |
104
|
1 |
|
$context['id_member'] = $this->_memID; |
105
|
1 |
|
$cur_profile = $this->_profile; |
106
|
|
|
|
107
|
|
|
// Let's have some information about this member ready, too. |
108
|
1 |
|
loadMemberContext($this->_memID); |
109
|
1 |
|
$context['member'] = $memberContext[$this->_memID]; |
110
|
|
|
|
111
|
|
|
// Is this the profile of the user himself or herself? |
112
|
1 |
|
$context['user']['is_owner'] = (int) $this->_memID === (int) $user_info['id']; |
113
|
|
|
|
114
|
|
|
// Create the menu of profile options |
115
|
1 |
|
$this->_define_profile_menu(); |
116
|
|
|
|
117
|
|
|
// Is there an updated message to show? |
118
|
1 |
|
if (isset($this->_req->query->updated)) |
119
|
|
|
$context['profile_updated'] = $txt['profile_updated_own']; |
120
|
|
|
|
121
|
|
|
// If it said no permissions that meant it wasn't valid! |
122
|
1 |
|
if ($this->_profile_include_data && empty($this->_profile_include_data['permission'])) |
123
|
|
|
$this->_profile_include_data['enabled'] = false; |
124
|
|
|
|
125
|
|
|
// No menu and guest? A warm welcome to register |
126
|
1 |
|
if (!$this->_profile_include_data && $user_info['is_guest']) |
127
|
|
|
is_not_guest(); |
128
|
|
|
|
129
|
|
|
// No menu means no access at all. |
130
|
1 |
|
if (!$this->_profile_include_data || (isset($this->_profile_include_data['enabled']) && $this->_profile_include_data['enabled'] === false)) |
131
|
|
|
throw new Elk_Exception('no_access', false); |
132
|
|
|
|
133
|
|
|
// Make a note of the Unique ID for this menu. |
134
|
1 |
|
$context['profile_menu_id'] = $context['max_menu_id']; |
135
|
1 |
|
$context['profile_menu_name'] = 'menu_data_' . $context['profile_menu_id']; |
136
|
|
|
|
137
|
|
|
// Set the selected item - now it's been validated. |
138
|
1 |
|
$this->_current_area = $this->_profile_include_data['current_area']; |
139
|
1 |
|
$context['menu_item_selected'] = $this->_current_area; |
140
|
|
|
|
141
|
|
|
// Before we go any further, let's work on the area we've said is valid. |
142
|
|
|
// Note this is done here just in case we ever compromise the menu function in error! |
143
|
1 |
|
$this->_completed_save = false; |
144
|
1 |
|
$context['do_preview'] = isset($this->_req->post->preview_signature); |
145
|
|
|
|
146
|
|
|
// Are we saving data in a valid area? |
147
|
1 |
|
$this->_saving = $this->_req->getPost('save', 'trim', $this->_req->getQuery('save', 'trim', null)); |
148
|
1 |
|
if (isset($this->_profile_include_data['sc']) && (isset($this->_saving) || $context['do_preview'])) |
149
|
|
|
{ |
150
|
|
|
checkSession($this->_profile_include_data['sc']); |
151
|
|
|
$this->_completed_save = true; |
152
|
|
|
} |
153
|
|
|
|
154
|
|
|
// Permissions for good measure. |
155
|
1 |
|
if (!empty($this->_profile_include_data['permission'])) |
156
|
1 |
|
isAllowedTo($this->_profile_include_data['permission'][$context['user']['is_owner'] ? 'own' : 'any']); |
157
|
|
|
|
158
|
|
|
// Session validation and/or Token Checks |
159
|
1 |
|
$this->_check_access(); |
160
|
|
|
|
161
|
|
|
// Build the link tree. |
162
|
1 |
|
$this->_build_profile_linktree(); |
163
|
|
|
|
164
|
|
|
// Set the template for this area... if you still can :P |
165
|
|
|
// and add the profile layer. |
166
|
1 |
|
$context['sub_template'] = $this->_profile_include_data['function']; |
167
|
1 |
|
theme()->getLayers()->add('profile'); |
168
|
|
|
|
169
|
|
|
// Need JS if we made it this far |
170
|
1 |
|
loadJavascriptFile('profile.js'); |
171
|
|
|
|
172
|
|
|
// Right - are we saving - if so let's save the old data first. |
173
|
1 |
|
$this->_save_updates(); |
174
|
|
|
|
175
|
|
|
// Have some errors for some reason? |
176
|
|
|
// @todo check that this can be safely removed. |
177
|
1 |
|
if (!empty($post_errors)) |
178
|
|
|
{ |
179
|
|
|
// Set all the errors so the template knows what went wrong. |
180
|
|
|
foreach ($post_errors as $error_type) |
181
|
|
|
$context['modify_error'][$error_type] = true; |
182
|
|
|
} |
183
|
|
|
// If it's you then we should redirect upon save. |
184
|
1 |
|
elseif (!empty($profile_vars) && $context['user']['is_owner'] && !$context['do_preview']) |
185
|
|
|
redirectexit('action=profile;area=' . $this->_current_area . ';updated'); |
186
|
1 |
|
elseif (!empty($this->_force_redirect)) |
187
|
|
|
redirectexit('action=profile' . ($context['user']['is_owner'] ? '' : ';u=' . $this->_memID) . ';area=' . $this->_current_area); |
188
|
|
|
|
189
|
|
|
// Let go to the right place |
190
|
1 |
|
if (isset($this->_profile_include_data['file'])) |
191
|
|
|
require_once($this->_profile_include_data['file']); |
192
|
|
|
|
193
|
1 |
|
callMenu($this->_profile_include_data); |
|
|
|
|
194
|
|
|
|
195
|
|
|
// Set the page title if it's not already set... |
196
|
1 |
|
if (!isset($context['page_title'])) |
197
|
|
|
$context['page_title'] = $txt['profile'] . (isset($txt[$this->_current_area]) ? ' - ' . $txt[$this->_current_area] : ''); |
198
|
1 |
|
} |
199
|
|
|
|
200
|
|
|
/** |
201
|
|
|
* Define all the sections within the profile area! |
202
|
|
|
* |
203
|
|
|
* We start by defining the permission required - then we take this and turn |
204
|
|
|
* it into the relevant context ;) |
205
|
|
|
* |
206
|
|
|
* Possible fields: |
207
|
|
|
* For Section: |
208
|
|
|
* - string $title: Section title. |
209
|
|
|
* - array $areas: Array of areas within this section. |
210
|
|
|
* |
211
|
|
|
* For Areas: |
212
|
|
|
* - string $label: Text string that will be used to show the area in the menu. |
213
|
|
|
* - string $file: Optional text string that may contain a file name that's needed for inclusion in order to display the area properly. |
214
|
|
|
* - string $custom_url: Optional href for area. |
215
|
|
|
* - string $function: Function to execute for this section. |
216
|
|
|
* - bool $enabled: Should area be shown? |
217
|
|
|
* - string $sc: Session check validation to do on save - note without this save will get unset - if set. |
218
|
|
|
* - bool $hidden: Does this not actually appear on the menu? |
219
|
|
|
* - bool $password: Whether to require the user's password in order to save the data in the area. |
220
|
|
|
* - array $subsections: Array of subsections, in order of appearance. |
221
|
|
|
* - array $permission: Array of permissions to determine who can access this area. Should contain arrays $own and $any. |
222
|
|
|
*/ |
223
|
1 |
|
private function _define_profile_menu() |
224
|
|
|
{ |
225
|
1 |
|
global $txt, $context, $modSettings; |
226
|
|
|
|
227
|
|
|
$profile_areas = array( |
228
|
1 |
|
'info' => array( |
229
|
1 |
|
'title' => $txt['profileInfo'], |
230
|
|
|
'areas' => array( |
231
|
|
|
'summary' => array( |
232
|
1 |
|
'label' => $txt['summary'], |
233
|
1 |
|
'controller' => 'ProfileInfo_Controller', |
234
|
1 |
|
'function' => 'action_summary', |
235
|
|
|
// From the summary it's possible to activate an account, so we need the token |
236
|
1 |
|
'token' => 'profile-aa%u', |
237
|
1 |
|
'token_type' => 'get', |
238
|
|
|
'permission' => array( |
239
|
|
|
'own' => 'profile_view_own', |
240
|
|
|
'any' => 'profile_view_any', |
241
|
|
|
), |
242
|
|
|
), |
243
|
|
|
'statistics' => array( |
244
|
1 |
|
'label' => $txt['statPanel'], |
245
|
1 |
|
'controller' => 'ProfileInfo_Controller', |
246
|
1 |
|
'function' => 'action_statPanel', |
247
|
|
|
'permission' => array( |
248
|
|
|
'own' => 'profile_view_own', |
249
|
|
|
'any' => 'profile_view_any', |
250
|
|
|
), |
251
|
|
|
), |
252
|
|
|
'showposts' => array( |
253
|
1 |
|
'label' => $txt['showPosts'], |
254
|
1 |
|
'controller' => 'ProfileInfo_Controller', |
255
|
1 |
|
'function' => 'action_showPosts', |
256
|
|
|
'subsections' => array( |
257
|
1 |
|
'messages' => array($txt['showMessages'], array('profile_view_own', 'profile_view_any')), |
258
|
1 |
|
'topics' => array($txt['showTopics'], array('profile_view_own', 'profile_view_any')), |
259
|
1 |
|
'unwatchedtopics' => array($txt['showUnwatched'], array('profile_view_own', 'profile_view_any'), 'enabled' => $modSettings['enable_unwatch'] && $context['user']['is_owner']), |
260
|
1 |
|
'attach' => array($txt['showAttachments'], array('profile_view_own', 'profile_view_any')), |
261
|
|
|
), |
262
|
|
|
'permission' => array( |
263
|
|
|
'own' => 'profile_view_own', |
264
|
|
|
'any' => 'profile_view_any', |
265
|
|
|
), |
266
|
|
|
), |
267
|
|
|
'showlikes' => array( |
268
|
1 |
|
'label' => $txt['likes_show'], |
269
|
1 |
|
'controller' => 'Likes_Controller', |
270
|
1 |
|
'function' => 'action_showProfileLikes', |
271
|
1 |
|
'enabled' => !empty($modSettings['likes_enabled']) && $context['user']['is_owner'], |
272
|
|
|
'subsections' => array( |
273
|
1 |
|
'given' => array($txt['likes_given'], array('profile_view_own')), |
274
|
1 |
|
'received' => array($txt['likes_received'], array('profile_view_own')), |
275
|
|
|
), |
276
|
|
|
'permission' => array( |
277
|
|
|
'own' => 'profile_view_own', |
278
|
|
|
'any' => array(), |
279
|
|
|
), |
280
|
|
|
), |
281
|
|
|
'permissions' => array( |
282
|
1 |
|
'label' => $txt['showPermissions'], |
283
|
1 |
|
'controller' => 'ProfileInfo_Controller', |
284
|
1 |
|
'function' => 'action_showPermissions', |
285
|
|
|
'permission' => array( |
286
|
|
|
'own' => 'manage_permissions', |
287
|
|
|
'any' => 'manage_permissions', |
288
|
|
|
), |
289
|
|
|
), |
290
|
|
|
'history' => array( |
291
|
1 |
|
'label' => $txt['history'], |
292
|
1 |
|
'controller' => 'ProfileHistory_Controller', |
293
|
1 |
|
'function' => 'action_index', |
294
|
|
|
'subsections' => array( |
295
|
1 |
|
'activity' => array($txt['trackActivity'], 'moderate_forum'), |
296
|
1 |
|
'ip' => array($txt['trackIP'], 'moderate_forum'), |
297
|
1 |
|
'edits' => array($txt['trackEdits'], 'moderate_forum'), |
298
|
1 |
|
'logins' => array($txt['trackLogins'], array('profile_view_own', 'moderate_forum')), |
299
|
|
|
), |
300
|
|
|
'permission' => array( |
301
|
|
|
'own' => 'moderate_forum', |
302
|
|
|
'any' => 'moderate_forum', |
303
|
|
|
), |
304
|
|
|
), |
305
|
|
|
'viewwarning' => array( |
306
|
1 |
|
'label' => $txt['profile_view_warnings'], |
307
|
1 |
|
'enabled' => in_array('w', $context['admin_features']) && !empty($modSettings['warning_enable']) && $this->_profile['warning'] && (!empty($modSettings['warning_show']) && ($context['user']['is_owner'] || $modSettings['warning_show'] == 2)), |
308
|
1 |
|
'controller' => 'ProfileInfo_Controller', |
309
|
1 |
|
'function' => 'action_viewWarning', |
310
|
|
|
'permission' => array( |
311
|
|
|
'own' => 'profile_view_own', |
312
|
|
|
'any' => 'issue_warning', |
313
|
|
|
), |
314
|
|
|
), |
315
|
|
|
), |
316
|
|
|
), |
317
|
|
|
'edit_profile' => array( |
318
|
1 |
|
'title' => $txt['profileEdit'], |
319
|
|
|
'areas' => array( |
320
|
|
|
'account' => array( |
321
|
1 |
|
'label' => $txt['account'], |
322
|
1 |
|
'controller' => 'ProfileOptions_Controller', |
323
|
1 |
|
'function' => 'action_account', |
324
|
1 |
|
'enabled' => $context['user']['is_admin'] || ($this->_profile['id_group'] != 1 && !in_array(1, explode(',', $this->_profile['additional_groups']))), |
325
|
1 |
|
'sc' => 'post', |
326
|
1 |
|
'token' => 'profile-ac%u', |
327
|
|
|
'password' => true, |
328
|
|
|
'permission' => array( |
329
|
|
|
'own' => array('profile_identity_any', 'profile_identity_own', 'manage_membergroups'), |
330
|
|
|
'any' => array('profile_identity_any', 'manage_membergroups'), |
331
|
|
|
), |
332
|
|
|
), |
333
|
|
|
'forumprofile' => array( |
334
|
1 |
|
'label' => $txt['forumprofile'], |
335
|
1 |
|
'controller' => 'ProfileOptions_Controller', |
336
|
1 |
|
'function' => 'action_forumProfile', |
337
|
1 |
|
'sc' => 'post', |
338
|
1 |
|
'token' => 'profile-fp%u', |
339
|
|
|
'permission' => array( |
340
|
|
|
'own' => array('profile_extra_any', 'profile_extra_own', 'profile_title_own', 'profile_title_any'), |
341
|
|
|
'any' => array('profile_extra_any', 'profile_title_any'), |
342
|
|
|
), |
343
|
|
|
), |
344
|
|
|
'theme' => array( |
345
|
1 |
|
'label' => $txt['theme'], |
346
|
1 |
|
'controller' => 'ProfileOptions_Controller', |
347
|
1 |
|
'function' => 'action_themepick', |
348
|
1 |
|
'sc' => 'post', |
349
|
1 |
|
'token' => 'profile-th%u', |
350
|
|
|
'permission' => array( |
351
|
|
|
'own' => array('profile_extra_any', 'profile_extra_own'), |
352
|
|
|
'any' => array('profile_extra_any'), |
353
|
|
|
), |
354
|
|
|
), |
355
|
|
|
'authentication' => array( |
356
|
1 |
|
'label' => $txt['authentication'], |
357
|
1 |
|
'controller' => 'ProfileOptions_Controller', |
358
|
1 |
|
'function' => 'action_authentication', |
359
|
1 |
|
'enabled' => !empty($modSettings['enableOpenID']) || !empty($this->_profile['openid_uri']), |
360
|
1 |
|
'sc' => 'post', |
361
|
1 |
|
'token' => 'profile-au%u', |
362
|
1 |
|
'hidden' => empty($modSettings['enableOpenID']) && empty($this->_profile['openid_uri']), |
363
|
|
|
'password' => true, |
364
|
|
|
'permission' => array( |
365
|
|
|
'own' => array('profile_identity_any', 'profile_identity_own'), |
366
|
|
|
'any' => array('profile_identity_any'), |
367
|
|
|
), |
368
|
|
|
), |
369
|
|
|
'notification' => array( |
370
|
1 |
|
'label' => $txt['notifications'], |
371
|
1 |
|
'controller' => 'ProfileOptions_Controller', |
372
|
1 |
|
'function' => 'action_notification', |
373
|
1 |
|
'sc' => 'post', |
374
|
1 |
|
'token' => 'profile-nt%u', |
375
|
|
|
'permission' => array( |
376
|
|
|
'own' => array('profile_extra_any', 'profile_extra_own'), |
377
|
|
|
'any' => array('profile_extra_any'), |
378
|
|
|
), |
379
|
|
|
), |
380
|
|
|
// Without profile_extra_own, settings are accessible from the PM section. |
381
|
|
|
// @todo at some point decouple it from PMs |
382
|
|
|
'contactprefs' => array( |
383
|
1 |
|
'label' => $txt['contactprefs'], |
384
|
1 |
|
'controller' => 'ProfileOptions_Controller', |
385
|
1 |
|
'function' => 'action_pmprefs', |
386
|
1 |
|
'enabled' => allowedTo(array('profile_extra_own', 'profile_extra_any')), |
387
|
1 |
|
'sc' => 'post', |
388
|
1 |
|
'token' => 'profile-pm%u', |
389
|
|
|
'permission' => array( |
390
|
|
|
'own' => array('pm_read'), |
391
|
|
|
'any' => array('profile_extra_any'), |
392
|
|
|
), |
393
|
|
|
), |
394
|
|
|
'ignoreboards' => array( |
395
|
1 |
|
'label' => $txt['ignoreboards'], |
396
|
1 |
|
'controller' => 'ProfileOptions_Controller', |
397
|
1 |
|
'function' => 'action_ignoreboards', |
398
|
1 |
|
'enabled' => !empty($modSettings['allow_ignore_boards']), |
399
|
1 |
|
'sc' => 'post', |
400
|
1 |
|
'token' => 'profile-ib%u', |
401
|
|
|
'permission' => array( |
402
|
|
|
'own' => array('profile_extra_any', 'profile_extra_own'), |
403
|
|
|
'any' => array('profile_extra_any'), |
404
|
|
|
), |
405
|
|
|
), |
406
|
|
|
'lists' => array( |
407
|
1 |
|
'label' => $txt['editBuddyIgnoreLists'], |
408
|
1 |
|
'controller' => 'ProfileOptions_Controller', |
409
|
1 |
|
'function' => 'action_editBuddyIgnoreLists', |
410
|
1 |
|
'enabled' => !empty($modSettings['enable_buddylist']) && $context['user']['is_owner'], |
411
|
1 |
|
'sc' => 'post', |
412
|
1 |
|
'token' => 'profile-bl%u', |
413
|
|
|
'subsections' => array( |
414
|
1 |
|
'buddies' => array($txt['editBuddies']), |
415
|
1 |
|
'ignore' => array($txt['editIgnoreList']), |
416
|
|
|
), |
417
|
|
|
'permission' => array( |
418
|
|
|
'own' => array('profile_extra_any', 'profile_extra_own'), |
419
|
|
|
'any' => array(), |
420
|
|
|
), |
421
|
|
|
), |
422
|
|
|
'groupmembership' => array( |
423
|
1 |
|
'label' => $txt['groupmembership'], |
424
|
1 |
|
'controller' => 'ProfileOptions_Controller', |
425
|
1 |
|
'function' => 'action_groupMembership', |
426
|
1 |
|
'enabled' => !empty($modSettings['show_group_membership']) && $context['user']['is_owner'], |
427
|
1 |
|
'sc' => 'request', |
428
|
1 |
|
'token' => 'profile-gm%u', |
429
|
1 |
|
'token_type' => 'request', |
430
|
|
|
'permission' => array( |
431
|
|
|
'own' => array('profile_view_own'), |
432
|
|
|
'any' => array('manage_membergroups'), |
433
|
|
|
), |
434
|
|
|
), |
435
|
|
|
), |
436
|
|
|
), |
437
|
|
|
'profile_action' => array( |
438
|
1 |
|
'title' => $txt['profileAction'], |
439
|
|
|
'areas' => array( |
440
|
|
|
'sendpm' => array( |
441
|
1 |
|
'label' => $txt['profileSendIm'], |
442
|
1 |
|
'custom_url' => getUrl('action', ['action' => 'pm', 'sa' => 'send']), |
443
|
|
|
'permission' => array( |
444
|
|
|
'own' => array(), |
445
|
|
|
'any' => array('pm_send'), |
446
|
|
|
), |
447
|
|
|
), |
448
|
|
|
'issuewarning' => array( |
449
|
1 |
|
'label' => $txt['profile_issue_warning'], |
450
|
1 |
|
'enabled' => in_array('w', $context['admin_features']) && !empty($modSettings['warning_enable']) && (!$context['user']['is_owner'] || $context['user']['is_admin']), |
451
|
1 |
|
'controller' => 'ProfileAccount_Controller', |
452
|
1 |
|
'function' => 'action_issuewarning', |
453
|
1 |
|
'token' => 'profile-iw%u', |
454
|
|
|
'permission' => array( |
455
|
|
|
'own' => array(), |
456
|
|
|
'any' => array('issue_warning'), |
457
|
|
|
), |
458
|
|
|
), |
459
|
|
|
'banuser' => array( |
460
|
1 |
|
'label' => $txt['profileBanUser'], |
461
|
1 |
|
'custom_url' => getUrl('admin', ['action' => 'admin', 'area' => 'ban', 'sa' => 'add']), |
462
|
1 |
|
'enabled' => $this->_profile['id_group'] != 1 && !in_array(1, explode(',', $this->_profile['additional_groups'])), |
463
|
|
|
'permission' => array( |
464
|
|
|
'own' => array(), |
465
|
|
|
'any' => array('manage_bans'), |
466
|
|
|
), |
467
|
|
|
), |
468
|
|
|
'subscriptions' => array( |
469
|
1 |
|
'label' => $txt['subscriptions'], |
470
|
1 |
|
'controller' => 'ProfileSubscriptions_Controller', |
471
|
1 |
|
'function' => 'action_subscriptions', |
472
|
1 |
|
'enabled' => !empty($modSettings['paid_enabled']), |
473
|
|
|
'permission' => array( |
474
|
|
|
'own' => array('profile_view_own'), |
475
|
|
|
'any' => array('moderate_forum'), |
476
|
|
|
), |
477
|
|
|
), |
478
|
|
|
'deleteaccount' => array( |
479
|
1 |
|
'label' => $txt['deleteAccount'], |
480
|
1 |
|
'controller' => 'ProfileAccount_Controller', |
481
|
1 |
|
'function' => 'action_deleteaccount', |
482
|
1 |
|
'sc' => 'post', |
483
|
1 |
|
'token' => 'profile-da%u', |
484
|
|
|
'password' => true, |
485
|
|
|
'permission' => array( |
486
|
|
|
'own' => array('profile_remove_any', 'profile_remove_own'), |
487
|
|
|
'any' => array('profile_remove_any'), |
488
|
|
|
), |
489
|
|
|
), |
490
|
|
|
'activateaccount' => array( |
491
|
|
|
'controller' => 'ProfileAccount_Controller', |
492
|
|
|
'function' => 'action_activateaccount', |
493
|
|
|
'sc' => 'get', |
494
|
|
|
'token' => 'profile-aa%u', |
495
|
|
|
'token_type' => 'get', |
496
|
|
|
'permission' => array( |
497
|
|
|
'own' => array(), |
498
|
|
|
'any' => array('moderate_forum'), |
499
|
|
|
), |
500
|
|
|
), |
501
|
|
|
), |
502
|
|
|
), |
503
|
|
|
); |
504
|
|
|
|
505
|
|
|
// Set a few options for the menu. |
506
|
|
|
$menuOptions = array( |
507
|
1 |
|
'disable_url_session_check' => true, |
508
|
1 |
|
'hook' => 'profile', |
509
|
|
|
'extra_url_parameters' => array( |
510
|
1 |
|
'u' => $context['id_member'], |
511
|
|
|
), |
512
|
|
|
'default_include_dir' => CONTROLLERDIR, |
513
|
|
|
); |
514
|
|
|
|
515
|
|
|
// Actually create the menu! |
516
|
1 |
|
$this->_profile_include_data = createMenu($profile_areas, $menuOptions); |
517
|
1 |
|
unset($profile_areas); |
518
|
1 |
|
} |
519
|
|
|
|
520
|
|
|
/** |
521
|
|
|
* Does session and token checks for the areas that require those |
522
|
|
|
*/ |
523
|
1 |
|
private function _check_access() |
524
|
|
|
{ |
525
|
1 |
|
global $context; |
526
|
|
|
|
527
|
|
|
// Does this require session validating? |
528
|
1 |
|
if (!empty($this->_profile_include_data['validate']) |
529
|
1 |
|
|| (isset($this->_saving) && !$context['user']['is_owner'])) |
530
|
|
|
{ |
531
|
|
|
validateSession(); |
532
|
|
|
} |
533
|
|
|
|
534
|
|
|
// Do we need to perform a token check? |
535
|
1 |
|
if (!empty($this->_profile_include_data['token'])) |
536
|
|
|
{ |
537
|
1 |
|
if ($this->_profile_include_data['token'] !== true) |
538
|
|
|
{ |
539
|
1 |
|
$token_name = str_replace('%u', $context['id_member'], $this->_profile_include_data['token']); |
540
|
|
|
} |
541
|
|
|
else |
542
|
|
|
{ |
543
|
|
|
$token_name = 'profile-u' . $context['id_member']; |
544
|
|
|
} |
545
|
|
|
|
546
|
1 |
|
if (isset($this->_profile_include_data['token_type']) && in_array($this->_profile_include_data['token_type'], array('request', 'post', 'get'))) |
547
|
|
|
{ |
548
|
1 |
|
$token_type = $this->_profile_include_data['token_type']; |
549
|
|
|
} |
550
|
|
|
else |
551
|
|
|
{ |
552
|
|
|
$token_type = 'post'; |
553
|
|
|
} |
554
|
|
|
|
555
|
1 |
|
if (isset($this->_saving)) |
556
|
|
|
{ |
557
|
|
|
validateToken($token_name, $token_type); |
558
|
|
|
} |
559
|
|
|
|
560
|
1 |
|
createToken($token_name, $token_type); |
561
|
1 |
|
$context['token_check'] = $token_name; |
562
|
|
|
} |
563
|
1 |
|
} |
564
|
|
|
|
565
|
|
|
/** |
566
|
|
|
* Just builds the link tree based on where were are in the profile section |
567
|
|
|
* and who's profile is being viewed, etc. |
568
|
|
|
*/ |
569
|
1 |
|
private function _build_profile_linktree() |
570
|
|
|
{ |
571
|
1 |
|
global $context, $txt, $user_info; |
572
|
|
|
|
573
|
1 |
|
$context['linktree'][] = array( |
574
|
1 |
|
'url' => getUrl('profile', ['action' => 'profile', 'u' => $this->_memID, 'name' => $this->_profile['real_name']]), |
575
|
1 |
|
'name' => sprintf($txt['profile_of_username'], $context['member']['name']), |
576
|
|
|
); |
577
|
|
|
|
578
|
1 |
|
if (!empty($this->_profile_include_data['label'])) |
579
|
|
|
{ |
580
|
1 |
|
$context['linktree'][] = array( |
581
|
1 |
|
'url' => getUrl('profile', ['action' => 'profile', 'area' => $this->_profile_include_data['current_area'], 'u' => $this->_memID, 'name' => $this->_profile['real_name']]), |
582
|
1 |
|
'name' => $this->_profile_include_data['label'], |
583
|
|
|
); |
584
|
|
|
} |
585
|
|
|
|
586
|
1 |
|
if (!empty($this->_profile_include_data['current_subsection']) && $this->_profile_include_data['subsections'][$this->_profile_include_data['current_subsection']][0] != $this->_profile_include_data['label']) |
587
|
|
|
{ |
588
|
|
|
$context['linktree'][] = array( |
589
|
|
|
'url' => getUrl('profile', ['action' => 'profile', 'area' => $this->_profile_include_data['current_area'], 'sa' => $this->_profile_include_data['current_subsection'], 'u' => $this->_memID, 'name' => $this->_profile['real_name']]), |
590
|
|
|
'name' => $this->_profile_include_data['subsections'][$this->_profile_include_data['current_subsection']][0], |
591
|
|
|
); |
592
|
|
|
} |
593
|
1 |
|
} |
594
|
|
|
|
595
|
|
|
/** |
596
|
|
|
* Save profile updates |
597
|
|
|
*/ |
598
|
1 |
|
private function _save_updates() |
599
|
|
|
{ |
600
|
1 |
|
global $txt, $user_info, $context, $modSettings, $user_settings, $post_errors, $profile_vars; |
601
|
|
|
|
602
|
|
|
// All the subactions that require a user password in order to validate. |
603
|
1 |
|
$check_password = $context['user']['is_owner'] && !empty($this->_profile_include_data['password']); |
604
|
1 |
|
$context['require_password'] = $check_password && empty($user_settings['openid_uri']); |
605
|
|
|
|
606
|
|
|
// These will get populated soon! |
607
|
1 |
|
$post_errors = array(); |
608
|
1 |
|
$profile_vars = array(); |
609
|
|
|
|
610
|
1 |
|
if ($this->_completed_save) |
611
|
|
|
{ |
612
|
|
|
// Clean up the POST variables. |
613
|
|
|
$post = htmltrim__recursive((array) $this->_req->post); |
614
|
|
|
$post = htmlspecialchars__recursive($post); |
615
|
|
|
$this->_req->post = new ArrayObject($post, ArrayObject::ARRAY_AS_PROPS); |
616
|
|
|
|
617
|
|
|
// Does the change require the current password as well? |
618
|
|
|
$this->_check_password($check_password); |
619
|
|
|
|
620
|
|
|
// Change the IP address in the database. |
621
|
|
|
if ($context['user']['is_owner']) |
622
|
|
|
{ |
623
|
|
|
$profile_vars['member_ip'] = $user_info['ip']; |
624
|
|
|
} |
625
|
|
|
|
626
|
|
|
// Now call the sub-action function... |
627
|
|
|
if ($this->_current_area === 'activateaccount' && empty($post_errors)) |
628
|
|
|
{ |
629
|
|
|
$controller = new ProfileAccount_Controller(new Event_Manager()); |
630
|
|
|
$controller->pre_dispatch(); |
631
|
|
|
$controller->action_activateaccount(); |
632
|
|
|
} |
633
|
|
|
elseif ($this->_current_area === 'deleteaccount' && empty($post_errors)) |
634
|
|
|
{ |
635
|
|
|
$controller = new ProfileAccount_Controller(new Event_Manager()); |
636
|
|
|
$controller->pre_dispatch(); |
637
|
|
|
$controller->action_deleteaccount2(); |
638
|
|
|
|
639
|
|
|
// Done |
640
|
|
|
redirectexit(); |
641
|
|
|
} |
642
|
|
|
elseif ($this->_current_area === 'groupmembership' && empty($post_errors)) |
643
|
|
|
{ |
644
|
|
|
$controller = new ProfileOptions_Controller(new Event_Manager()); |
645
|
|
|
$controller->pre_dispatch(); |
646
|
|
|
$msg = $controller->action_groupMembership2(); |
647
|
|
|
|
648
|
|
|
// Whatever we've done, we have nothing else to do here... |
649
|
|
|
redirectexit('action=profile' . ($context['user']['is_owner'] ? '' : ';u=' . $this->_memID) . ';area=groupmembership' . (!empty($msg) ? ';msg=' . $msg : '')); |
650
|
|
|
} |
651
|
|
|
// Authentication changes? |
652
|
|
|
elseif ($this->_current_area === 'authentication') |
653
|
|
|
{ |
654
|
|
|
$controller = new ProfileOptions_Controller(new Event_Manager()); |
655
|
|
|
$controller->pre_dispatch(); |
656
|
|
|
$controller->action_authentication(true); |
657
|
|
|
} |
658
|
|
|
elseif (in_array($this->_current_area, array('account', 'forumprofile', 'theme', 'contactprefs'))) |
659
|
|
|
{ |
660
|
|
|
// @todo yes this is ugly, but saveProfileFields needs to be updated first |
661
|
|
|
$_POST = (array) $this->_req->post; |
662
|
|
|
|
663
|
|
|
require_once(CONTROLLERDIR . '/ProfileOptions.controller.php'); |
664
|
|
|
if ($this->_current_area === 'account' && !empty($modSettings['enableOTP'])) |
665
|
|
|
{ |
666
|
|
|
$fields = ProfileOptions_Controller::getFields('account_otp'); |
667
|
|
|
} |
668
|
|
|
else |
669
|
|
|
{ |
670
|
|
|
$fields = ProfileOptions_Controller::getFields($this->_current_area); |
671
|
|
|
} |
672
|
|
|
|
673
|
|
|
saveProfileFields($fields['fields'], $fields['hook']); |
674
|
|
|
} |
675
|
|
|
elseif (empty($post_errors)) |
676
|
|
|
{ |
677
|
|
|
// @todo yes this is also ugly, but saveProfileChanges needs to be updated first |
678
|
|
|
$_POST = (array) $this->_req->post; |
679
|
|
|
|
680
|
|
|
$this->_force_redirect = true; |
681
|
|
|
saveProfileChanges($profile_vars, $this->_memID); |
682
|
|
|
} |
683
|
|
|
|
684
|
|
|
call_integration_hook('integrate_profile_save', array(&$profile_vars, &$post_errors, $this->_memID)); |
685
|
|
|
|
686
|
|
|
// There was a problem, let them try to re-enter. |
687
|
|
|
if (!empty($post_errors)) |
688
|
|
|
{ |
689
|
|
|
// Load the language file so we can give a nice explanation of the errors. |
690
|
|
|
theme()->getTemplates()->loadLanguageFile('Errors'); |
691
|
|
|
$context['post_errors'] = $post_errors; |
692
|
|
|
} |
693
|
|
|
elseif (!empty($profile_vars)) |
694
|
|
|
{ |
695
|
|
|
// If we've changed the password, notify any integration that may be listening in. |
696
|
|
|
if (isset($profile_vars['passwd'])) |
697
|
|
|
{ |
698
|
|
|
call_integration_hook('integrate_reset_pass', array($this->_profile['member_name'], $this->_profile['member_name'], $this->_req->post->passwrd2)); |
|
|
|
|
699
|
|
|
} |
700
|
|
|
|
701
|
|
|
require_once(SUBSDIR . '/Members.subs.php'); |
702
|
|
|
updateMemberData($this->_memID, $profile_vars); |
703
|
|
|
|
704
|
|
|
// What if this is the newest member? |
705
|
|
|
if ($modSettings['latestMember'] == $this->_memID) |
706
|
|
|
{ |
707
|
|
|
require_once(SUBSDIR . '/Members.subs.php'); |
708
|
|
|
updateMemberStats(); |
709
|
|
|
} |
710
|
|
|
elseif (isset($profile_vars['real_name'])) |
711
|
|
|
{ |
712
|
|
|
updateSettings(array('memberlist_updated' => time())); |
713
|
|
|
} |
714
|
|
|
|
715
|
|
|
// If the member changed his/her birth date, update calendar statistics. |
716
|
|
|
if (isset($profile_vars['birthdate']) || isset($profile_vars['real_name'])) |
717
|
|
|
{ |
718
|
|
|
updateSettings(array( |
719
|
|
|
'calendar_updated' => time(), |
720
|
|
|
)); |
721
|
|
|
} |
722
|
|
|
|
723
|
|
|
// Anything worth logging? |
724
|
|
|
if (!empty($context['log_changes']) && !empty($modSettings['modlog_enabled'])) |
725
|
|
|
{ |
726
|
|
|
$log_changes = array(); |
727
|
|
|
foreach ($context['log_changes'] as $k => $v) |
|
|
|
|
728
|
|
|
{ |
729
|
|
|
$log_changes[] = array( |
730
|
|
|
'action' => $k, |
731
|
|
|
'log_type' => 'user', |
732
|
|
|
'extra' => array_merge($v, array( |
733
|
|
|
'applicator' => $user_info['id'], |
734
|
|
|
'member_affected' => $this->_memID, |
735
|
|
|
)), |
736
|
|
|
); |
737
|
|
|
} |
738
|
|
|
|
739
|
|
|
logActions($log_changes); |
740
|
|
|
} |
741
|
|
|
|
742
|
|
|
// Have we got any post save functions to execute? |
743
|
|
|
if (!empty($context['profile_execute_on_save'])) |
744
|
|
|
{ |
745
|
|
|
foreach ($context['profile_execute_on_save'] as $saveFunc) |
|
|
|
|
746
|
|
|
$saveFunc(); |
747
|
|
|
} |
748
|
|
|
|
749
|
|
|
// Let them know it worked! |
750
|
|
|
$context['profile_updated'] = $context['user']['is_owner'] ? $txt['profile_updated_own'] : sprintf($txt['profile_updated_else'], $this->_profile['member_name']); |
751
|
|
|
|
752
|
|
|
// Invalidate any cached data. |
753
|
|
|
Cache::instance()->remove('member_data-profile-' . $this->_memID); |
754
|
|
|
} |
755
|
|
|
} |
756
|
1 |
|
} |
757
|
|
|
|
758
|
|
|
/** |
759
|
|
|
* If a password validation before a change is needed, this is the function to do it |
760
|
|
|
* |
761
|
|
|
* @param bool $check_password if this profile update requires a password verification |
762
|
|
|
* @throws Elk_Exception |
763
|
|
|
*/ |
764
|
|
|
private function _check_password($check_password) |
765
|
|
|
{ |
766
|
|
|
global $user_settings, $user_info, $post_errors, $context; |
767
|
|
|
|
768
|
|
|
if ($check_password) |
769
|
|
|
{ |
770
|
|
|
// If we're using OpenID try to re-validate. |
771
|
|
|
if (!empty($user_settings['openid_uri'])) |
772
|
|
|
{ |
773
|
|
|
require_once(SUBSDIR . '/OpenID.subs.php'); |
774
|
|
|
$openID = new OpenID(); |
775
|
|
|
$openID->revalidate(); |
776
|
|
|
} |
777
|
|
|
else |
778
|
|
|
{ |
779
|
|
|
// You didn't even enter a password! |
780
|
|
|
if (trim($this->_req->post->oldpasswrd) === '') |
781
|
|
|
{ |
782
|
|
|
$post_errors[] = 'no_password'; |
783
|
|
|
} |
784
|
|
|
|
785
|
|
|
// Since the password got modified due to all the $_POST cleaning, lets undo it so we can get the correct password |
786
|
|
|
$this->_req->post->oldpasswrd = un_htmlspecialchars($this->_req->post->oldpasswrd); |
787
|
|
|
|
788
|
|
|
// Does the integration want to check passwords? |
789
|
|
|
$good_password = in_array(true, call_integration_hook('integrate_verify_password', array($this->_profile['member_name'], $this->_req->post->oldpasswrd, false)), true); |
790
|
|
|
|
791
|
|
|
// Start up the password checker, we have work to do |
792
|
|
|
require_once(SUBSDIR . '/Auth.subs.php'); |
793
|
|
|
|
794
|
|
|
// Bad password!!! |
795
|
|
|
if (!$good_password && !validateLoginPassword($this->_req->post->oldpasswrd, $user_info['passwd'], $this->_profile['member_name'])) |
796
|
|
|
{ |
797
|
|
|
$post_errors[] = 'bad_password'; |
798
|
|
|
} |
799
|
|
|
|
800
|
|
|
// Warn other elements not to jump the gun and do custom changes! |
801
|
|
|
if (in_array('bad_password', $post_errors)) |
802
|
|
|
{ |
803
|
|
|
$context['password_auth_failed'] = true; |
804
|
|
|
} |
805
|
|
|
} |
806
|
|
|
} |
807
|
|
|
} |
808
|
|
|
} |
809
|
|
|
|
If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:
If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.