1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* This file manages... the news. :P |
5
|
|
|
* |
6
|
|
|
* Simple Machines Forum (SMF) |
7
|
|
|
* |
8
|
|
|
* @package SMF |
9
|
|
|
* @author Simple Machines https://www.simplemachines.org |
10
|
|
|
* @copyright 2022 Simple Machines and individual contributors |
11
|
|
|
* @license https://www.simplemachines.org/about/smf/license.php BSD |
12
|
|
|
* |
13
|
|
|
* @version 2.1.0 |
14
|
|
|
*/ |
15
|
|
|
|
16
|
|
|
if (!defined('SMF')) |
17
|
|
|
die('No direct access...'); |
18
|
|
|
|
19
|
|
|
/** |
20
|
|
|
* The news dispatcher; doesn't do anything, just delegates. |
21
|
|
|
* This is the entrance point for all News and Newsletter screens. |
22
|
|
|
* Called by ?action=admin;area=news. |
23
|
|
|
* It does the permission checks, and calls the appropriate function |
24
|
|
|
* based on the requested sub-action. |
25
|
|
|
*/ |
26
|
|
|
function ManageNews() |
27
|
|
|
{ |
28
|
|
|
global $context, $txt; |
29
|
|
|
|
30
|
|
|
// First, let's do a quick permissions check for the best error message possible. |
31
|
|
|
isAllowedTo(array('edit_news', 'send_mail', 'admin_forum')); |
32
|
|
|
|
33
|
|
|
loadTemplate('ManageNews'); |
34
|
|
|
|
35
|
|
|
// Format: 'sub-action' => array('function', 'permission') |
36
|
|
|
$subActions = array( |
37
|
|
|
'editnews' => array('EditNews', 'edit_news'), |
38
|
|
|
'mailingmembers' => array('SelectMailingMembers', 'send_mail'), |
39
|
|
|
'mailingcompose' => array('ComposeMailing', 'send_mail'), |
40
|
|
|
'mailingsend' => array('SendMailing', 'send_mail'), |
41
|
|
|
'settings' => array('ModifyNewsSettings', 'admin_forum'), |
42
|
|
|
); |
43
|
|
|
|
44
|
|
|
call_integration_hook('integrate_manage_news', array(&$subActions)); |
45
|
|
|
|
46
|
|
|
// Default to sub action 'main' or 'settings' depending on permissions. |
47
|
|
|
$_REQUEST['sa'] = isset($_REQUEST['sa']) && isset($subActions[$_REQUEST['sa']]) ? $_REQUEST['sa'] : (allowedTo('edit_news') ? 'editnews' : (allowedTo('send_mail') ? 'mailingmembers' : 'settings')); |
48
|
|
|
|
49
|
|
|
// Have you got the proper permissions? |
50
|
|
|
isAllowedTo($subActions[$_REQUEST['sa']][1]); |
51
|
|
|
|
52
|
|
|
// Create the tabs for the template. |
53
|
|
|
$context[$context['admin_menu_name']]['tab_data'] = array( |
54
|
|
|
'title' => $txt['news_title'], |
55
|
|
|
'help' => 'edit_news', |
56
|
|
|
'description' => $txt['admin_news_desc'], |
57
|
|
|
'tabs' => array( |
58
|
|
|
'editnews' => array( |
59
|
|
|
), |
60
|
|
|
'mailingmembers' => array( |
61
|
|
|
'description' => $txt['news_mailing_desc'], |
62
|
|
|
), |
63
|
|
|
'settings' => array( |
64
|
|
|
'description' => $txt['news_settings_desc'], |
65
|
|
|
), |
66
|
|
|
), |
67
|
|
|
); |
68
|
|
|
|
69
|
|
|
// Force the right area... |
70
|
|
|
if (substr($_REQUEST['sa'], 0, 7) == 'mailing') |
71
|
|
|
$context[$context['admin_menu_name']]['current_subsection'] = 'mailingmembers'; |
72
|
|
|
|
73
|
|
|
call_helper($subActions[$_REQUEST['sa']][0]); |
74
|
|
|
} |
75
|
|
|
|
76
|
|
|
/** |
77
|
|
|
* Let the administrator(s) edit the news items for the forum. |
78
|
|
|
* It writes an entry into the moderation log. |
79
|
|
|
* This function uses the edit_news administration area. |
80
|
|
|
* Called by ?action=admin;area=news. |
81
|
|
|
* Requires the edit_news permission. |
82
|
|
|
* Can be accessed with ?action=admin;sa=editnews. |
83
|
|
|
* |
84
|
|
|
* Uses a standard list (@see createList()) |
85
|
|
|
*/ |
86
|
|
|
function EditNews() |
87
|
|
|
{ |
88
|
|
|
global $txt, $modSettings, $context, $sourcedir, $scripturl; |
89
|
|
|
global $smcFunc; |
90
|
|
|
|
91
|
|
|
require_once($sourcedir . '/Subs-Post.php'); |
92
|
|
|
|
93
|
|
|
// The 'remove selected' button was pressed. |
94
|
|
|
if (!empty($_POST['delete_selection']) && !empty($_POST['remove'])) |
95
|
|
|
{ |
96
|
|
|
checkSession(); |
97
|
|
|
|
98
|
|
|
// Store the news temporarily in this array. |
99
|
|
|
$temp_news = explode("\n", $modSettings['news']); |
100
|
|
|
|
101
|
|
|
// Remove the items that were selected. |
102
|
|
|
foreach ($temp_news as $i => $news) |
103
|
|
|
if (in_array($i, $_POST['remove'])) |
104
|
|
|
unset($temp_news[$i]); |
105
|
|
|
|
106
|
|
|
// Update the database. |
107
|
|
|
updateSettings(array('news' => implode("\n", $temp_news))); |
108
|
|
|
|
109
|
|
|
$context['saved_successful'] = true; |
110
|
|
|
|
111
|
|
|
logAction('news'); |
112
|
|
|
} |
113
|
|
|
// The 'Save' button was pressed. |
114
|
|
|
elseif (!empty($_POST['save_items'])) |
115
|
|
|
{ |
116
|
|
|
checkSession(); |
117
|
|
|
|
118
|
|
|
foreach ($_POST['news'] as $i => $news) |
119
|
|
|
{ |
120
|
|
|
if (trim($news) == '') |
121
|
|
|
unset($_POST['news'][$i]); |
122
|
|
|
else |
123
|
|
|
{ |
124
|
|
|
$_POST['news'][$i] = $smcFunc['htmlspecialchars']($_POST['news'][$i], ENT_QUOTES); |
125
|
|
|
preparsecode($_POST['news'][$i]); |
126
|
|
|
} |
127
|
|
|
} |
128
|
|
|
|
129
|
|
|
// Send the new news to the database. |
130
|
|
|
updateSettings(array('news' => implode("\n", $_POST['news']))); |
131
|
|
|
|
132
|
|
|
$context['saved_successful'] = true; |
133
|
|
|
|
134
|
|
|
// Log this into the moderation log. |
135
|
|
|
logAction('news'); |
136
|
|
|
} |
137
|
|
|
|
138
|
|
|
// We're going to want this for making our list. |
139
|
|
|
require_once($sourcedir . '/Subs-List.php'); |
140
|
|
|
|
141
|
|
|
$context['page_title'] = $txt['admin_edit_news']; |
142
|
|
|
|
143
|
|
|
// Use the standard templates for showing this. |
144
|
|
|
$listOptions = array( |
145
|
|
|
'id' => 'news_lists', |
146
|
|
|
'get_items' => array( |
147
|
|
|
'function' => 'list_getNews', |
148
|
|
|
), |
149
|
|
|
'columns' => array( |
150
|
|
|
'news' => array( |
151
|
|
|
'header' => array( |
152
|
|
|
'value' => $txt['admin_edit_news'], |
153
|
|
|
'class' => 'half_table', |
154
|
|
|
), |
155
|
|
|
'data' => array( |
156
|
|
|
'function' => function($news) |
157
|
|
|
{ |
158
|
|
|
if (is_numeric($news['id'])) |
159
|
|
|
return ' |
160
|
|
|
<textarea id="data_' . $news['id'] . '" rows="3" cols="50" name="news[]" class="padding block">' . $news['unparsed'] . '</textarea> |
161
|
|
|
<div class="floatleft" id="preview_' . $news['id'] . '"></div>'; |
162
|
|
|
else |
163
|
|
|
return $news['unparsed']; |
164
|
|
|
}, |
165
|
|
|
'class' => 'half_table', |
166
|
|
|
), |
167
|
|
|
), |
168
|
|
|
'preview' => array( |
169
|
|
|
'header' => array( |
170
|
|
|
'value' => $txt['preview'], |
171
|
|
|
'class' => 'half_table', |
172
|
|
|
), |
173
|
|
|
'data' => array( |
174
|
|
|
'function' => function($news) |
175
|
|
|
{ |
176
|
|
|
return '<div id="box_preview_' . $news['id'] . '" style="overflow: auto; width: 100%; height: 10ex;">' . $news['parsed'] . '</div>'; |
177
|
|
|
}, |
178
|
|
|
'class' => 'half_table', |
179
|
|
|
), |
180
|
|
|
), |
181
|
|
|
'check' => array( |
182
|
|
|
'header' => array( |
183
|
|
|
'value' => '<input type="checkbox" onclick="invertAll(this, this.form);">', |
184
|
|
|
'class' => 'centercol icon', |
185
|
|
|
), |
186
|
|
|
'data' => array( |
187
|
|
|
'function' => function($news) |
188
|
|
|
{ |
189
|
|
|
if (is_numeric($news['id'])) |
190
|
|
|
return '<input type="checkbox" name="remove[]" value="' . $news['id'] . '">'; |
191
|
|
|
else |
192
|
|
|
return ''; |
193
|
|
|
}, |
194
|
|
|
'class' => 'centercol icon', |
195
|
|
|
), |
196
|
|
|
), |
197
|
|
|
), |
198
|
|
|
'form' => array( |
199
|
|
|
'href' => $scripturl . '?action=admin;area=news;sa=editnews', |
200
|
|
|
'hidden_fields' => array( |
201
|
|
|
$context['session_var'] => $context['session_id'], |
202
|
|
|
), |
203
|
|
|
), |
204
|
|
|
'additional_rows' => array( |
205
|
|
|
array( |
206
|
|
|
'position' => 'bottom_of_list', |
207
|
|
|
'value' => ' |
208
|
|
|
<span id="moreNewsItems_link" class="floatleft" style="display: none;"> |
209
|
|
|
<a class="button" href="javascript:void(0);" onclick="addNewsItem(); return false;">' . $txt['editnews_clickadd'] . '</a> |
210
|
|
|
</span> |
211
|
|
|
<input type="submit" name="save_items" value="' . $txt['save'] . '" class="button"> |
212
|
|
|
<input type="submit" name="delete_selection" value="' . $txt['editnews_remove_selected'] . '" data-confirm="' . $txt['editnews_remove_confirm'] . '" class="button you_sure">', |
213
|
|
|
), |
214
|
|
|
), |
215
|
|
|
'javascript' => ' |
216
|
|
|
document.getElementById(\'list_news_lists_last\').style.display = "none"; |
217
|
|
|
document.getElementById("moreNewsItems_link").style.display = ""; |
218
|
|
|
var last_preview = 0; |
219
|
|
|
|
220
|
|
|
$(document).ready(function () { |
221
|
|
|
$("div[id ^= \'preview_\']").each(function () { |
222
|
|
|
var preview_id = $(this).attr(\'id\').split(\'_\')[1]; |
223
|
|
|
if (last_preview < preview_id) |
224
|
|
|
last_preview = preview_id; |
225
|
|
|
make_preview_btn(preview_id); |
226
|
|
|
}); |
227
|
|
|
}); |
228
|
|
|
|
229
|
|
|
function make_preview_btn (preview_id) |
230
|
|
|
{ |
231
|
|
|
$("#preview_" + preview_id).addClass("button"); |
232
|
|
|
$("#preview_" + preview_id).text(\'' . $txt['preview'] . '\').click(function () { |
233
|
|
|
$.ajax({ |
234
|
|
|
type: "POST", |
235
|
|
|
headers: { |
236
|
|
|
"X-SMF-AJAX": 1 |
237
|
|
|
}, |
238
|
|
|
xhrFields: { |
239
|
|
|
withCredentials: typeof allow_xhjr_credentials !== "undefined" ? allow_xhjr_credentials : false |
240
|
|
|
}, |
241
|
|
|
url: "' . $scripturl . '?action=xmlhttp;sa=previews;xml", |
242
|
|
|
data: {item: "newspreview", news: $("#data_" + preview_id).val()}, |
243
|
|
|
context: document.body, |
244
|
|
|
success: function(request){ |
245
|
|
|
if ($(request).find("error").text() == \'\') |
246
|
|
|
$(document).find("#box_preview_" + preview_id).html($(request).text()); |
247
|
|
|
else |
248
|
|
|
$(document).find("#box_preview_" + preview_id).text(\'' . $txt['news_error_no_news'] . '\'); |
249
|
|
|
}, |
250
|
|
|
}); |
251
|
|
|
}); |
252
|
|
|
} |
253
|
|
|
|
254
|
|
|
function addNewsItem () |
255
|
|
|
{ |
256
|
|
|
last_preview++; |
257
|
|
|
$("#list_news_lists_last").before(' . javaScriptEscape(' |
258
|
|
|
<tr class="windowbg') . ' + (last_preview % 2 == 0 ? \'\' : \'2\') + ' . javaScriptEscape('"> |
259
|
|
|
<td style="width: 50%;"> |
260
|
|
|
<textarea id="data_') . ' + last_preview + ' . javaScriptEscape('" rows="3" cols="65" name="news[]" style="width: 95%;"></textarea> |
261
|
|
|
<br> |
262
|
|
|
<div class="floatleft" id="preview_') . ' + last_preview + ' . javaScriptEscape('"></div> |
263
|
|
|
</td> |
264
|
|
|
<td style="width: 45%;"> |
265
|
|
|
<div id="box_preview_') . ' + last_preview + ' . javaScriptEscape('" style="overflow: auto; width: 100%; height: 10ex;"></div> |
266
|
|
|
</td> |
267
|
|
|
<td></td> |
268
|
|
|
</tr>') . '); |
269
|
|
|
make_preview_btn(last_preview); |
270
|
|
|
}', |
271
|
|
|
); |
272
|
|
|
|
273
|
|
|
// Create the request list. |
274
|
|
|
createList($listOptions); |
275
|
|
|
|
276
|
|
|
// And go! |
277
|
|
|
loadTemplate('ManageNews'); |
278
|
|
|
$context['sub_template'] = 'news_lists'; |
279
|
|
|
} |
280
|
|
|
|
281
|
|
|
/** |
282
|
|
|
* Prepares an array of the forum news items for display in the template |
283
|
|
|
* |
284
|
|
|
* @return array An array of information about the news items |
285
|
|
|
*/ |
286
|
|
|
function list_getNews() |
287
|
|
|
{ |
288
|
|
|
global $modSettings; |
289
|
|
|
|
290
|
|
|
$admin_current_news = array(); |
291
|
|
|
// Ready the current news. |
292
|
|
|
foreach (explode("\n", $modSettings['news']) as $id => $line) |
293
|
|
|
$admin_current_news[$id] = array( |
294
|
|
|
'id' => $id, |
295
|
|
|
'unparsed' => un_preparsecode($line), |
296
|
|
|
'parsed' => preg_replace('~<([/]?)form[^>]*?[>]*>~i', '<em class="smalltext"><$1form></em>', parse_bbc($line)), |
297
|
|
|
); |
298
|
|
|
|
299
|
|
|
$admin_current_news['last'] = array( |
300
|
|
|
'id' => 'last', |
301
|
|
|
'unparsed' => '<div id="moreNewsItems"></div> |
302
|
|
|
<noscript><textarea rows="3" cols="65" name="news[]" style="width: 85%;"></textarea></noscript>', |
303
|
|
|
'parsed' => '<div id="moreNewsItems_preview"></div>', |
304
|
|
|
); |
305
|
|
|
|
306
|
|
|
return $admin_current_news; |
307
|
|
|
} |
308
|
|
|
|
309
|
|
|
/** |
310
|
|
|
* This function allows a user to select the membergroups to send their |
311
|
|
|
* mailing to. |
312
|
|
|
* Called by ?action=admin;area=news;sa=mailingmembers. |
313
|
|
|
* Requires the send_mail permission. |
314
|
|
|
* Form is submitted to ?action=admin;area=news;mailingcompose. |
315
|
|
|
* |
316
|
|
|
* @uses template_email_members() |
317
|
|
|
*/ |
318
|
|
|
function SelectMailingMembers() |
319
|
|
|
{ |
320
|
|
|
global $txt, $context, $modSettings, $smcFunc; |
321
|
|
|
|
322
|
|
|
// Is there any confirm message? |
323
|
|
|
$context['newsletter_sent'] = isset($_SESSION['newsletter_sent']) ? $_SESSION['newsletter_sent'] : ''; |
324
|
|
|
|
325
|
|
|
$context['page_title'] = $txt['admin_newsletters']; |
326
|
|
|
|
327
|
|
|
$context['sub_template'] = 'email_members'; |
328
|
|
|
|
329
|
|
|
$context['groups'] = array(); |
330
|
|
|
$postGroups = array(); |
331
|
|
|
$normalGroups = array(); |
332
|
|
|
|
333
|
|
|
// If we have post groups disabled then we need to give a "ungrouped members" option. |
334
|
|
|
if (empty($modSettings['permission_enable_postgroups'])) |
335
|
|
|
{ |
336
|
|
|
$context['groups'][0] = array( |
337
|
|
|
'id' => 0, |
338
|
|
|
'name' => $txt['membergroups_members'], |
339
|
|
|
'member_count' => 0, |
340
|
|
|
); |
341
|
|
|
$normalGroups[0] = 0; |
342
|
|
|
} |
343
|
|
|
|
344
|
|
|
// Get all the extra groups as well as Administrator and Global Moderator. |
345
|
|
|
$request = $smcFunc['db_query']('', ' |
346
|
|
|
SELECT mg.id_group, mg.group_name, mg.min_posts |
347
|
|
|
FROM {db_prefix}membergroups AS mg' . (empty($modSettings['permission_enable_postgroups']) ? ' |
348
|
|
|
WHERE mg.min_posts = {int:min_posts}' : '') . ' |
349
|
|
|
GROUP BY mg.id_group, mg.min_posts, mg.group_name |
350
|
|
|
ORDER BY mg.min_posts, CASE WHEN mg.id_group < {int:newbie_group} THEN mg.id_group ELSE 4 END, mg.group_name', |
351
|
|
|
array( |
352
|
|
|
'min_posts' => -1, |
353
|
|
|
'newbie_group' => 4, |
354
|
|
|
) |
355
|
|
|
); |
356
|
|
|
while ($row = $smcFunc['db_fetch_assoc']($request)) |
357
|
|
|
{ |
358
|
|
|
$context['groups'][$row['id_group']] = array( |
359
|
|
|
'id' => $row['id_group'], |
360
|
|
|
'name' => $row['group_name'], |
361
|
|
|
'member_count' => 0, |
362
|
|
|
); |
363
|
|
|
|
364
|
|
|
if ($row['min_posts'] == -1) |
365
|
|
|
$normalGroups[$row['id_group']] = $row['id_group']; |
366
|
|
|
else |
367
|
|
|
$postGroups[$row['id_group']] = $row['id_group']; |
368
|
|
|
} |
369
|
|
|
$smcFunc['db_free_result']($request); |
370
|
|
|
|
371
|
|
|
// If we have post groups, let's count the number of members... |
372
|
|
|
if (!empty($postGroups)) |
373
|
|
|
{ |
374
|
|
|
$query = $smcFunc['db_query']('', ' |
375
|
|
|
SELECT mem.id_post_group AS id_group, COUNT(*) AS member_count |
376
|
|
|
FROM {db_prefix}members AS mem |
377
|
|
|
WHERE mem.id_post_group IN ({array_int:post_group_list}) |
378
|
|
|
GROUP BY mem.id_post_group', |
379
|
|
|
array( |
380
|
|
|
'post_group_list' => $postGroups, |
381
|
|
|
) |
382
|
|
|
); |
383
|
|
|
while ($row = $smcFunc['db_fetch_assoc']($query)) |
384
|
|
|
$context['groups'][$row['id_group']]['member_count'] += $row['member_count']; |
385
|
|
|
$smcFunc['db_free_result']($query); |
386
|
|
|
} |
387
|
|
|
|
388
|
|
|
if (!empty($normalGroups)) |
389
|
|
|
{ |
390
|
|
|
// Find people who are members of this group... |
391
|
|
|
$query = $smcFunc['db_query']('', ' |
392
|
|
|
SELECT id_group, COUNT(*) AS member_count |
393
|
|
|
FROM {db_prefix}members |
394
|
|
|
WHERE id_group IN ({array_int:normal_group_list}) |
395
|
|
|
GROUP BY id_group', |
396
|
|
|
array( |
397
|
|
|
'normal_group_list' => $normalGroups, |
398
|
|
|
) |
399
|
|
|
); |
400
|
|
|
while ($row = $smcFunc['db_fetch_assoc']($query)) |
401
|
|
|
$context['groups'][$row['id_group']]['member_count'] += $row['member_count']; |
402
|
|
|
$smcFunc['db_free_result']($query); |
403
|
|
|
|
404
|
|
|
// Also do those who have it as an additional membergroup - this ones more yucky... |
405
|
|
|
$query = $smcFunc['db_query']('', ' |
406
|
|
|
SELECT mg.id_group, COUNT(*) AS member_count |
407
|
|
|
FROM {db_prefix}membergroups AS mg |
408
|
|
|
INNER JOIN {db_prefix}members AS mem ON (mem.additional_groups != {string:blank_string} |
409
|
|
|
AND mem.id_group != mg.id_group |
410
|
|
|
AND FIND_IN_SET(mg.id_group, mem.additional_groups) != 0) |
411
|
|
|
WHERE mg.id_group IN ({array_int:normal_group_list}) |
412
|
|
|
GROUP BY mg.id_group', |
413
|
|
|
array( |
414
|
|
|
'normal_group_list' => $normalGroups, |
415
|
|
|
'blank_string' => '', |
416
|
|
|
) |
417
|
|
|
); |
418
|
|
|
while ($row = $smcFunc['db_fetch_assoc']($query)) |
419
|
|
|
$context['groups'][$row['id_group']]['member_count'] += $row['member_count']; |
420
|
|
|
$smcFunc['db_free_result']($query); |
421
|
|
|
} |
422
|
|
|
|
423
|
|
|
// Any moderators? |
424
|
|
|
$request = $smcFunc['db_query']('', ' |
425
|
|
|
SELECT COUNT(DISTINCT id_member) AS num_distinct_mods |
426
|
|
|
FROM {db_prefix}moderators |
427
|
|
|
LIMIT 1', |
428
|
|
|
array( |
429
|
|
|
) |
430
|
|
|
); |
431
|
|
|
list ($context['groups'][3]['member_count']) = $smcFunc['db_fetch_row']($request); |
432
|
|
|
$smcFunc['db_free_result']($request); |
433
|
|
|
|
434
|
|
|
$context['can_send_pm'] = allowedTo('pm_send'); |
435
|
|
|
|
436
|
|
|
loadJavaScriptFile('suggest.js', array('defer' => false, 'minimize' => true), 'smf_suggest'); |
437
|
|
|
} |
438
|
|
|
|
439
|
|
|
/** |
440
|
|
|
* Prepare subject and message of an email for the preview box |
441
|
|
|
* Used in ComposeMailing and RetrievePreview (Xml.php) |
442
|
|
|
*/ |
443
|
|
|
function prepareMailingForPreview() |
444
|
|
|
{ |
445
|
|
|
global $context, $modSettings, $scripturl, $user_info, $txt; |
446
|
|
|
loadLanguage('Errors'); |
447
|
|
|
|
448
|
|
|
$processing = array('preview_subject' => 'subject', 'preview_message' => 'message'); |
449
|
|
|
|
450
|
|
|
// Use the default time format. |
451
|
|
|
$user_info['time_format'] = $modSettings['time_format']; |
452
|
|
|
|
453
|
|
|
$variables = array( |
454
|
|
|
'{$board_url}', |
455
|
|
|
'{$current_time}', |
456
|
|
|
'{$latest_member.link}', |
457
|
|
|
'{$latest_member.id}', |
458
|
|
|
'{$latest_member.name}' |
459
|
|
|
); |
460
|
|
|
|
461
|
|
|
$html = $context['send_html']; |
462
|
|
|
|
463
|
|
|
// We might need this in a bit |
464
|
|
|
$cleanLatestMember = empty($context['send_html']) || $context['send_pm'] ? un_htmlspecialchars($modSettings['latestRealName']) : $modSettings['latestRealName']; |
465
|
|
|
|
466
|
|
|
foreach ($processing as $key => $post) |
467
|
|
|
{ |
468
|
|
|
$context[$key] = !empty($_REQUEST[$post]) ? $_REQUEST[$post] : ''; |
469
|
|
|
|
470
|
|
|
if (empty($context[$key]) && empty($_REQUEST['xml'])) |
471
|
|
|
$context['post_error']['messages'][] = $txt['error_no_' . $post]; |
472
|
|
|
elseif (!empty($_REQUEST['xml'])) |
473
|
|
|
continue; |
474
|
|
|
|
475
|
|
|
preparsecode($context[$key]); |
476
|
|
|
if ($html) |
477
|
|
|
{ |
478
|
|
|
$enablePostHTML = $modSettings['enablePostHTML']; |
479
|
|
|
$modSettings['enablePostHTML'] = $context['send_html']; |
480
|
|
|
$context[$key] = parse_bbc($context[$key]); |
481
|
|
|
$modSettings['enablePostHTML'] = $enablePostHTML; |
482
|
|
|
} |
483
|
|
|
|
484
|
|
|
// Replace in all the standard things. |
485
|
|
|
$context[$key] = str_replace($variables, |
486
|
|
|
array( |
487
|
|
|
!empty($context['send_html']) ? '<a href="' . $scripturl . '">' . $scripturl . '</a>' : $scripturl, |
488
|
|
|
timeformat(time(), false), |
489
|
|
|
!empty($context['send_html']) ? '<a href="' . $scripturl . '?action=profile;u=' . $modSettings['latestMember'] . '">' . $cleanLatestMember . '</a>' : ($context['send_pm'] ? '[url=' . $scripturl . '?action=profile;u=' . $modSettings['latestMember'] . ']' . $cleanLatestMember . '[/url]' : $cleanLatestMember), |
490
|
|
|
$modSettings['latestMember'], |
491
|
|
|
$cleanLatestMember |
492
|
|
|
), $context[$key]); |
493
|
|
|
} |
494
|
|
|
} |
495
|
|
|
|
496
|
|
|
/** |
497
|
|
|
* Shows a form to edit a forum mailing and its recipients. |
498
|
|
|
* Called by ?action=admin;area=news;sa=mailingcompose. |
499
|
|
|
* Requires the send_mail permission. |
500
|
|
|
* Form is submitted to ?action=admin;area=news;sa=mailingsend. |
501
|
|
|
* |
502
|
|
|
* @uses template_email_members_compose() |
503
|
|
|
*/ |
504
|
|
|
function ComposeMailing() |
505
|
|
|
{ |
506
|
|
|
global $txt, $sourcedir, $context, $smcFunc; |
507
|
|
|
|
508
|
|
|
// Setup the template! |
509
|
|
|
$context['page_title'] = $txt['admin_newsletters']; |
510
|
|
|
$context['sub_template'] = 'email_members_compose'; |
511
|
|
|
|
512
|
|
|
$context['subject'] = !empty($_POST['subject']) ? $_POST['subject'] : $smcFunc['htmlspecialchars']($context['forum_name'] . ': ' . $txt['subject']); |
513
|
|
|
$context['message'] = !empty($_POST['message']) ? $_POST['message'] : $smcFunc['htmlspecialchars']($txt['message'] . "\n\n" . sprintf($txt['regards_team'], $context['forum_name']) . "\n\n" . '{$board_url}'); |
514
|
|
|
|
515
|
|
|
// Needed for the WYSIWYG editor. |
516
|
|
|
require_once($sourcedir . '/Subs-Editor.php'); |
517
|
|
|
|
518
|
|
|
// Now create the editor. |
519
|
|
|
$editorOptions = array( |
520
|
|
|
'id' => 'message', |
521
|
|
|
'value' => $context['message'], |
522
|
|
|
'height' => '150px', |
523
|
|
|
'width' => '100%', |
524
|
|
|
'labels' => array( |
525
|
|
|
'post_button' => $txt['sendtopic_send'], |
526
|
|
|
), |
527
|
|
|
'preview_type' => 2, |
528
|
|
|
'required' => true, |
529
|
|
|
); |
530
|
|
|
create_control_richedit($editorOptions); |
531
|
|
|
// Store the ID for old compatibility. |
532
|
|
|
$context['post_box_name'] = $editorOptions['id']; |
533
|
|
|
|
534
|
|
|
if (isset($context['preview'])) |
535
|
|
|
{ |
536
|
|
|
require_once($sourcedir . '/Subs-Post.php'); |
537
|
|
|
$context['recipients']['members'] = !empty($_POST['members']) ? explode(',', $_POST['members']) : array(); |
538
|
|
|
$context['recipients']['exclude_members'] = !empty($_POST['exclude_members']) ? explode(',', $_POST['exclude_members']) : array(); |
539
|
|
|
$context['recipients']['groups'] = !empty($_POST['groups']) ? explode(',', $_POST['groups']) : array(); |
540
|
|
|
$context['recipients']['exclude_groups'] = !empty($_POST['exclude_groups']) ? explode(',', $_POST['exclude_groups']) : array(); |
541
|
|
|
$context['recipients']['emails'] = !empty($_POST['emails']) ? explode(';', $_POST['emails']) : array(); |
542
|
|
|
$context['email_force'] = !empty($_POST['email_force']) ? 1 : 0; |
543
|
|
|
$context['total_emails'] = !empty($_POST['total_emails']) ? (int) $_POST['total_emails'] : 0; |
544
|
|
|
$context['send_pm'] = !empty($_POST['send_pm']) ? 1 : 0; |
545
|
|
|
$context['send_html'] = !empty($_POST['send_html']) ? '1' : '0'; |
546
|
|
|
|
547
|
|
|
return prepareMailingForPreview(); |
|
|
|
|
548
|
|
|
} |
549
|
|
|
|
550
|
|
|
// Start by finding any members! |
551
|
|
|
$toClean = array(); |
552
|
|
|
if (!empty($_POST['members'])) |
553
|
|
|
$toClean[] = 'members'; |
554
|
|
|
if (!empty($_POST['exclude_members'])) |
555
|
|
|
$toClean[] = 'exclude_members'; |
556
|
|
|
if (!empty($toClean)) |
557
|
|
|
{ |
558
|
|
|
require_once($sourcedir . '/Subs-Auth.php'); |
559
|
|
|
foreach ($toClean as $type) |
560
|
|
|
{ |
561
|
|
|
// Remove the quotes. |
562
|
|
|
$_POST[$type] = strtr($_POST[$type], array('\\"' => '"')); |
563
|
|
|
|
564
|
|
|
preg_match_all('~"([^"]+)"~', $_POST[$type], $matches); |
565
|
|
|
$_POST[$type] = array_unique(array_merge($matches[1], explode(',', preg_replace('~"[^"]+"~', '', $_POST[$type])))); |
566
|
|
|
|
567
|
|
|
foreach ($_POST[$type] as $index => $member) |
568
|
|
|
if (strlen(trim($member)) > 0) |
569
|
|
|
$_POST[$type][$index] = $smcFunc['htmlspecialchars']($smcFunc['strtolower'](trim($member))); |
570
|
|
|
else |
571
|
|
|
unset($_POST[$type][$index]); |
572
|
|
|
|
573
|
|
|
// Find the members |
574
|
|
|
$_POST[$type] = implode(',', array_keys(findMembers($_POST[$type]))); |
575
|
|
|
} |
576
|
|
|
} |
577
|
|
|
|
578
|
|
|
if (isset($_POST['member_list']) && is_array($_POST['member_list'])) |
579
|
|
|
{ |
580
|
|
|
$members = array(); |
581
|
|
|
foreach ($_POST['member_list'] as $member_id) |
582
|
|
|
$members[] = (int) $member_id; |
583
|
|
|
$_POST['members'] = implode(',', $members); |
584
|
|
|
} |
585
|
|
|
|
586
|
|
|
if (isset($_POST['exclude_member_list']) && is_array($_POST['exclude_member_list'])) |
587
|
|
|
{ |
588
|
|
|
$members = array(); |
589
|
|
|
foreach ($_POST['exclude_member_list'] as $member_id) |
590
|
|
|
$members[] = (int) $member_id; |
591
|
|
|
$_POST['exclude_members'] = implode(',', $members); |
592
|
|
|
} |
593
|
|
|
|
594
|
|
|
// Clean the other vars. |
595
|
|
|
SendMailing(true); |
596
|
|
|
|
597
|
|
|
// We need a couple strings from the email template file |
598
|
|
|
loadLanguage('EmailTemplates'); |
599
|
|
|
|
600
|
|
|
// Get a list of all full banned users. Use their Username and email to find them. Only get the ones that can't login to turn off notification. |
601
|
|
|
$request = $smcFunc['db_query']('', ' |
602
|
|
|
SELECT DISTINCT mem.id_member |
603
|
|
|
FROM {db_prefix}ban_groups AS bg |
604
|
|
|
INNER JOIN {db_prefix}ban_items AS bi ON (bg.id_ban_group = bi.id_ban_group) |
605
|
|
|
INNER JOIN {db_prefix}members AS mem ON (bi.id_member = mem.id_member) |
606
|
|
|
WHERE (bg.cannot_access = {int:cannot_access} OR bg.cannot_login = {int:cannot_login}) |
607
|
|
|
AND (bg.expire_time IS NULL OR bg.expire_time > {int:current_time})', |
608
|
|
|
array( |
609
|
|
|
'cannot_access' => 1, |
610
|
|
|
'cannot_login' => 1, |
611
|
|
|
'current_time' => time(), |
612
|
|
|
) |
613
|
|
|
); |
614
|
|
|
while ($row = $smcFunc['db_fetch_assoc']($request)) |
615
|
|
|
$context['recipients']['exclude_members'][] = $row['id_member']; |
616
|
|
|
$smcFunc['db_free_result']($request); |
617
|
|
|
|
618
|
|
|
$request = $smcFunc['db_query']('', ' |
619
|
|
|
SELECT DISTINCT bi.email_address |
620
|
|
|
FROM {db_prefix}ban_items AS bi |
621
|
|
|
INNER JOIN {db_prefix}ban_groups AS bg ON (bg.id_ban_group = bi.id_ban_group) |
622
|
|
|
WHERE (bg.cannot_access = {int:cannot_access} OR bg.cannot_login = {int:cannot_login}) |
623
|
|
|
AND (bg.expire_time IS NULL OR bg.expire_time > {int:current_time}) |
624
|
|
|
AND bi.email_address != {string:blank_string}', |
625
|
|
|
array( |
626
|
|
|
'cannot_access' => 1, |
627
|
|
|
'cannot_login' => 1, |
628
|
|
|
'current_time' => time(), |
629
|
|
|
'blank_string' => '', |
630
|
|
|
) |
631
|
|
|
); |
632
|
|
|
$condition_array = array(); |
633
|
|
|
$condition_array_params = array(); |
634
|
|
|
$count = 0; |
635
|
|
|
while ($row = $smcFunc['db_fetch_assoc']($request)) |
636
|
|
|
{ |
637
|
|
|
$condition_array[] = '{string:email_' . $count . '}'; |
638
|
|
|
$condition_array_params['email_' . $count++] = $row['email_address']; |
639
|
|
|
} |
640
|
|
|
$smcFunc['db_free_result']($request); |
641
|
|
|
|
642
|
|
|
if (!empty($condition_array)) |
643
|
|
|
{ |
644
|
|
|
$request = $smcFunc['db_query']('', ' |
645
|
|
|
SELECT id_member |
646
|
|
|
FROM {db_prefix}members |
647
|
|
|
WHERE email_address IN(' . implode(', ', $condition_array) . ')', |
648
|
|
|
$condition_array_params |
649
|
|
|
); |
650
|
|
|
while ($row = $smcFunc['db_fetch_assoc']($request)) |
651
|
|
|
$context['recipients']['exclude_members'][] = $row['id_member']; |
652
|
|
|
$smcFunc['db_free_result']($request); |
653
|
|
|
} |
654
|
|
|
|
655
|
|
|
// Did they select moderators - if so add them as specific members... |
656
|
|
|
if ((!empty($context['recipients']['groups']) && in_array(3, $context['recipients']['groups'])) || (!empty($context['recipients']['exclude_groups']) && in_array(3, $context['recipients']['exclude_groups']))) |
657
|
|
|
{ |
658
|
|
|
$request = $smcFunc['db_query']('', ' |
659
|
|
|
SELECT DISTINCT mem.id_member AS identifier |
660
|
|
|
FROM {db_prefix}members AS mem |
661
|
|
|
INNER JOIN {db_prefix}moderators AS mods ON (mods.id_member = mem.id_member) |
662
|
|
|
WHERE mem.is_activated = {int:is_activated}', |
663
|
|
|
array( |
664
|
|
|
'is_activated' => 1, |
665
|
|
|
) |
666
|
|
|
); |
667
|
|
|
while ($row = $smcFunc['db_fetch_assoc']($request)) |
668
|
|
|
{ |
669
|
|
|
if (in_array(3, $context['recipients'])) |
670
|
|
|
$context['recipients']['exclude_members'][] = $row['identifier']; |
671
|
|
|
else |
672
|
|
|
$context['recipients']['members'][] = $row['identifier']; |
673
|
|
|
} |
674
|
|
|
$smcFunc['db_free_result']($request); |
675
|
|
|
} |
676
|
|
|
|
677
|
|
|
// For progress bar! |
678
|
|
|
$context['total_emails'] = count($context['recipients']['emails']); |
679
|
|
|
$request = $smcFunc['db_query']('', ' |
680
|
|
|
SELECT COUNT(*) |
681
|
|
|
FROM {db_prefix}members', |
682
|
|
|
array( |
683
|
|
|
) |
684
|
|
|
); |
685
|
|
|
list ($context['total_members']) = $smcFunc['db_fetch_row']($request); |
686
|
|
|
$smcFunc['db_free_result']($request); |
687
|
|
|
|
688
|
|
|
// Clean up the arrays. |
689
|
|
|
$context['recipients']['members'] = array_unique($context['recipients']['members']); |
690
|
|
|
$context['recipients']['exclude_members'] = array_unique($context['recipients']['exclude_members']); |
691
|
|
|
} |
692
|
|
|
|
693
|
|
|
/** |
694
|
|
|
* Handles the sending of the forum mailing in batches. |
695
|
|
|
* Called by ?action=admin;area=news;sa=mailingsend |
696
|
|
|
* Requires the send_mail permission. |
697
|
|
|
* Redirects to itself when more batches need to be sent. |
698
|
|
|
* Redirects to ?action=admin;area=news;sa=mailingmembers after everything has been sent. |
699
|
|
|
* @uses template_email_members_send() |
700
|
|
|
* |
701
|
|
|
* @param bool $clean_only If set, it will only clean the variables, put them in context, then return. |
702
|
|
|
*/ |
703
|
|
|
function SendMailing($clean_only = false) |
704
|
|
|
{ |
705
|
|
|
global $txt, $sourcedir, $context, $smcFunc; |
706
|
|
|
global $scripturl, $modSettings, $user_info; |
707
|
|
|
global $webmaster_email; |
708
|
|
|
|
709
|
|
|
if (isset($_POST['preview'])) |
710
|
|
|
{ |
711
|
|
|
$context['preview'] = true; |
712
|
|
|
return ComposeMailing(); |
|
|
|
|
713
|
|
|
} |
714
|
|
|
|
715
|
|
|
// How many to send at once? Quantity depends on whether we are queueing or not. |
716
|
|
|
// @todo Might need an interface? (used in Post.php too with different limits) |
717
|
|
|
$num_at_once = 1000; |
718
|
|
|
|
719
|
|
|
// If by PM's I suggest we half the above number. |
720
|
|
|
if (!empty($_POST['send_pm'])) |
721
|
|
|
$num_at_once /= 2; |
722
|
|
|
|
723
|
|
|
checkSession(); |
724
|
|
|
|
725
|
|
|
// Where are we actually to? |
726
|
|
|
$context['start'] = isset($_REQUEST['start']) ? (int) $_REQUEST['start'] : 0; |
727
|
|
|
$context['email_force'] = !empty($_POST['email_force']) ? 1 : 0; |
728
|
|
|
$context['send_pm'] = !empty($_POST['send_pm']) ? 1 : 0; |
729
|
|
|
$context['total_emails'] = !empty($_POST['total_emails']) ? (int) $_POST['total_emails'] : 0; |
730
|
|
|
$context['send_html'] = !empty($_POST['send_html']) ? '1' : '0'; |
731
|
|
|
$context['parse_html'] = !empty($_POST['parse_html']) ? '1' : '0'; |
732
|
|
|
|
733
|
|
|
//One can't simply nullify things around |
734
|
|
|
if (empty($_REQUEST['total_members'])) |
735
|
|
|
{ |
736
|
|
|
$request = $smcFunc['db_query']('', ' |
737
|
|
|
SELECT COUNT(*) |
738
|
|
|
FROM {db_prefix}members', |
739
|
|
|
array( |
740
|
|
|
) |
741
|
|
|
); |
742
|
|
|
list ($context['total_members']) = $smcFunc['db_fetch_row']($request); |
743
|
|
|
$smcFunc['db_free_result']($request); |
744
|
|
|
} |
745
|
|
|
else |
746
|
|
|
{ |
747
|
|
|
$context['total_members'] = (int) $_REQUEST['total_members']; |
748
|
|
|
} |
749
|
|
|
|
750
|
|
|
// Create our main context. |
751
|
|
|
$context['recipients'] = array( |
752
|
|
|
'groups' => array(), |
753
|
|
|
'exclude_groups' => array(), |
754
|
|
|
'members' => array(), |
755
|
|
|
'exclude_members' => array(), |
756
|
|
|
'emails' => array(), |
757
|
|
|
); |
758
|
|
|
|
759
|
|
|
// Have we any excluded members? |
760
|
|
|
if (!empty($_POST['exclude_members'])) |
761
|
|
|
{ |
762
|
|
|
$members = explode(',', $_POST['exclude_members']); |
763
|
|
|
foreach ($members as $member) |
764
|
|
|
if ($member >= $context['start']) |
765
|
|
|
$context['recipients']['exclude_members'][] = (int) $member; |
766
|
|
|
} |
767
|
|
|
|
768
|
|
|
// What about members we *must* do? |
769
|
|
|
if (!empty($_POST['members'])) |
770
|
|
|
{ |
771
|
|
|
$members = explode(',', $_POST['members']); |
772
|
|
|
foreach ($members as $member) |
773
|
|
|
if ($member >= $context['start']) |
774
|
|
|
$context['recipients']['members'][] = (int) $member; |
775
|
|
|
} |
776
|
|
|
// Cleaning groups is simple - although deal with both checkbox and commas. |
777
|
|
|
if (isset($_POST['groups'])) |
778
|
|
|
{ |
779
|
|
|
if (is_array($_POST['groups'])) |
780
|
|
|
{ |
781
|
|
|
foreach ($_POST['groups'] as $group => $dummy) |
782
|
|
|
$context['recipients']['groups'][] = (int) $group; |
783
|
|
|
} |
784
|
|
|
else |
785
|
|
|
{ |
786
|
|
|
$groups = explode(',', $_POST['groups']); |
787
|
|
|
foreach ($groups as $group) |
788
|
|
|
$context['recipients']['groups'][] = (int) $group; |
789
|
|
|
} |
790
|
|
|
} |
791
|
|
|
// Same for excluded groups |
792
|
|
|
if (isset($_POST['exclude_groups'])) |
793
|
|
|
{ |
794
|
|
|
if (is_array($_POST['exclude_groups'])) |
795
|
|
|
{ |
796
|
|
|
foreach ($_POST['exclude_groups'] as $group => $dummy) |
797
|
|
|
$context['recipients']['exclude_groups'][] = (int) $group; |
798
|
|
|
} |
799
|
|
|
// Ignore an empty string - we don't want to exclude "Regular Members" unless it's specifically selected |
800
|
|
|
elseif ($_POST['exclude_groups'] != '') |
801
|
|
|
{ |
802
|
|
|
$groups = explode(',', $_POST['exclude_groups']); |
803
|
|
|
foreach ($groups as $group) |
804
|
|
|
$context['recipients']['exclude_groups'][] = (int) $group; |
805
|
|
|
} |
806
|
|
|
} |
807
|
|
|
// Finally - emails! |
808
|
|
|
if (!empty($_POST['emails'])) |
809
|
|
|
{ |
810
|
|
|
$addressed = array_unique(explode(';', strtr($_POST['emails'], array("\n" => ';', "\r" => ';', ',' => ';')))); |
811
|
|
|
foreach ($addressed as $curmem) |
812
|
|
|
{ |
813
|
|
|
$curmem = trim($curmem); |
814
|
|
|
if ($curmem != '' && filter_var($curmem, FILTER_VALIDATE_EMAIL)) |
815
|
|
|
$context['recipients']['emails'][$curmem] = $curmem; |
816
|
|
|
} |
817
|
|
|
} |
818
|
|
|
|
819
|
|
|
// If we're only cleaning drop out here. |
820
|
|
|
if ($clean_only) |
821
|
|
|
return; |
822
|
|
|
|
823
|
|
|
require_once($sourcedir . '/Subs-Post.php'); |
824
|
|
|
|
825
|
|
|
// We are relying too much on writing to superglobals... |
826
|
|
|
$_POST['subject'] = !empty($_POST['subject']) ? $_POST['subject'] : ''; |
827
|
|
|
$_POST['message'] = !empty($_POST['message']) ? $_POST['message'] : ''; |
828
|
|
|
|
829
|
|
|
// Save the message and its subject in $context |
830
|
|
|
$context['subject'] = $smcFunc['htmlspecialchars']($_POST['subject'], ENT_QUOTES); |
831
|
|
|
$context['message'] = $smcFunc['htmlspecialchars']($_POST['message'], ENT_QUOTES); |
832
|
|
|
|
833
|
|
|
// Include an unsubscribe link if necessary. |
834
|
|
|
if (!$context['send_pm']) |
835
|
|
|
{ |
836
|
|
|
$include_unsubscribe = true; |
837
|
|
|
$_POST['message'] .= "\n\n" . '{$member.unsubscribe}'; |
838
|
|
|
} |
839
|
|
|
|
840
|
|
|
// Prepare the message for sending it as HTML |
841
|
|
|
if (!$context['send_pm'] && !empty($_POST['send_html'])) |
842
|
|
|
{ |
843
|
|
|
// Prepare the message for HTML. |
844
|
|
|
if (!empty($_POST['parse_html'])) |
845
|
|
|
$_POST['message'] = str_replace(array("\n", ' '), array('<br>' . "\n", ' '), $_POST['message']); |
846
|
|
|
|
847
|
|
|
// This is here to prevent spam filters from tagging this as spam. |
848
|
|
|
if (preg_match('~\<html~i', $_POST['message']) == 0) |
849
|
|
|
{ |
850
|
|
|
if (preg_match('~\<body~i', $_POST['message']) == 0) |
851
|
|
|
$_POST['message'] = '<html><head><title>' . $_POST['subject'] . '</title></head>' . "\n" . '<body>' . $_POST['message'] . '</body></html>'; |
852
|
|
|
else |
853
|
|
|
$_POST['message'] = '<html>' . $_POST['message'] . '</html>'; |
854
|
|
|
} |
855
|
|
|
} |
856
|
|
|
|
857
|
|
|
if (empty($_POST['message']) || empty($_POST['subject'])) |
858
|
|
|
{ |
859
|
|
|
$context['preview'] = true; |
860
|
|
|
return ComposeMailing(); |
861
|
|
|
} |
862
|
|
|
|
863
|
|
|
// Use the default time format. |
864
|
|
|
$user_info['time_format'] = $modSettings['time_format']; |
865
|
|
|
|
866
|
|
|
$variables = array( |
867
|
|
|
'{$board_url}', |
868
|
|
|
'{$current_time}', |
869
|
|
|
'{$latest_member.link}', |
870
|
|
|
'{$latest_member.id}', |
871
|
|
|
'{$latest_member.name}' |
872
|
|
|
); |
873
|
|
|
|
874
|
|
|
// We might need this in a bit |
875
|
|
|
$cleanLatestMember = empty($_POST['send_html']) || $context['send_pm'] ? un_htmlspecialchars($modSettings['latestRealName']) : $modSettings['latestRealName']; |
876
|
|
|
|
877
|
|
|
// Replace in all the standard things. |
878
|
|
|
$_POST['message'] = str_replace($variables, |
879
|
|
|
array( |
880
|
|
|
!empty($_POST['send_html']) ? '<a href="' . $scripturl . '">' . $scripturl . '</a>' : $scripturl, |
881
|
|
|
timeformat(time(), false), |
882
|
|
|
!empty($_POST['send_html']) ? '<a href="' . $scripturl . '?action=profile;u=' . $modSettings['latestMember'] . '">' . $cleanLatestMember . '</a>' : ($context['send_pm'] ? '[url=' . $scripturl . '?action=profile;u=' . $modSettings['latestMember'] . ']' . $cleanLatestMember . '[/url]' : $scripturl . '?action=profile;u=' . $modSettings['latestMember']), |
883
|
|
|
$modSettings['latestMember'], |
884
|
|
|
$cleanLatestMember |
885
|
|
|
), $_POST['message']); |
886
|
|
|
$_POST['subject'] = str_replace($variables, |
887
|
|
|
array( |
888
|
|
|
$scripturl, |
889
|
|
|
timeformat(time(), false), |
890
|
|
|
$modSettings['latestRealName'], |
891
|
|
|
$modSettings['latestMember'], |
892
|
|
|
$modSettings['latestRealName'] |
893
|
|
|
), $_POST['subject']); |
894
|
|
|
|
895
|
|
|
$from_member = array( |
896
|
|
|
'{$member.email}', |
897
|
|
|
'{$member.link}', |
898
|
|
|
'{$member.id}', |
899
|
|
|
'{$member.name}', |
900
|
|
|
'{$member.unsubscribe}', |
901
|
|
|
); |
902
|
|
|
|
903
|
|
|
// If we still have emails, do them first! |
904
|
|
|
$i = 0; |
905
|
|
|
foreach ($context['recipients']['emails'] as $k => $email) |
906
|
|
|
{ |
907
|
|
|
// Done as many as we can? |
908
|
|
|
if ($i >= $num_at_once) |
909
|
|
|
break; |
910
|
|
|
|
911
|
|
|
// Don't sent it twice! |
912
|
|
|
unset($context['recipients']['emails'][$k]); |
913
|
|
|
|
914
|
|
|
// Dammit - can't PM emails! |
915
|
|
|
if ($context['send_pm']) |
916
|
|
|
continue; |
917
|
|
|
|
918
|
|
|
// Non-members can't unsubscribe via the automated system. |
919
|
|
|
$unsubscribe_link = sprintf($txt['unsubscribe_announcements_manual'], empty($modSettings['mail_from']) ? $webmaster_email : $modSettings['mail_from']); |
920
|
|
|
|
921
|
|
|
$to_member = array( |
922
|
|
|
$email, |
923
|
|
|
!empty($_POST['send_html']) ? '<a href="mailto:' . $email . '">' . $email . '</a>' : $email, |
924
|
|
|
'??', |
925
|
|
|
$email, |
926
|
|
|
$unsubscribe_link, |
927
|
|
|
); |
928
|
|
|
|
929
|
|
|
sendmail($email, str_replace($from_member, $to_member, $_POST['subject']), str_replace($from_member, $to_member, $_POST['message']), null, 'news', !empty($_POST['send_html']), 5); |
930
|
|
|
|
931
|
|
|
// Done another... |
932
|
|
|
$i++; |
933
|
|
|
} |
934
|
|
|
|
935
|
|
|
if ($i < $num_at_once) |
936
|
|
|
{ |
937
|
|
|
// Need to build quite a query! |
938
|
|
|
$sendQuery = '('; |
939
|
|
|
$sendParams = array(); |
940
|
|
|
if (!empty($context['recipients']['groups'])) |
941
|
|
|
{ |
942
|
|
|
// Take the long route... |
943
|
|
|
$queryBuild = array(); |
944
|
|
|
foreach ($context['recipients']['groups'] as $group) |
945
|
|
|
{ |
946
|
|
|
$sendParams['group_' . $group] = $group; |
947
|
|
|
$queryBuild[] = 'mem.id_group = {int:group_' . $group . '}'; |
948
|
|
|
if (!empty($group)) |
949
|
|
|
{ |
950
|
|
|
$queryBuild[] = 'FIND_IN_SET({int:group_' . $group . '}, mem.additional_groups) != 0'; |
951
|
|
|
$queryBuild[] = 'mem.id_post_group = {int:group_' . $group . '}'; |
952
|
|
|
} |
953
|
|
|
} |
954
|
|
|
if (!empty($queryBuild)) |
955
|
|
|
$sendQuery .= implode(' OR ', $queryBuild); |
956
|
|
|
} |
957
|
|
|
if (!empty($context['recipients']['members'])) |
958
|
|
|
{ |
959
|
|
|
$sendQuery .= ($sendQuery == '(' ? '' : ' OR ') . 'mem.id_member IN ({array_int:members})'; |
960
|
|
|
$sendParams['members'] = $context['recipients']['members']; |
961
|
|
|
} |
962
|
|
|
|
963
|
|
|
$sendQuery .= ')'; |
964
|
|
|
|
965
|
|
|
// If we've not got a query then we must be done! |
966
|
|
|
if ($sendQuery == '()') |
967
|
|
|
{ |
968
|
|
|
// Set a confirmation message. |
969
|
|
|
$_SESSION['newsletter_sent'] = 'queue_done'; |
970
|
|
|
redirectexit('action=admin;area=news;sa=mailingmembers'); |
971
|
|
|
} |
972
|
|
|
|
973
|
|
|
// Anything to exclude? |
974
|
|
|
if (!empty($context['recipients']['exclude_groups']) && in_array(0, $context['recipients']['exclude_groups'])) |
975
|
|
|
$sendQuery .= ' AND mem.id_group != {int:regular_group}'; |
976
|
|
|
if (!empty($context['recipients']['exclude_members'])) |
977
|
|
|
{ |
978
|
|
|
$sendQuery .= ' AND mem.id_member NOT IN ({array_int:exclude_members})'; |
979
|
|
|
$sendParams['exclude_members'] = $context['recipients']['exclude_members']; |
980
|
|
|
} |
981
|
|
|
|
982
|
|
|
// Get the smelly people - note we respect the id_member range as it gives us a quicker query. |
983
|
|
|
$result = $smcFunc['db_query']('', ' |
984
|
|
|
SELECT mem.id_member, mem.email_address, mem.real_name, mem.id_group, mem.additional_groups, mem.id_post_group |
985
|
|
|
FROM {db_prefix}members AS mem |
986
|
|
|
WHERE ' . $sendQuery . ' |
987
|
|
|
AND mem.is_activated = {int:is_activated} |
988
|
|
|
ORDER BY mem.id_member ASC |
989
|
|
|
LIMIT {int:start}, {int:atonce}', |
990
|
|
|
array_merge($sendParams, array( |
991
|
|
|
'start' => $context['start'], |
992
|
|
|
'atonce' => $num_at_once, |
993
|
|
|
'regular_group' => 0, |
994
|
|
|
'is_activated' => 1, |
995
|
|
|
)) |
996
|
|
|
); |
997
|
|
|
$rows = array(); |
998
|
|
|
while ($row = $smcFunc['db_fetch_assoc']($result)) |
999
|
|
|
{ |
1000
|
|
|
$rows[$row['id_member']] = $row; |
1001
|
|
|
} |
1002
|
|
|
$smcFunc['db_free_result']($result); |
1003
|
|
|
|
1004
|
|
|
// Load their alert preferences |
1005
|
|
|
require_once($sourcedir . '/Subs-Notify.php'); |
1006
|
|
|
$prefs = getNotifyPrefs(array_keys($rows), 'announcements', true); |
1007
|
|
|
|
1008
|
|
|
foreach ($rows as $row) |
1009
|
|
|
{ |
1010
|
|
|
// Force them to have it? |
1011
|
|
|
if (empty($context['email_force']) && empty($prefs[$row['id_member']]['announcements'])) |
1012
|
|
|
continue; |
1013
|
|
|
|
1014
|
|
|
// What groups are we looking at here? |
1015
|
|
|
if (empty($row['additional_groups'])) |
1016
|
|
|
$groups = array($row['id_group'], $row['id_post_group']); |
1017
|
|
|
else |
1018
|
|
|
$groups = array_merge( |
1019
|
|
|
array($row['id_group'], $row['id_post_group']), |
1020
|
|
|
explode(',', $row['additional_groups']) |
1021
|
|
|
); |
1022
|
|
|
|
1023
|
|
|
// Excluded groups? |
1024
|
|
|
if (array_intersect($groups, $context['recipients']['exclude_groups'])) |
1025
|
|
|
continue; |
1026
|
|
|
|
1027
|
|
|
// We might need this |
1028
|
|
|
$cleanMemberName = empty($_POST['send_html']) || $context['send_pm'] ? un_htmlspecialchars($row['real_name']) : $row['real_name']; |
1029
|
|
|
|
1030
|
|
|
if (!empty($include_unsubscribe)) |
1031
|
|
|
{ |
1032
|
|
|
$token = createUnsubscribeToken($row['id_member'], $row['email_address'], 'announcements'); |
1033
|
|
|
$unsubscribe_link = sprintf($txt['unsubscribe_announcements_' . (!empty($_POST['send_html']) ? 'html' : 'plain')], $scripturl . '?action=notifyannouncements;u=' . $row['id_member'] . ';token=' . $token); |
1034
|
|
|
} |
1035
|
|
|
else |
1036
|
|
|
$unsubscribe_link = ''; |
1037
|
|
|
|
1038
|
|
|
// Replace the member-dependant variables |
1039
|
|
|
$message = str_replace($from_member, |
1040
|
|
|
array( |
1041
|
|
|
$row['email_address'], |
1042
|
|
|
!empty($_POST['send_html']) ? '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member'] . '">' . $cleanMemberName . '</a>' : ($context['send_pm'] ? '[url=' . $scripturl . '?action=profile;u=' . $row['id_member'] . ']' . $cleanMemberName . '[/url]' : $scripturl . '?action=profile;u=' . $row['id_member']), |
1043
|
|
|
$row['id_member'], |
1044
|
|
|
$cleanMemberName, |
1045
|
|
|
$unsubscribe_link, |
1046
|
|
|
), $_POST['message']); |
1047
|
|
|
|
1048
|
|
|
$subject = str_replace($from_member, |
1049
|
|
|
array( |
1050
|
|
|
$row['email_address'], |
1051
|
|
|
$row['real_name'], |
1052
|
|
|
$row['id_member'], |
1053
|
|
|
$row['real_name'], |
1054
|
|
|
), $_POST['subject']); |
1055
|
|
|
|
1056
|
|
|
// Send the actual email - or a PM! |
1057
|
|
|
if (!$context['send_pm']) |
1058
|
|
|
sendmail($row['email_address'], $subject, $message, null, 'news', !empty($_POST['send_html']), 5); |
1059
|
|
|
else |
1060
|
|
|
sendpm(array('to' => array($row['id_member']), 'bcc' => array()), $subject, $message); |
1061
|
|
|
} |
1062
|
|
|
} |
1063
|
|
|
|
1064
|
|
|
$context['start'] = $context['start'] + $num_at_once; |
1065
|
|
|
if (empty($context['recipients']['emails']) && ($context['start'] >= $context['total_members'])) |
1066
|
|
|
{ |
1067
|
|
|
// Log this into the admin log. |
1068
|
|
|
logAction('newsletter', array(), 'admin'); |
1069
|
|
|
$_SESSION['newsletter_sent'] = 'queue_done'; |
1070
|
|
|
redirectexit('action=admin;area=news;sa=mailingmembers'); |
1071
|
|
|
} |
1072
|
|
|
|
1073
|
|
|
// Working out progress is a black art of sorts. |
1074
|
|
|
$percentEmails = $context['total_emails'] == 0 ? 0 : ((count($context['recipients']['emails']) / $context['total_emails']) * ($context['total_emails'] / ($context['total_emails'] + $context['total_members']))); |
1075
|
|
|
$percentMembers = ($context['start'] / $context['total_members']) * ($context['total_members'] / ($context['total_emails'] + $context['total_members'])); |
1076
|
|
|
$context['percentage_done'] = round(($percentEmails + $percentMembers) * 100, 2); |
1077
|
|
|
|
1078
|
|
|
$context['page_title'] = $txt['admin_newsletters']; |
1079
|
|
|
$context['sub_template'] = 'email_members_send'; |
1080
|
|
|
} |
1081
|
|
|
|
1082
|
|
|
/** |
1083
|
|
|
* Set general news and newsletter settings and permissions. |
1084
|
|
|
* Called by ?action=admin;area=news;sa=settings. |
1085
|
|
|
* Requires the forum_admin permission. |
1086
|
|
|
* @uses template_show_settings() |
1087
|
|
|
* |
1088
|
|
|
* @param bool $return_config Whether or not to return the config_vars array (used for admin search) |
1089
|
|
|
* @return void|array Returns nothing or returns the config_vars array if $return_config is true |
1090
|
|
|
*/ |
1091
|
|
|
function ModifyNewsSettings($return_config = false) |
1092
|
|
|
{ |
1093
|
|
|
global $context, $sourcedir, $txt, $scripturl; |
1094
|
|
|
|
1095
|
|
|
$config_vars = array( |
1096
|
|
|
array('title', 'settings'), |
1097
|
|
|
// Inline permissions. |
1098
|
|
|
array('permissions', 'edit_news', 'help' => ''), |
1099
|
|
|
array('permissions', 'send_mail'), |
1100
|
|
|
'', |
1101
|
|
|
|
1102
|
|
|
// Just the remaining settings. |
1103
|
|
|
array('check', 'xmlnews_enable', 'onclick' => 'document.getElementById(\'xmlnews_maxlen\').disabled = !this.checked;'), |
1104
|
|
|
array('int', 'xmlnews_maxlen', 'subtext' => $txt['xmlnews_maxlen_note'], 10), |
1105
|
|
|
array('check', 'xmlnews_attachments', 'subtext' => $txt['xmlnews_attachments_note']), |
1106
|
|
|
); |
1107
|
|
|
|
1108
|
|
|
call_integration_hook('integrate_modify_news_settings', array(&$config_vars)); |
1109
|
|
|
|
1110
|
|
|
if ($return_config) |
1111
|
|
|
return $config_vars; |
1112
|
|
|
|
1113
|
|
|
$context['page_title'] = $txt['admin_edit_news'] . ' - ' . $txt['settings']; |
1114
|
|
|
$context['sub_template'] = 'show_settings'; |
1115
|
|
|
|
1116
|
|
|
// Needed for the settings template. |
1117
|
|
|
require_once($sourcedir . '/ManageServer.php'); |
1118
|
|
|
|
1119
|
|
|
// Wrap it all up nice and warm... |
1120
|
|
|
$context['post_url'] = $scripturl . '?action=admin;area=news;save;sa=settings'; |
1121
|
|
|
|
1122
|
|
|
// Add some javascript at the bottom... |
1123
|
|
|
addInlineJavaScript(' |
1124
|
|
|
document.getElementById("xmlnews_maxlen").disabled = !document.getElementById("xmlnews_enable").checked;', true); |
1125
|
|
|
|
1126
|
|
|
// Saving the settings? |
1127
|
|
|
if (isset($_GET['save'])) |
1128
|
|
|
{ |
1129
|
|
|
checkSession(); |
1130
|
|
|
|
1131
|
|
|
call_integration_hook('integrate_save_news_settings'); |
1132
|
|
|
|
1133
|
|
|
saveDBSettings($config_vars); |
1134
|
|
|
$_SESSION['adm-save'] = true; |
1135
|
|
|
redirectexit('action=admin;area=news;sa=settings'); |
1136
|
|
|
} |
1137
|
|
|
|
1138
|
|
|
// We need this for the in-line permissions |
1139
|
|
|
createToken('admin-mp'); |
1140
|
|
|
|
1141
|
|
|
prepareDBSettingContext($config_vars); |
1142
|
|
|
} |
1143
|
|
|
|
1144
|
|
|
?> |
This check looks for function or method calls that always return null and whose return value is used.
The method
getObject()
can return nothing but null, so it makes no sense to use the return value.The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.