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 1.1 beta 1 |
17
|
|
|
* |
18
|
|
|
*/ |
19
|
|
|
|
20
|
|
|
if (!defined('ELK')) |
21
|
|
|
die('No access...'); |
22
|
|
|
|
23
|
|
|
/** |
24
|
|
|
* ProfileOptions_Controller Class. |
25
|
|
|
* Does the job of showing and editing people's profiles. |
26
|
|
|
* Interface to buddy list, ignore list, notifications, authentication options, forum profile |
27
|
|
|
* account settings, etc |
28
|
|
|
*/ |
29
|
|
|
class ProfileOptions_Controller extends Action_Controller |
|
|
|
|
30
|
|
|
{ |
31
|
|
|
/** |
32
|
|
|
* Member id for the profile being viewed |
33
|
|
|
* @var int |
34
|
|
|
*/ |
35
|
|
|
private $_memID = 0; |
36
|
|
|
|
37
|
|
|
/** |
38
|
|
|
* Called before all other methods when coming from the dispatcher or |
39
|
|
|
* action class. |
40
|
|
|
* |
41
|
|
|
* - If you initiate the class outside of those methods, call this method. |
42
|
|
|
* or setup the class yourself else a horrible fate awaits you |
43
|
|
|
*/ |
44
|
|
|
public function pre_dispatch() |
45
|
|
|
{ |
46
|
|
|
$this->_memID = currentMemberID(); |
47
|
|
|
} |
48
|
|
|
|
49
|
|
|
/** |
50
|
|
|
* Default method, if another action is not called by the menu. |
51
|
|
|
* |
52
|
|
|
* @see Action_Controller::action_index() |
53
|
|
|
*/ |
54
|
|
|
public function action_index() |
55
|
|
|
{ |
56
|
|
|
// action_account() is the first to do |
57
|
|
|
// these subactions are mostly routed to from the profile |
58
|
|
|
// menu though. |
59
|
|
|
} |
60
|
|
|
|
61
|
|
|
/** |
62
|
|
|
* Show all the users buddies, as well as a add/delete interface. |
63
|
|
|
*/ |
64
|
|
|
public function action_editBuddyIgnoreLists() |
65
|
|
|
{ |
66
|
|
|
global $context, $txt, $modSettings; |
67
|
|
|
|
68
|
|
|
// Do a quick check to ensure people aren't getting here illegally! |
69
|
|
|
if (!$context['user']['is_owner'] || empty($modSettings['enable_buddylist'])) |
70
|
|
|
Errors::instance()->fatal_lang_error('no_access', false); |
71
|
|
|
|
72
|
|
|
loadTemplate('ProfileOptions'); |
73
|
|
|
|
74
|
|
|
// Can we email the user direct? |
75
|
|
|
$context['can_moderate_forum'] = allowedTo('moderate_forum'); |
76
|
|
|
$context['can_send_email'] = allowedTo('send_email_to_members'); |
77
|
|
|
|
78
|
|
|
$subActions = array( |
79
|
|
|
'buddies' => array($this, 'action_editBuddies'), |
80
|
|
|
'ignore' => array($this, 'action_editIgnoreList'), |
81
|
|
|
); |
82
|
|
|
|
83
|
|
|
// Set a subaction |
84
|
|
|
$action = new Action(); |
85
|
|
|
$subAction = $action->initialize($subActions, 'buddies'); |
86
|
|
|
|
87
|
|
|
// Create the tabs for the template. |
88
|
|
|
$context[$context['profile_menu_name']]['tab_data'] = array( |
89
|
|
|
'title' => $txt['editBuddyIgnoreLists'], |
90
|
|
|
'description' => $txt['buddy_ignore_desc'], |
91
|
|
|
'class' => 'profile', |
92
|
|
|
'tabs' => array( |
93
|
|
|
'buddies' => array(), |
94
|
|
|
'ignore' => array(), |
95
|
|
|
), |
96
|
|
|
); |
97
|
|
|
|
98
|
|
|
// Pass on to the actual function. |
99
|
|
|
$action->dispatch($subAction); |
100
|
|
|
} |
101
|
|
|
|
102
|
|
|
/** |
103
|
|
|
* Show all the users buddies, as well as a add/delete interface. |
104
|
|
|
* |
105
|
|
|
* @uses template_editBuddies() |
106
|
|
|
*/ |
107
|
|
|
public function action_editBuddies() |
108
|
|
|
{ |
109
|
|
|
global $context, $user_profile, $memberContext; |
110
|
|
|
|
111
|
|
|
loadTemplate('ProfileOptions'); |
112
|
|
|
|
113
|
|
|
// We want to view what we're doing :P |
114
|
|
|
$context['sub_template'] = 'editBuddies'; |
115
|
|
|
|
116
|
|
|
// Use suggest to find the right buddies |
117
|
|
|
loadJavascriptFile('suggest.js', array('defer' => true)); |
118
|
|
|
|
119
|
|
|
// For making changes! |
120
|
|
|
$buddiesArray = explode(',', $user_profile[$this->_memID]['buddy_list']); |
121
|
|
|
foreach ($buddiesArray as $k => $dummy) |
122
|
|
|
{ |
123
|
|
|
if ($dummy === '') |
124
|
|
|
unset($buddiesArray[$k]); |
125
|
|
|
} |
126
|
|
|
|
127
|
|
|
// Removing a buddy? |
128
|
|
|
if (isset($this->_req->query->remove)) |
129
|
|
|
{ |
130
|
|
|
checkSession('get'); |
131
|
|
|
|
132
|
|
|
call_integration_hook('integrate_remove_buddy', array($this->_memID)); |
133
|
|
|
|
134
|
|
|
// Heh, I'm lazy, do it the easy way... |
135
|
|
|
foreach ($buddiesArray as $key => $buddy) |
136
|
|
|
{ |
137
|
|
|
if ($buddy == (int) $this->_req->query->remove) |
138
|
|
|
unset($buddiesArray[$key]); |
139
|
|
|
} |
140
|
|
|
|
141
|
|
|
// Make the changes. |
142
|
|
|
$user_profile[$this->_memID]['buddy_list'] = implode(',', $buddiesArray); |
143
|
|
|
require_once(SUBSDIR . '/Members.subs.php'); |
144
|
|
|
updateMemberData($this->_memID, array('buddy_list' => $user_profile[$this->_memID]['buddy_list'])); |
145
|
|
|
|
146
|
|
|
// Redirect off the page because we don't like all this ugly query stuff to stick in the history. |
147
|
|
|
redirectexit('action=profile;area=lists;sa=buddies;u=' . $this->_memID); |
148
|
|
|
} |
149
|
|
|
// Or adding a new one |
150
|
|
|
elseif (isset($this->_req->post->new_buddy)) |
151
|
|
|
{ |
152
|
|
|
checkSession(); |
153
|
|
|
|
154
|
|
|
// Prepare the string for extraction... |
155
|
|
|
$new_buddy = strtr(Util::htmlspecialchars($this->_req->post->new_buddy, ENT_QUOTES), array('"' => '"')); |
156
|
|
|
preg_match_all('~"([^"]+)"~', $new_buddy, $matches); |
157
|
|
|
$new_buddies = array_unique(array_merge($matches[1], explode(',', preg_replace('~"[^"]+"~', '', $new_buddy)))); |
158
|
|
|
|
159
|
|
View Code Duplication |
foreach ($new_buddies as $k => $dummy) |
160
|
|
|
{ |
161
|
|
|
$new_buddies[$k] = strtr(trim($new_buddies[$k]), array('\'' => ''')); |
162
|
|
|
|
163
|
|
|
if (strlen($new_buddies[$k]) == 0 || in_array($new_buddies[$k], array($user_profile[$this->_memID]['member_name'], $user_profile[$this->_memID]['real_name']))) |
164
|
|
|
unset($new_buddies[$k]); |
165
|
|
|
} |
166
|
|
|
|
167
|
|
|
call_integration_hook('integrate_add_buddies', array($this->_memID, &$new_buddies)); |
168
|
|
|
|
169
|
|
View Code Duplication |
if (!empty($new_buddies)) |
170
|
|
|
{ |
171
|
|
|
// Now find out the id_member of the buddy. |
172
|
|
|
require_once(SUBSDIR . '/ProfileOptions.subs.php'); |
173
|
|
|
$buddiesArray = getBuddiesID($new_buddies); |
174
|
|
|
|
175
|
|
|
// Now update the current users buddy list. |
176
|
|
|
$user_profile[$this->_memID]['buddy_list'] = implode(',', $buddiesArray); |
177
|
|
|
require_once(SUBSDIR . '/Members.subs.php'); |
178
|
|
|
updateMemberData($this->_memID, array('buddy_list' => $user_profile[$this->_memID]['buddy_list'])); |
179
|
|
|
} |
180
|
|
|
|
181
|
|
|
// Back to the buddy list! |
182
|
|
|
redirectexit('action=profile;area=lists;sa=buddies;u=' . $this->_memID); |
183
|
|
|
} |
184
|
|
|
|
185
|
|
|
// Get all the users "buddies"... |
186
|
|
|
$buddies = array(); |
187
|
|
|
|
188
|
|
View Code Duplication |
if (!empty($buddiesArray)) |
189
|
|
|
{ |
190
|
|
|
require_once(SUBSDIR . '/Members.subs.php'); |
191
|
|
|
$result = getBasicMemberData($buddiesArray, array('sort' => 'real_name', 'limit' => substr_count($user_profile[$this->_memID]['buddy_list'], ',') + 1)); |
192
|
|
|
foreach ($result as $row) |
193
|
|
|
$buddies[] = $row['id_member']; |
194
|
|
|
} |
195
|
|
|
|
196
|
|
|
$context['buddy_count'] = count($buddies); |
197
|
|
|
|
198
|
|
|
// Load all the members up. |
199
|
|
|
loadMemberData($buddies, false, 'profile'); |
200
|
|
|
|
201
|
|
|
// Setup the context for each buddy. |
202
|
|
|
$context['buddies'] = array(); |
203
|
|
View Code Duplication |
foreach ($buddies as $buddy) |
204
|
|
|
{ |
205
|
|
|
loadMemberContext($buddy, true); |
206
|
|
|
$context['buddies'][$buddy] = $memberContext[$buddy]; |
207
|
|
|
} |
208
|
|
|
|
209
|
|
|
call_integration_hook('integrate_view_buddies', array($this->_memID)); |
210
|
|
|
} |
211
|
|
|
|
212
|
|
|
/** |
213
|
|
|
* Allows the user to view their ignore list, |
214
|
|
|
* |
215
|
|
|
* - Provides the option to manage members on it. |
216
|
|
|
*/ |
217
|
|
|
public function action_editIgnoreList() |
218
|
|
|
{ |
219
|
|
|
global $context, $user_profile, $memberContext; |
220
|
|
|
|
221
|
|
|
loadTemplate('ProfileOptions'); |
222
|
|
|
|
223
|
|
|
// We want to view what we're doing :P |
224
|
|
|
$context['sub_template'] = 'editIgnoreList'; |
225
|
|
|
loadJavascriptFile('suggest.js', array('defer' => true)); |
226
|
|
|
|
227
|
|
|
// For making changes! |
228
|
|
|
$ignoreArray = explode(',', $user_profile[$this->_memID]['pm_ignore_list']); |
229
|
|
|
foreach ($ignoreArray as $k => $dummy) |
230
|
|
|
{ |
231
|
|
|
if ($dummy === '') |
232
|
|
|
unset($ignoreArray[$k]); |
233
|
|
|
} |
234
|
|
|
|
235
|
|
|
// Removing a member from the ignore list? |
236
|
|
|
if (isset($this->_req->query->remove)) |
237
|
|
|
{ |
238
|
|
|
checkSession('get'); |
239
|
|
|
|
240
|
|
|
// Heh, I'm lazy, do it the easy way... |
241
|
|
|
foreach ($ignoreArray as $key => $id_remove) |
242
|
|
|
{ |
243
|
|
|
if ($id_remove == (int) $this->_req->query->remove) |
244
|
|
|
unset($ignoreArray[$key]); |
245
|
|
|
} |
246
|
|
|
|
247
|
|
|
// Make the changes. |
248
|
|
|
$user_profile[$this->_memID]['pm_ignore_list'] = implode(',', $ignoreArray); |
249
|
|
|
require_once(SUBSDIR . '/Members.subs.php'); |
250
|
|
|
updateMemberData($this->_memID, array('pm_ignore_list' => $user_profile[$this->_memID]['pm_ignore_list'])); |
251
|
|
|
|
252
|
|
|
// Redirect off the page because we don't like all this ugly query stuff to stick in the history. |
253
|
|
|
redirectexit('action=profile;area=lists;sa=ignore;u=' . $this->_memID); |
254
|
|
|
} |
255
|
|
|
elseif (isset($this->_req->post->new_ignore)) |
256
|
|
|
{ |
257
|
|
|
checkSession(); |
258
|
|
|
|
259
|
|
|
// Prepare the string for extraction... |
260
|
|
|
$new_ignore = strtr(Util::htmlspecialchars($this->_req->post->new_ignore, ENT_QUOTES), array('"' => '"')); |
261
|
|
|
preg_match_all('~"([^"]+)"~', $new_ignore, $matches); |
262
|
|
|
$new_entries = array_unique(array_merge($matches[1], explode(',', preg_replace('~"[^"]+"~', '', $new_ignore)))); |
263
|
|
|
|
264
|
|
View Code Duplication |
foreach ($new_entries as $k => $dummy) |
265
|
|
|
{ |
266
|
|
|
$new_entries[$k] = strtr(trim($new_entries[$k]), array('\'' => ''')); |
267
|
|
|
|
268
|
|
|
if (strlen($new_entries[$k]) == 0 || in_array($new_entries[$k], array($user_profile[$this->_memID]['member_name'], $user_profile[$this->_memID]['real_name']))) |
269
|
|
|
unset($new_entries[$k]); |
270
|
|
|
} |
271
|
|
|
|
272
|
|
View Code Duplication |
if (!empty($new_entries)) |
273
|
|
|
{ |
274
|
|
|
// Now find out the id_member for the members in question. |
275
|
|
|
require_once(SUBSDIR . '/ProfileOptions.subs.php'); |
276
|
|
|
$ignoreArray = getBuddiesID($new_entries, false); |
277
|
|
|
|
278
|
|
|
// Now update the current users buddy list. |
279
|
|
|
$user_profile[$this->_memID]['pm_ignore_list'] = implode(',', $ignoreArray); |
280
|
|
|
require_once(SUBSDIR . '/Members.subs.php'); |
281
|
|
|
updateMemberData($this->_memID, array('pm_ignore_list' => $user_profile[$this->_memID]['pm_ignore_list'])); |
282
|
|
|
} |
283
|
|
|
|
284
|
|
|
// Back to the list of pitiful people! |
285
|
|
|
redirectexit('action=profile;area=lists;sa=ignore;u=' . $this->_memID); |
286
|
|
|
} |
287
|
|
|
|
288
|
|
|
// Initialise the list of members we're ignoring. |
289
|
|
|
$ignored = array(); |
290
|
|
|
|
291
|
|
View Code Duplication |
if (!empty($ignoreArray)) |
292
|
|
|
{ |
293
|
|
|
require_once(SUBSDIR . '/Members.subs.php'); |
294
|
|
|
$result = getBasicMemberData($ignoreArray, array('sort' => 'real_name', 'limit' => substr_count($user_profile[$this->_memID]['pm_ignore_list'], ',') + 1)); |
295
|
|
|
foreach ($result as $row) |
296
|
|
|
$ignored[] = $row['id_member']; |
297
|
|
|
} |
298
|
|
|
|
299
|
|
|
$context['ignore_count'] = count($ignored); |
300
|
|
|
|
301
|
|
|
// Load all the members up. |
302
|
|
|
loadMemberData($ignored, false, 'profile'); |
303
|
|
|
|
304
|
|
|
// Setup the context for each buddy. |
305
|
|
|
$context['ignore_list'] = array(); |
306
|
|
|
foreach ($ignored as $ignore_member) |
307
|
|
|
{ |
308
|
|
|
loadMemberContext($ignore_member); |
309
|
|
|
$context['ignore_list'][$ignore_member] = $memberContext[$ignore_member]; |
310
|
|
|
} |
311
|
|
|
} |
312
|
|
|
|
313
|
|
|
/** |
314
|
|
|
* Allows the user to see or change their account info. |
315
|
|
|
*/ |
316
|
|
|
public function action_account() |
317
|
|
|
{ |
318
|
|
|
global $modSettings, $context, $txt; |
319
|
|
|
|
320
|
|
|
loadTemplate('ProfileOptions'); |
321
|
|
|
$this->loadThemeOptions(); |
322
|
|
|
|
323
|
|
|
if (allowedTo(array('profile_identity_own', 'profile_identity_any'))) |
324
|
|
|
loadCustomFields($this->_memID, 'account'); |
325
|
|
|
|
326
|
|
|
$context['sub_template'] = 'edit_options'; |
327
|
|
|
$context['page_desc'] = $txt['account_info']; |
328
|
|
|
|
329
|
|
|
if (!empty($modSettings['enableOTP'])) |
330
|
|
|
{ |
331
|
|
|
setupProfileContext( |
332
|
|
|
array( |
333
|
|
|
'member_name', 'real_name', 'date_registered', 'posts', 'lngfile', 'hr', |
334
|
|
|
'id_group', 'hr', |
335
|
|
|
'email_address', 'hide_email', 'show_online', 'hr', |
336
|
|
|
'passwrd1', 'passwrd2', 'hr', |
337
|
|
|
'secret_question', 'secret_answer', 'hr', |
338
|
|
|
'enable_otp', 'otp_secret', 'hr' |
339
|
|
|
), |
340
|
|
|
'account' |
341
|
|
|
); |
342
|
|
|
|
343
|
|
|
loadJavascriptFile('qrcode.js'); |
344
|
|
|
addInlineJavascript(' |
345
|
|
|
var secret = document.getElementById("otp_secret").value; |
346
|
|
|
|
347
|
|
|
if (secret) |
348
|
|
|
{ |
349
|
|
|
var qrcode = new QRCode("qrcode", { |
350
|
|
|
text: "otpauth://totp/' . $context['forum_name'] . '?secret=" + secret, |
351
|
|
|
width: 80, |
352
|
|
|
height: 80, |
353
|
|
|
colorDark : "#000000", |
354
|
|
|
colorLight : "#ffffff", |
355
|
|
|
}); |
356
|
|
|
} |
357
|
|
|
|
358
|
|
|
/** |
359
|
|
|
* Generate a secret key for Google Authenticator |
360
|
|
|
*/ |
361
|
|
|
function generateSecret() { |
362
|
|
|
var text = "", |
363
|
|
|
possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567", |
364
|
|
|
qr = document.getElementById("qrcode"); |
365
|
|
|
|
366
|
|
|
for (var i = 0; i < 16; i++) |
367
|
|
|
text += possible.charAt(Math.floor(Math.random() * possible.length)); |
368
|
|
|
|
369
|
|
|
document.getElementById("otp_secret").value = text; |
370
|
|
|
|
371
|
|
|
while (qr.firstChild) { |
372
|
|
|
qr.removeChild(qr.firstChild); |
373
|
|
|
} |
374
|
|
|
|
375
|
|
|
var qrcode = new QRCode("qrcode", { |
376
|
|
|
text: "otpauth://totp/' . $context['forum_name'] . '?secret=" + text, |
377
|
|
|
width: 80, |
378
|
|
|
height: 80, |
379
|
|
|
colorDark: "#000000", |
380
|
|
|
colorLight: "#ffffff", |
381
|
|
|
}); |
382
|
|
|
}', true); |
383
|
|
|
} |
384
|
|
|
else |
385
|
|
|
{ |
386
|
|
|
setupProfileContext( |
387
|
|
|
array( |
388
|
|
|
'member_name', 'real_name', 'date_registered', 'posts', 'lngfile', 'hr', |
389
|
|
|
'id_group', 'hr', |
390
|
|
|
'email_address', 'hide_email', 'show_online', 'hr', |
391
|
|
|
'passwrd1', 'passwrd2', 'hr', |
392
|
|
|
'secret_question', 'secret_answer', 'hr', |
393
|
|
|
), |
394
|
|
|
'account' |
395
|
|
|
); |
396
|
|
|
} |
397
|
|
|
} |
398
|
|
|
|
399
|
|
|
|
400
|
|
|
/** |
401
|
|
|
* Allow the user to change the forum options in their profile. |
402
|
|
|
*/ |
403
|
|
|
public function action_forumProfile() |
404
|
|
|
{ |
405
|
|
|
global $context, $txt; |
406
|
|
|
|
407
|
|
|
loadTemplate('ProfileOptions'); |
408
|
|
|
$this->loadThemeOptions(); |
409
|
|
|
|
410
|
|
|
if (allowedTo(array('profile_extra_own', 'profile_extra_any'))) |
411
|
|
|
loadCustomFields($this->_memID, 'forumprofile'); |
412
|
|
|
|
413
|
|
|
$context['sub_template'] = 'edit_options'; |
414
|
|
|
$context['page_desc'] = replaceBasicActionUrl($txt['forumProfile_info']); |
415
|
|
|
$context['show_preview_button'] = true; |
416
|
|
|
|
417
|
|
|
setupProfileContext( |
418
|
|
|
array( |
419
|
|
|
'avatar_choice', 'hr', |
420
|
|
|
'bday1', 'usertitle', 'hr', |
421
|
|
|
'signature', 'hr', |
422
|
|
|
'karma_good', 'hr', |
423
|
|
|
'website_title', 'website_url', |
424
|
|
|
), |
425
|
|
|
'forum' |
426
|
|
|
); |
427
|
|
|
} |
428
|
|
|
|
429
|
|
|
/** |
430
|
|
|
* Allow the edit of *someone else's* personal message settings. |
431
|
|
|
*/ |
432
|
|
|
public function action_pmprefs() |
433
|
|
|
{ |
434
|
|
|
global $context, $txt; |
435
|
|
|
|
436
|
|
|
$this->loadThemeOptions(); |
437
|
|
|
loadCustomFields($this->_memID, 'pmprefs'); |
438
|
|
|
loadTemplate('ProfileOptions'); |
439
|
|
|
|
440
|
|
|
$context['sub_template'] = 'edit_options'; |
441
|
|
|
$context['page_desc'] = $txt['pm_settings_desc']; |
442
|
|
|
|
443
|
|
|
// Setup the profile context and call the 'integrate_pmprefs_profile_fields' hook |
444
|
|
|
setupProfileContext( |
445
|
|
|
array( |
446
|
|
|
'receive_from', |
447
|
|
|
'hr', |
448
|
|
|
'pm_settings', |
449
|
|
|
), |
450
|
|
|
'pmprefs' |
451
|
|
|
); |
452
|
|
|
} |
453
|
|
|
|
454
|
|
|
/** |
455
|
|
|
* Allow the user to pick a theme. |
456
|
|
|
* |
457
|
|
|
*/ |
458
|
|
|
public function action_themepick() |
459
|
|
|
{ |
460
|
|
|
global $txt, $context; |
461
|
|
|
|
462
|
|
|
$this->loadThemeOptions(); |
463
|
|
|
|
464
|
|
|
if (allowedTo(array('profile_extra_own', 'profile_extra_any'))) |
465
|
|
|
loadCustomFields($this->_memID, 'theme'); |
466
|
|
|
|
467
|
|
|
loadTemplate('ProfileOptions'); |
468
|
|
|
|
469
|
|
|
$context['sub_template'] = 'edit_options'; |
470
|
|
|
$context['page_desc'] = $txt['theme_info']; |
471
|
|
|
|
472
|
|
|
setupProfileContext( |
473
|
|
|
array( |
474
|
|
|
'id_theme', 'smiley_set', 'hr', |
475
|
|
|
'time_format', 'time_offset', 'hr', |
476
|
|
|
'theme_settings', |
477
|
|
|
), |
478
|
|
|
'themepick' |
479
|
|
|
); |
480
|
|
|
} |
481
|
|
|
|
482
|
|
|
/** |
483
|
|
|
* Changing authentication method? |
484
|
|
|
* Only appropriate for people using OpenID. |
485
|
|
|
* |
486
|
|
|
* @param bool $saving = false |
487
|
|
|
*/ |
488
|
|
|
public function action_authentication($saving = false) |
|
|
|
|
489
|
|
|
{ |
490
|
|
|
global $context, $cur_profile, $post_errors, $modSettings; |
491
|
|
|
|
492
|
|
|
loadLanguage('Login'); |
493
|
|
|
loadTemplate('ProfileOptions'); |
494
|
|
|
|
495
|
|
|
// We are saving? |
496
|
|
|
if ($saving) |
497
|
|
|
{ |
498
|
|
|
// Moving to password passed authentication? |
499
|
|
|
if ($this->_req->post->authenticate === 'passwd') |
500
|
|
|
{ |
501
|
|
|
// Didn't enter anything? |
502
|
|
|
if ($this->_req->post->passwrd1 === '') |
503
|
|
|
$post_errors[] = 'no_password'; |
504
|
|
|
// Do the two entries for the password even match? |
505
|
|
|
elseif (!isset($this->_req->post->passwrd2) || $this->_req->post->passwrd1 != $this->_req->post->passwrd2) |
506
|
|
|
$post_errors[] = 'bad_new_password'; |
507
|
|
|
// Is it valid? |
508
|
|
|
else |
509
|
|
|
{ |
510
|
|
|
require_once(SUBSDIR . '/Auth.subs.php'); |
511
|
|
|
$passwordErrors = validatePassword($this->_req->post->passwrd1, $cur_profile['member_name'], array($cur_profile['real_name'], $cur_profile['email_address'])); |
512
|
|
|
|
513
|
|
|
// Were there errors? |
514
|
|
|
if ($passwordErrors != null) |
|
|
|
|
515
|
|
|
$post_errors[] = 'password_' . $passwordErrors; |
516
|
|
|
} |
517
|
|
|
|
518
|
|
|
if (empty($post_errors)) |
519
|
|
|
{ |
520
|
|
|
// Integration? |
521
|
|
|
call_integration_hook('integrate_reset_pass', array($cur_profile['member_name'], $cur_profile['member_name'], $this->_req->post->passwrd1)); |
522
|
|
|
|
523
|
|
|
// Go then. |
524
|
|
|
require_once(SUBSDIR . '/Auth.subs.php'); |
525
|
|
|
$new_pass = $this->_req->post->passwrd1; |
526
|
|
|
$passwd = validateLoginPassword($new_pass, '', $cur_profile['member_name'], true); |
527
|
|
|
|
528
|
|
|
// Do the important bits. |
529
|
|
|
require_once(SUBSDIR . '/Members.subs.php'); |
530
|
|
|
updateMemberData($this->_memID, array('openid_uri' => '', 'passwd' => $passwd)); |
531
|
|
|
if ($context['user']['is_owner']) |
532
|
|
|
{ |
533
|
|
|
setLoginCookie(60 * $modSettings['cookieTime'], $this->_memID, hash('sha256', $new_pass . $cur_profile['password_salt'])); |
534
|
|
|
redirectexit('action=profile;area=authentication;updated'); |
535
|
|
|
} |
536
|
|
|
else |
537
|
|
|
redirectexit('action=profile;u=' . $this->_memID); |
538
|
|
|
} |
539
|
|
|
|
540
|
|
|
return true; |
541
|
|
|
} |
542
|
|
|
// Not right yet! |
543
|
|
|
elseif ($this->_req->post->authenticate === 'openid' && !empty($this->_req->post->openid_identifier)) |
544
|
|
|
{ |
545
|
|
|
require_once(SUBSDIR . '/OpenID.subs.php'); |
546
|
|
|
require_once(SUBSDIR . '/Members.subs.php'); |
547
|
|
|
|
548
|
|
|
$openID = new OpenID(); |
549
|
|
|
$this->_req->post->openid_identifier = $openID->canonize($this->_req->post->openid_identifier); |
550
|
|
|
|
551
|
|
|
if (memberExists($this->_req->post->openid_identifier)) |
552
|
|
|
$post_errors[] = 'openid_in_use'; |
553
|
|
|
elseif (empty($post_errors)) |
554
|
|
|
{ |
555
|
|
|
// Authenticate using the new OpenID URI first to make sure they didn't make a mistake. |
556
|
|
|
if ($context['user']['is_owner']) |
557
|
|
|
{ |
558
|
|
|
$_SESSION['new_openid_uri'] = $this->_req->post->openid_identifier; |
559
|
|
|
$openID->validate($this->_req->post->openid_identifier, false, null, 'change_uri'); |
560
|
|
|
} |
561
|
|
|
else |
562
|
|
|
updateMemberData($this->_memID, array('openid_uri' => $this->_req->post->openid_identifier)); |
563
|
|
|
} |
564
|
|
|
} |
565
|
|
|
} |
566
|
|
|
|
567
|
|
|
// Some stuff for the template |
568
|
|
|
$context['member']['openid_uri'] = $cur_profile['openid_uri']; |
569
|
|
|
$context['auth_method'] = empty($cur_profile['openid_uri']) ? 'password' : 'openid'; |
570
|
|
|
$context['sub_template'] = 'authentication_method'; |
571
|
|
|
loadJavascriptFile('register.js'); |
572
|
|
|
} |
573
|
|
|
|
574
|
|
|
/** |
575
|
|
|
* Display the notifications and settings for changes. |
576
|
|
|
*/ |
577
|
|
|
public function action_notification() |
578
|
|
|
{ |
579
|
|
|
global $txt, $scripturl, $user_profile, $context, $modSettings; |
580
|
|
|
|
581
|
|
|
loadTemplate('ProfileOptions'); |
582
|
|
|
|
583
|
|
|
// Going to need this for the list. |
584
|
|
|
require_once(SUBSDIR . '/Boards.subs.php'); |
585
|
|
|
require_once(SUBSDIR . '/Topic.subs.php'); |
586
|
|
|
require_once(SUBSDIR . '/Profile.subs.php'); |
587
|
|
|
|
588
|
|
|
$context['mention_types'] = getMemberNotificationsProfile($this->_memID); |
589
|
|
|
|
590
|
|
|
// Fine, start with the board list. |
591
|
|
|
$listOptions = array( |
592
|
|
|
'id' => 'board_notification_list', |
593
|
|
|
'width' => '100%', |
594
|
|
|
'no_items_label' => $txt['notifications_boards_none'] . '<br /><br />' . $txt['notifications_boards_howto'], |
595
|
|
|
'no_items_align' => 'left', |
596
|
|
|
'base_href' => $scripturl . '?action=profile;u=' . $this->_memID . ';area=notification', |
597
|
|
|
'default_sort_col' => 'board_name', |
598
|
|
|
'get_items' => array( |
599
|
|
|
'function' => array($this, 'list_getBoardNotifications'), |
600
|
|
|
'params' => array( |
601
|
|
|
$this->_memID, |
602
|
|
|
), |
603
|
|
|
), |
604
|
|
|
'columns' => array( |
605
|
|
|
'board_name' => array( |
606
|
|
|
'header' => array( |
607
|
|
|
'value' => $txt['notifications_boards'], |
608
|
|
|
'class' => 'lefttext', |
609
|
|
|
), |
610
|
|
|
'data' => array( |
611
|
|
|
'function' => function ($board) { |
612
|
|
|
global $txt; |
613
|
|
|
|
614
|
|
|
$link = $board['link']; |
615
|
|
|
|
616
|
|
|
if ($board['new']) |
617
|
|
|
$link .= ' <a href="' . $board['href'] . '"><span class="new_posts">' . $txt['new'] . '</span></a>'; |
618
|
|
|
|
619
|
|
|
return $link; |
620
|
|
|
}, |
621
|
|
|
), |
622
|
|
|
'sort' => array( |
623
|
|
|
'default' => 'name', |
624
|
|
|
'reverse' => 'name DESC', |
625
|
|
|
), |
626
|
|
|
), |
627
|
|
|
'delete' => array( |
628
|
|
|
'header' => array( |
629
|
|
|
'value' => '<input type="checkbox" onclick="invertAll(this, this.form);" />', |
630
|
|
|
'class' => 'centertext', |
631
|
|
|
'style' => 'width:4%;', |
632
|
|
|
), |
633
|
|
|
'data' => array( |
634
|
|
|
'sprintf' => array( |
635
|
|
|
'format' => '<input type="checkbox" name="notify_boards[]" value="%1$d" %2$s />', |
636
|
|
|
'params' => array( |
637
|
|
|
'id' => false, |
638
|
|
|
'checked' => false, |
639
|
|
|
), |
640
|
|
|
), |
641
|
|
|
'class' => 'centertext', |
642
|
|
|
), |
643
|
|
|
), |
644
|
|
|
), |
645
|
|
|
'form' => array( |
646
|
|
|
'href' => $scripturl . '?action=profile;area=notification', |
647
|
|
|
'include_sort' => true, |
648
|
|
|
'include_start' => true, |
649
|
|
|
'hidden_fields' => array( |
650
|
|
|
'u' => $this->_memID, |
651
|
|
|
'sa' => $context['menu_item_selected'], |
652
|
|
|
$context['session_var'] => $context['session_id'], |
653
|
|
|
), |
654
|
|
|
'token' => $context['token_check'], |
655
|
|
|
), |
656
|
|
|
'additional_rows' => array( |
657
|
|
|
array( |
658
|
|
|
'class' => 'submitbutton', |
659
|
|
|
'position' => 'bottom_of_list', |
660
|
|
|
'value' => ' |
661
|
|
|
<input type="submit" name="edit_notify_boards" value="' . $txt['notifications_boards_update'] . '" /> |
662
|
|
|
<input type="hidden" name="save" value="save" />', |
663
|
|
|
), |
664
|
|
|
array( |
665
|
|
|
'position' => 'after_title', |
666
|
|
|
'value' => getBoardNotificationsCount($this->_memID) == 0 ? $txt['notifications_boards_none'] . '<br />' . $txt['notifications_boards_howto'] : $txt['notifications_boards_current'], |
667
|
|
|
), |
668
|
|
|
), |
669
|
|
|
); |
670
|
|
|
|
671
|
|
|
// Create the board notification list. |
672
|
|
|
createList($listOptions); |
673
|
|
|
|
674
|
|
|
// Now do the topic notifications. |
675
|
|
|
$listOptions = array( |
676
|
|
|
'id' => 'topic_notification_list', |
677
|
|
|
'width' => '100%', |
678
|
|
|
'items_per_page' => $modSettings['defaultMaxMessages'], |
679
|
|
|
'no_items_label' => $txt['notifications_topics_none'] . '<br /><br />' . $txt['notifications_topics_howto'], |
680
|
|
|
'no_items_align' => 'left', |
681
|
|
|
'base_href' => $scripturl . '?action=profile;u=' . $this->_memID . ';area=notification', |
682
|
|
|
'default_sort_col' => 'last_post', |
683
|
|
|
'get_items' => array( |
684
|
|
|
'function' => array($this, 'list_getTopicNotifications'), |
685
|
|
|
'params' => array( |
686
|
|
|
$this->_memID, |
687
|
|
|
), |
688
|
|
|
), |
689
|
|
|
'get_count' => array( |
690
|
|
|
'function' => array($this, 'list_getTopicNotificationCount'), |
691
|
|
|
'params' => array( |
692
|
|
|
$this->_memID, |
693
|
|
|
), |
694
|
|
|
), |
695
|
|
|
'columns' => array( |
696
|
|
|
'subject' => array( |
697
|
|
|
'header' => array( |
698
|
|
|
'value' => $txt['notifications_topics'], |
699
|
|
|
'class' => 'lefttext', |
700
|
|
|
), |
701
|
|
|
'data' => array( |
702
|
|
|
'function' => function ($topic) { |
703
|
|
|
global $txt; |
704
|
|
|
|
705
|
|
|
$link = $topic['link']; |
706
|
|
|
|
707
|
|
|
if ($topic['new']) |
708
|
|
|
$link .= ' <a href="' . $topic['new_href'] . '"><span class="new_posts">' . $txt['new'] . '</span></a>'; |
709
|
|
|
|
710
|
|
|
$link .= '<br /><span class="smalltext"><em>' . $txt['in'] . ' ' . $topic['board_link'] . '</em></span>'; |
711
|
|
|
|
712
|
|
|
return $link; |
713
|
|
|
}, |
714
|
|
|
), |
715
|
|
|
'sort' => array( |
716
|
|
|
'default' => 'ms.subject', |
717
|
|
|
'reverse' => 'ms.subject DESC', |
718
|
|
|
), |
719
|
|
|
), |
720
|
|
|
'started_by' => array( |
721
|
|
|
'header' => array( |
722
|
|
|
'value' => $txt['started_by'], |
723
|
|
|
'class' => 'lefttext', |
724
|
|
|
), |
725
|
|
|
'data' => array( |
726
|
|
|
'db' => 'poster_link', |
727
|
|
|
), |
728
|
|
|
'sort' => array( |
729
|
|
|
'default' => 'real_name_col', |
730
|
|
|
'reverse' => 'real_name_col DESC', |
731
|
|
|
), |
732
|
|
|
), |
733
|
|
|
'last_post' => array( |
734
|
|
|
'header' => array( |
735
|
|
|
'value' => $txt['last_post'], |
736
|
|
|
'class' => 'lefttext', |
737
|
|
|
), |
738
|
|
|
'data' => array( |
739
|
|
|
'sprintf' => array( |
740
|
|
|
'format' => '<span class="smalltext">%1$s<br />' . $txt['by'] . ' %2$s</span>', |
741
|
|
|
'params' => array( |
742
|
|
|
'updated' => false, |
743
|
|
|
'poster_updated_link' => false, |
744
|
|
|
), |
745
|
|
|
), |
746
|
|
|
), |
747
|
|
|
'sort' => array( |
748
|
|
|
'default' => 'ml.id_msg DESC', |
749
|
|
|
'reverse' => 'ml.id_msg', |
750
|
|
|
), |
751
|
|
|
), |
752
|
|
|
'delete' => array( |
753
|
|
|
'header' => array( |
754
|
|
|
'value' => '<input type="checkbox" onclick="invertAll(this, this.form);" />', |
755
|
|
|
'class' => 'centertext', |
756
|
|
|
'style' => 'width:4%;', |
757
|
|
|
), |
758
|
|
|
'data' => array( |
759
|
|
|
'sprintf' => array( |
760
|
|
|
'format' => '<input type="checkbox" name="notify_topics[]" value="%1$d" />', |
761
|
|
|
'params' => array( |
762
|
|
|
'id' => false, |
763
|
|
|
), |
764
|
|
|
), |
765
|
|
|
'class' => 'centertext', |
766
|
|
|
), |
767
|
|
|
), |
768
|
|
|
), |
769
|
|
|
'form' => array( |
770
|
|
|
'href' => $scripturl . '?action=profile;area=notification', |
771
|
|
|
'include_sort' => true, |
772
|
|
|
'include_start' => true, |
773
|
|
|
'hidden_fields' => array( |
774
|
|
|
'u' => $this->_memID, |
775
|
|
|
'sa' => $context['menu_item_selected'], |
776
|
|
|
$context['session_var'] => $context['session_id'], |
777
|
|
|
), |
778
|
|
|
'token' => $context['token_check'], |
779
|
|
|
), |
780
|
|
|
'additional_rows' => array( |
781
|
|
|
array( |
782
|
|
|
'class' => 'submitbutton', |
783
|
|
|
'position' => 'bottom_of_list', |
784
|
|
|
'value' => ' |
785
|
|
|
<input type="submit" name="edit_notify_topics" value="' . $txt['notifications_update'] . '" /> |
786
|
|
|
<input type="hidden" name="save" value="save" />', |
787
|
|
|
), |
788
|
|
|
), |
789
|
|
|
); |
790
|
|
|
|
791
|
|
|
// Create the notification list. |
792
|
|
|
createList($listOptions); |
793
|
|
|
|
794
|
|
|
// What options are set? |
795
|
|
|
$context['member'] += array( |
796
|
|
|
'notify_announcements' => $user_profile[$this->_memID]['notify_announcements'], |
797
|
|
|
'notify_send_body' => $user_profile[$this->_memID]['notify_send_body'], |
798
|
|
|
'notify_types' => $user_profile[$this->_memID]['notify_types'], |
799
|
|
|
'notify_regularity' => $user_profile[$this->_memID]['notify_regularity'], |
800
|
|
|
); |
801
|
|
|
|
802
|
|
|
$this->loadThemeOptions(); |
803
|
|
|
} |
804
|
|
|
|
805
|
|
|
/** |
806
|
|
|
* Callback for createList() in action_notification() |
807
|
|
|
* |
808
|
|
|
* - Retrieve topic notifications count. |
809
|
|
|
* |
810
|
|
|
* @param int $memID id_member the id of the member who's notifications we are loading |
811
|
|
|
* @return integer |
812
|
|
|
*/ |
813
|
|
|
public function list_getTopicNotificationCount($memID) |
814
|
|
|
{ |
815
|
|
|
// Topic notifications count, for the list |
816
|
|
|
return topicNotificationCount($memID); |
817
|
|
|
} |
818
|
|
|
|
819
|
|
|
/** |
820
|
|
|
* Callback for createList() in action_notification() |
821
|
|
|
* |
822
|
|
|
* @param int $start The item to start with (for pagination purposes) |
823
|
|
|
* @param int $items_per_page The number of items to show per page |
824
|
|
|
* @param string $sort A string indicating how to sort the results |
825
|
|
|
* @param int $memID id_member |
826
|
|
|
* @return mixed array of topic notifications |
827
|
|
|
*/ |
828
|
|
|
public function list_getTopicNotifications($start, $items_per_page, $sort, $memID) |
829
|
|
|
{ |
830
|
|
|
// Topic notifications, for the list |
831
|
|
|
return topicNotifications($start, $items_per_page, $sort, $memID); |
832
|
|
|
} |
833
|
|
|
|
834
|
|
|
/** |
835
|
|
|
* Callback for createList() in action_notification() |
836
|
|
|
* |
837
|
|
|
* @uses template_ignoreboards() |
838
|
|
|
* @param int $start The item to start with (for pagination purposes) |
839
|
|
|
* @param int $items_per_page The number of items to show per page |
840
|
|
|
* @param string $sort A string indicating how to sort the results |
841
|
|
|
* @param int $memID id_member |
842
|
|
|
* @return mixed[] array of board notifications |
843
|
|
|
*/ |
844
|
|
|
public function list_getBoardNotifications($start, $items_per_page, $sort, $memID) |
845
|
|
|
{ |
846
|
|
|
// Return boards you see and their notification status for the list |
847
|
|
|
return boardNotifications($start, $items_per_page, $sort, $memID); |
848
|
|
|
} |
849
|
|
|
|
850
|
|
|
/** |
851
|
|
|
* Allows the user to see the list of their ignored boards. |
852
|
|
|
* (and un-ignore them) |
853
|
|
|
*/ |
854
|
|
|
public function action_ignoreboards() |
855
|
|
|
{ |
856
|
|
|
global $context, $modSettings, $cur_profile; |
857
|
|
|
|
858
|
|
|
// Have the admins enabled this option? |
859
|
|
|
if (empty($modSettings['allow_ignore_boards'])) |
860
|
|
|
Errors::instance()->fatal_lang_error('ignoreboards_disallowed', 'user'); |
861
|
|
|
|
862
|
|
|
loadTemplate('ProfileOptions'); |
863
|
|
|
|
864
|
|
|
$context['sub_template'] = 'ignoreboards'; |
865
|
|
|
require_once(SUBSDIR . '/Boards.subs.php'); |
866
|
|
|
$context += getBoardList(array('not_redirection' => true, 'ignore' => !empty($cur_profile['ignore_boards']) ? explode(',', $cur_profile['ignore_boards']) : array())); |
867
|
|
|
|
868
|
|
|
// Include a list of boards per category for easy toggling. |
869
|
|
View Code Duplication |
foreach ($context['categories'] as $cat => &$category) |
870
|
|
|
{ |
871
|
|
|
$context['boards_in_category'][$cat] = count($category['boards']); |
872
|
|
|
$category['child_ids'] = array_keys($category['boards']); |
873
|
|
|
} |
874
|
|
|
|
875
|
|
|
$this->loadThemeOptions(); |
876
|
|
|
} |
877
|
|
|
|
878
|
|
|
/** |
879
|
|
|
* Function to allow the user to choose group membership etc... |
880
|
|
|
*/ |
881
|
|
|
public function action_groupMembership() |
882
|
|
|
{ |
883
|
|
|
global $txt, $user_profile, $context; |
884
|
|
|
|
885
|
|
|
loadTemplate('ProfileOptions'); |
886
|
|
|
$context['sub_template'] = 'groupMembership'; |
887
|
|
|
|
888
|
|
|
$curMember = $user_profile[$this->_memID]; |
889
|
|
|
$context['primary_group'] = $curMember['id_group']; |
890
|
|
|
|
891
|
|
|
// Can they manage groups? |
892
|
|
|
$context['can_manage_membergroups'] = allowedTo('manage_membergroups'); |
893
|
|
|
$context['can_manage_protected'] = allowedTo('admin_forum'); |
894
|
|
|
$context['can_edit_primary'] = $context['can_manage_protected']; |
895
|
|
|
$context['update_message'] = isset($this->_req->query->msg) && isset($txt['group_membership_msg_' . $this->_req->query->msg]) ? $txt['group_membership_msg_' . $this->_req->query->msg] : ''; |
896
|
|
|
|
897
|
|
|
// Get all the groups this user is a member of. |
898
|
|
|
$groups = explode(',', $curMember['additional_groups']); |
899
|
|
|
$groups[] = $curMember['id_group']; |
900
|
|
|
|
901
|
|
|
// Ensure the query doesn't croak! |
902
|
|
|
if (empty($groups)) |
903
|
|
|
$groups = array(0); |
904
|
|
|
|
905
|
|
|
// Just to be sure... |
906
|
|
|
$groups = array_map('intval', $groups); |
907
|
|
|
|
908
|
|
|
// Get all the membergroups they can join. |
909
|
|
|
require_once(SUBSDIR . '/ProfileOptions.subs.php'); |
910
|
|
|
$context['groups'] = loadMembergroupsJoin($groups, $this->_memID); |
911
|
|
|
|
912
|
|
|
// Add registered members on the end. |
913
|
|
|
$context['groups']['member'][0] = array( |
914
|
|
|
'id' => 0, |
915
|
|
|
'name' => $txt['regular_members'], |
916
|
|
|
'desc' => $txt['regular_members_desc'], |
917
|
|
|
'type' => 0, |
918
|
|
|
'is_primary' => $context['primary_group'] == 0 ? true : false, |
919
|
|
|
'can_be_primary' => true, |
920
|
|
|
'can_leave' => 0, |
921
|
|
|
); |
922
|
|
|
|
923
|
|
|
// No changing primary one unless you have enough groups! |
924
|
|
|
if (count($context['groups']['member']) < 2) |
925
|
|
|
$context['can_edit_primary'] = false; |
926
|
|
|
|
927
|
|
|
// In the special case that someone is requesting membership of a group, setup some special context vars. |
928
|
|
|
if (isset($this->_req->query->request) |
929
|
|
|
&& isset($context['groups']['available'][(int) $this->_req->query->request]) |
930
|
|
|
&& $context['groups']['available'][(int) $this->_req->query->request]['type'] == 2) |
931
|
|
|
{ |
932
|
|
|
$context['group_request'] = $context['groups']['available'][(int) $this->_req->query->request]; |
933
|
|
|
} |
934
|
|
|
} |
935
|
|
|
|
936
|
|
|
/** |
937
|
|
|
* This function actually makes all the group changes |
938
|
|
|
* |
939
|
|
|
* @return string |
940
|
|
|
*/ |
941
|
|
|
public function action_groupMembership2() |
|
|
|
|
942
|
|
|
{ |
943
|
|
|
global $context, $user_profile, $modSettings, $scripturl, $language; |
944
|
|
|
|
945
|
|
|
// Let's be extra cautious... |
946
|
|
|
if (!$context['user']['is_owner'] || empty($modSettings['show_group_membership'])) |
947
|
|
|
isAllowedTo('manage_membergroups'); |
948
|
|
|
|
949
|
|
|
$group_id = $this->_req->getPost('gid', 'intval', $this->_req->getQuery('gid', 'intval', null)); |
950
|
|
|
|
951
|
|
View Code Duplication |
if (!isset($group_id) && !isset($this->_req->post->primary)) |
952
|
|
|
Errors::instance()->fatal_lang_error('no_access', false); |
953
|
|
|
|
954
|
|
|
// GID may be from a link or a form |
955
|
|
|
checkSession(isset($this->_req->query->gid) ? 'get' : 'post'); |
956
|
|
|
|
957
|
|
|
require_once(SUBSDIR . '/Membergroups.subs.php'); |
958
|
|
|
|
959
|
|
|
$old_profile = &$user_profile[$this->_memID]; |
960
|
|
|
$context['can_manage_membergroups'] = allowedTo('manage_membergroups'); |
961
|
|
|
$context['can_manage_protected'] = allowedTo('admin_forum'); |
962
|
|
|
|
963
|
|
|
// By default the new primary is the old one. |
964
|
|
|
$newPrimary = $old_profile['id_group']; |
965
|
|
|
$addGroups = array_flip(explode(',', $old_profile['additional_groups'])); |
966
|
|
|
$canChangePrimary = $old_profile['id_group'] == 0 ? 1 : 0; |
967
|
|
|
$changeType = isset($this->_req->post->primary) ? 'primary' : (isset($this->_req->post->req) ? 'request' : 'free'); |
968
|
|
|
|
969
|
|
|
// One way or another, we have a target group in mind... |
970
|
|
|
$group_id = isset($group_id) ? $group_id : (int) $this->_req->post->primary; |
971
|
|
|
$foundTarget = $changeType === 'primary' && $group_id == 0 ? true : false; |
972
|
|
|
|
973
|
|
|
// Sanity check!! |
974
|
|
|
if ($group_id == 1) |
975
|
|
|
isAllowedTo('admin_forum'); |
976
|
|
|
|
977
|
|
|
// What ever we are doing, we need to determine if changing primary is possible! |
978
|
|
|
$groups_details = membergroupsById(array($group_id, $old_profile['id_group']), 0, true); |
979
|
|
|
|
980
|
|
|
// Protected groups require proper permissions! |
981
|
|
|
if ($group_id != 1 && $groups_details[$group_id]['group_type'] == 1) |
982
|
|
|
isAllowedTo('admin_forum'); |
983
|
|
|
|
984
|
|
|
foreach ($groups_details as $key => $row) |
985
|
|
|
{ |
986
|
|
|
// Is this the new group? |
987
|
|
|
if ($row['id_group'] == $group_id) |
988
|
|
|
{ |
989
|
|
|
$foundTarget = true; |
990
|
|
|
$group_name = $row['group_name']; |
991
|
|
|
|
992
|
|
|
// Does the group type match what we're doing - are we trying to request a non-requestable group? |
993
|
|
|
if ($changeType === 'request' && $row['group_type'] != 2) |
994
|
|
|
Errors::instance()->fatal_lang_error('no_access', false); |
995
|
|
|
// What about leaving a requestable group we are not a member of? |
996
|
|
|
elseif ($changeType === 'free' && $row['group_type'] == 2 && $old_profile['id_group'] != $row['id_group'] && !isset($addGroups[$row['id_group']])) |
997
|
|
|
Errors::instance()->fatal_lang_error('no_access', false); |
998
|
|
|
elseif ($changeType === 'free' && $row['group_type'] != 3 && $row['group_type'] != 2) |
999
|
|
|
Errors::instance()->fatal_lang_error('no_access', false); |
1000
|
|
|
|
1001
|
|
|
// We can't change the primary group if this is hidden! |
1002
|
|
|
if ($row['hidden'] == 2) |
1003
|
|
|
$canChangePrimary = false; |
1004
|
|
|
} |
1005
|
|
|
|
1006
|
|
|
// If this is their old primary, can we change it? |
1007
|
|
View Code Duplication |
if ($row['id_group'] == $old_profile['id_group'] && ($row['group_type'] > 1 || $context['can_manage_membergroups']) && $canChangePrimary !== false) |
1008
|
|
|
$canChangePrimary = 1; |
1009
|
|
|
|
1010
|
|
|
// If we are not doing a force primary move, don't do it automatically if current primary is not 0. |
1011
|
|
|
if ($changeType != 'primary' && $old_profile['id_group'] != 0) |
1012
|
|
|
$canChangePrimary = false; |
1013
|
|
|
|
1014
|
|
|
// If this is the one we are acting on, can we even act? |
1015
|
|
View Code Duplication |
if ((!$context['can_manage_protected'] && $row['group_type'] == 1) || (!$context['can_manage_membergroups'] && $row['group_type'] == 0)) |
1016
|
|
|
$canChangePrimary = false; |
1017
|
|
|
} |
1018
|
|
|
|
1019
|
|
|
// Didn't find the target? |
1020
|
|
|
if (!$foundTarget) |
1021
|
|
|
Errors::instance()->fatal_lang_error('no_access', false); |
1022
|
|
|
|
1023
|
|
|
// Final security check, don't allow users to promote themselves to admin. |
1024
|
|
|
require_once(SUBSDIR . '/ProfileOptions.subs.php'); |
1025
|
|
|
if ($context['can_manage_membergroups'] && !allowedTo('admin_forum')) |
1026
|
|
|
{ |
1027
|
|
|
$disallow = checkMembergroupChange($group_id); |
1028
|
|
|
if ($disallow) |
1029
|
|
|
isAllowedTo('admin_forum'); |
1030
|
|
|
} |
1031
|
|
|
|
1032
|
|
|
// If we're requesting, add the note then return. |
1033
|
|
|
if ($changeType === 'request') |
1034
|
|
|
{ |
1035
|
|
|
if (logMembergroupRequest($group_id, $this->_memID)) |
1036
|
|
|
Errors::instance()->fatal_lang_error('profile_error_already_requested_group'); |
1037
|
|
|
|
1038
|
|
|
// Send an email to all group moderators etc. |
1039
|
|
|
require_once(SUBSDIR . '/Mail.subs.php'); |
1040
|
|
|
|
1041
|
|
|
// Do we have any group moderators? |
1042
|
|
|
require_once(SUBSDIR . '/Membergroups.subs.php'); |
1043
|
|
|
$moderators = array_keys(getGroupModerators($group_id)); |
1044
|
|
|
|
1045
|
|
|
// Otherwise this is the backup! |
1046
|
|
|
if (empty($moderators)) |
1047
|
|
|
{ |
1048
|
|
|
require_once(SUBSDIR . '/Members.subs.php'); |
1049
|
|
|
$moderators = membersAllowedTo('manage_membergroups'); |
1050
|
|
|
} |
1051
|
|
|
|
1052
|
|
|
if (!empty($moderators)) |
1053
|
|
|
{ |
1054
|
|
|
require_once(SUBSDIR . '/Members.subs.php'); |
1055
|
|
|
$members = getBasicMemberData($moderators, array('preferences' => true, 'sort' => 'lngfile')); |
1056
|
|
|
|
1057
|
|
|
foreach ($members as $member) |
1058
|
|
|
{ |
1059
|
|
|
if ($member['notify_types'] != 4) |
1060
|
|
|
continue; |
1061
|
|
|
|
1062
|
|
|
// Check whether they are interested. |
1063
|
|
View Code Duplication |
if (!empty($member['mod_prefs'])) |
1064
|
|
|
{ |
1065
|
|
|
list (,, $pref_binary) = explode('|', $member['mod_prefs']); |
1066
|
|
|
if (!($pref_binary & 4)) |
1067
|
|
|
continue; |
1068
|
|
|
} |
1069
|
|
|
|
1070
|
|
|
$replacements = array( |
1071
|
|
|
'RECPNAME' => $member['member_name'], |
1072
|
|
|
'APPYNAME' => $old_profile['member_name'], |
1073
|
|
|
'GROUPNAME' => $group_name, |
|
|
|
|
1074
|
|
|
'REASON' => $this->_req->post->reason, |
1075
|
|
|
'MODLINK' => $scripturl . '?action=moderate;area=groups;sa=requests', |
1076
|
|
|
); |
1077
|
|
|
|
1078
|
|
|
$emaildata = loadEmailTemplate('request_membership', $replacements, empty($member['lngfile']) || empty($modSettings['userLanguage']) ? $language : $member['lngfile']); |
1079
|
|
|
sendmail($member['email_address'], $emaildata['subject'], $emaildata['body'], null, null, false, 2); |
1080
|
|
|
} |
1081
|
|
|
} |
1082
|
|
|
|
1083
|
|
|
return $changeType; |
1084
|
|
|
} |
1085
|
|
|
// Otherwise we are leaving/joining a group. |
1086
|
|
|
elseif ($changeType === 'free') |
1087
|
|
|
{ |
1088
|
|
|
// Are we leaving? |
1089
|
|
|
if ($old_profile['id_group'] == $group_id || isset($addGroups[$group_id])) |
1090
|
|
|
{ |
1091
|
|
|
if ($old_profile['id_group'] == $group_id) |
1092
|
|
|
$newPrimary = 0; |
1093
|
|
|
else |
1094
|
|
|
unset($addGroups[$group_id]); |
1095
|
|
|
} |
1096
|
|
|
// ... if not, must be joining. |
1097
|
|
|
else |
1098
|
|
|
{ |
1099
|
|
|
// Can we change the primary, and do we want to? |
1100
|
|
|
if ($canChangePrimary) |
|
|
|
|
1101
|
|
|
{ |
1102
|
|
|
if ($old_profile['id_group'] != 0) |
1103
|
|
|
$addGroups[$old_profile['id_group']] = -1; |
1104
|
|
|
$newPrimary = $group_id; |
1105
|
|
|
} |
1106
|
|
|
// Otherwise it's an additional group... |
1107
|
|
|
else |
1108
|
|
|
$addGroups[$group_id] = -1; |
1109
|
|
|
} |
1110
|
|
|
} |
1111
|
|
|
// Finally, we must be setting the primary. |
1112
|
|
|
elseif ($canChangePrimary) |
|
|
|
|
1113
|
|
|
{ |
1114
|
|
|
if ($old_profile['id_group'] != 0) |
1115
|
|
|
$addGroups[$old_profile['id_group']] = -1; |
1116
|
|
|
if (isset($addGroups[$group_id])) |
1117
|
|
|
unset($addGroups[$group_id]); |
1118
|
|
|
$newPrimary = $group_id; |
1119
|
|
|
} |
1120
|
|
|
|
1121
|
|
|
// Finally, we can make the changes! |
1122
|
|
|
foreach ($addGroups as $id => $dummy) |
1123
|
|
|
{ |
1124
|
|
|
if (empty($id)) |
1125
|
|
|
unset($addGroups[$id]); |
1126
|
|
|
} |
1127
|
|
|
$addGroups = implode(',', array_flip($addGroups)); |
1128
|
|
|
|
1129
|
|
|
// Ensure that we don't cache permissions if the group is changing. |
1130
|
|
View Code Duplication |
if ($context['user']['is_owner']) |
1131
|
|
|
$_SESSION['mc']['time'] = 0; |
1132
|
|
|
else |
1133
|
|
|
updateSettings(array('settings_updated' => time())); |
1134
|
|
|
|
1135
|
|
|
require_once(SUBSDIR . '/Members.subs.php'); |
1136
|
|
|
updateMemberData($this->_memID, array('id_group' => $newPrimary, 'additional_groups' => $addGroups)); |
1137
|
|
|
|
1138
|
|
|
return $changeType; |
1139
|
|
|
} |
1140
|
|
|
|
1141
|
|
|
/** |
1142
|
|
|
* Load the options for an user. |
1143
|
|
|
*/ |
1144
|
|
|
public function loadThemeOptions() |
1145
|
|
|
{ |
1146
|
|
|
global $context, $options, $cur_profile; |
1147
|
|
|
|
1148
|
|
View Code Duplication |
if (isset($this->_req->post->default_options)) |
1149
|
|
|
$this->_req->post->options = isset($this->_req->post->options) ? $this->_req->post->options + $this->_req->post->default_options : $this->_req->post->default_options; |
1150
|
|
|
|
1151
|
|
|
if ($context['user']['is_owner']) |
1152
|
|
|
{ |
1153
|
|
|
$context['member']['options'] = $options; |
1154
|
|
|
|
1155
|
|
|
if (isset($this->_req->post->options) && is_array($this->_req->post->options)) |
1156
|
|
|
{ |
1157
|
|
|
foreach ($this->_req->post->options as $k => $v) |
1158
|
|
|
$context['member']['options'][$k] = $v; |
1159
|
|
|
} |
1160
|
|
|
} |
1161
|
|
|
else |
1162
|
|
|
{ |
1163
|
|
|
require_once(SUBSDIR . '/Themes.subs.php'); |
1164
|
|
|
$context['member']['options'] = loadThemeOptionsInto(array(1, (int) $cur_profile['id_theme']), array(-1, $this->_memID), $context['member']['options']); |
|
|
|
|
1165
|
|
|
|
1166
|
|
|
if (isset($this->_req->post->options)) |
1167
|
|
|
{ |
1168
|
|
|
foreach ($this->_req->post->options as $var => $val) |
1169
|
|
|
$context['member']['options'][$var] = $val; |
1170
|
|
|
} |
1171
|
|
|
} |
1172
|
|
|
} |
1173
|
|
|
} |
The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.
The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.
To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.