showProfileDrafts()   F
last analyzed

Complexity

Conditions 25
Paths > 20000

Size

Total Lines 157
Code Lines 88

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 25
eloc 88
nc 71808
nop 2
dl 0
loc 157
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * This file contains all the functions that allow for the saving,
5
 * retrieving, deleting and settings for the drafts function.
6
 *
7
 * Simple Machines Forum (SMF)
8
 *
9
 * @package SMF
10
 * @author Simple Machines https://www.simplemachines.org
11
 * @copyright 2022 Simple Machines and individual contributors
12
 * @license https://www.simplemachines.org/about/smf/license.php BSD
13
 *
14
 * @version 2.1.0
15
 */
16
17
if (!defined('SMF'))
18
	die('No direct access...');
19
20
loadLanguage('Drafts');
21
22
/**
23
 * Saves a post draft in the user_drafts table
24
 * The core draft feature must be enabled, as well as the post draft option
25
 * Determines if this is a new or an existing draft
26
 * Returns errors in $post_errors for display in the template
27
 *
28
 * @param string[] $post_errors Any errors encountered trying to save this draft
29
 * @return boolean Always returns true
30
 */
31
function SaveDraft(&$post_errors)
32
{
33
	global $context, $user_info, $smcFunc, $modSettings, $board;
34
35
	// can you be, should you be ... here?
36
	if (empty($modSettings['drafts_post_enabled']) || !allowedTo('post_draft') || !isset($_POST['save_draft']) || !isset($_POST['id_draft']))
37
		return false;
38
39
	// read in what they sent us, if anything
40
	$id_draft = (int) $_POST['id_draft'];
41
	$draft_info = ReadDraft($id_draft);
42
43
	// A draft has been saved less than 5 seconds ago, let's not do the autosave again
44
	if (isset($_REQUEST['xml']) && !empty($draft_info['poster_time']) && time() < $draft_info['poster_time'] + 5)
45
	{
46
		$context['draft_saved_on'] = $draft_info['poster_time'];
47
48
		// since we were called from the autosave function, send something back
49
		if (!empty($id_draft))
50
			XmlDraft($id_draft);
51
52
		return true;
53
	}
54
55
	if (!isset($_POST['message']))
56
		$_POST['message'] = isset($_POST['quickReply']) ? $_POST['quickReply'] : '';
57
58
	// prepare any data from the form
59
	$topic_id = empty($_REQUEST['topic']) ? 0 : (int) $_REQUEST['topic'];
60
	$draft['icon'] = empty($_POST['icon']) ? 'xx' : preg_replace('~[\./\\\\*:"\'<>]~', '', $_POST['icon']);
0 ignored issues
show
Comprehensibility Best Practice introduced by
$draft was never initialized. Although not strictly required by PHP, it is generally a good practice to add $draft = array(); before regardless.
Loading history...
61
	$draft['smileys_enabled'] = isset($_POST['ns']) ? (int) $_POST['ns'] : 1;
62
	$draft['locked'] = isset($_POST['lock']) ? (int) $_POST['lock'] : 0;
63
	$draft['sticky'] = isset($_POST['sticky']) ? (int) $_POST['sticky'] : 0;
64
	$draft['subject'] = strtr($smcFunc['htmlspecialchars']($_POST['subject']), array("\r" => '', "\n" => '', "\t" => ''));
65
	$draft['body'] = $smcFunc['htmlspecialchars']($_POST['message'], ENT_QUOTES);
66
67
	// message and subject still need a bit more work
68
	preparsecode($draft['body']);
69
	if ($smcFunc['strlen']($draft['subject']) > 100)
70
		$draft['subject'] = $smcFunc['substr']($draft['subject'], 0, 100);
71
72
	// Modifying an existing draft, like hitting the save draft button or autosave enabled?
73
	if (!empty($id_draft) && !empty($draft_info))
74
	{
75
		$smcFunc['db_query']('', '
76
			UPDATE {db_prefix}user_drafts
77
			SET
78
				id_topic = {int:id_topic},
79
				id_board = {int:id_board},
80
				poster_time = {int:poster_time},
81
				subject = {string:subject},
82
				smileys_enabled = {int:smileys_enabled},
83
				body = {string:body},
84
				icon = {string:icon},
85
				locked = {int:locked},
86
				is_sticky = {int:is_sticky}
87
			WHERE id_draft = {int:id_draft}',
88
			array(
89
				'id_topic' => $topic_id,
90
				'id_board' => $board,
91
				'poster_time' => time(),
92
				'subject' => $draft['subject'],
93
				'smileys_enabled' => (int) $draft['smileys_enabled'],
94
				'body' => $draft['body'],
95
				'icon' => $draft['icon'],
96
				'locked' => $draft['locked'],
97
				'is_sticky' => $draft['sticky'],
98
				'id_draft' => $id_draft,
99
			)
100
		);
101
102
		// some items to return to the form
103
		$context['draft_saved'] = true;
104
		$context['id_draft'] = $id_draft;
105
106
		// cleanup
107
		unset($_POST['save_draft']);
108
	}
109
	// otherwise creating a new draft
110
	else
111
	{
112
		$id_draft = $smcFunc['db_insert']('',
113
			'{db_prefix}user_drafts',
114
			array(
115
				'id_topic' => 'int',
116
				'id_board' => 'int',
117
				'type' => 'int',
118
				'poster_time' => 'int',
119
				'id_member' => 'int',
120
				'subject' => 'string-255',
121
				'smileys_enabled' => 'int',
122
				'body' => (!empty($modSettings['max_messageLength']) && $modSettings['max_messageLength'] > 65534 ? 'string-' . $modSettings['max_messageLength'] : 'string-65534'),
123
				'icon' => 'string-16',
124
				'locked' => 'int',
125
				'is_sticky' => 'int'
126
			),
127
			array(
128
				$topic_id,
129
				$board,
130
				0,
131
				time(),
132
				$user_info['id'],
133
				$draft['subject'],
134
				$draft['smileys_enabled'],
135
				$draft['body'],
136
				$draft['icon'],
137
				$draft['locked'],
138
				$draft['sticky']
139
			),
140
			array(
141
				'id_draft'
142
			),
143
			1
144
		);
145
146
		// everything go as expected?
147
		if (!empty($id_draft))
148
		{
149
			$context['draft_saved'] = true;
150
			$context['id_draft'] = $id_draft;
151
		}
152
		else
153
			$post_errors[] = 'draft_not_saved';
154
155
		// cleanup
156
		unset($_POST['save_draft']);
157
	}
158
159
	// if we were called from the autosave function, send something back
160
	if (!empty($id_draft) && isset($_REQUEST['xml']) && (!in_array('session_timeout', $post_errors)))
161
	{
162
		$context['draft_saved_on'] = time();
163
		XmlDraft($id_draft);
164
	}
165
166
	return true;
167
}
168
169
/**
170
 * Saves a PM draft in the user_drafts table
171
 * The core draft feature must be enabled, as well as the pm draft option
172
 * Determines if this is a new or and update to an existing pm draft
173
 *
174
 * @param string $post_errors A string of info about errors encountered trying to save this draft
175
 * @param array $recipientList An array of data about who this PM is being sent to
176
 * @return boolean false if you can't save the draft, true if we're doing this via XML more than 5 seconds after the last save, nothing otherwise
177
 */
178
function SavePMDraft(&$post_errors, $recipientList)
179
{
180
	global $context, $user_info, $smcFunc, $modSettings;
181
182
	// PM survey says ... can you stay or must you go
183
	if (empty($modSettings['drafts_pm_enabled']) || !allowedTo('pm_draft') || !isset($_POST['save_draft']))
184
		return false;
185
186
	// read in what you sent us
187
	$id_pm_draft = (int) $_POST['id_pm_draft'];
188
	$draft_info = ReadDraft($id_pm_draft, 1);
189
190
	// 5 seconds is the same limit we have for posting
191
	if (isset($_REQUEST['xml']) && !empty($draft_info['poster_time']) && time() < $draft_info['poster_time'] + 5)
192
	{
193
		$context['draft_saved_on'] = $draft_info['poster_time'];
194
195
		// Send something back to the javascript caller
196
		if (!empty($id_draft))
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $id_draft does not exist. Did you maybe mean $id_pm_draft?
Loading history...
197
			XmlDraft($id_draft);
198
199
		return true;
200
	}
201
202
	// determine who this is being sent to
203
	if (isset($_REQUEST['xml']))
204
	{
205
		$recipientList['to'] = isset($_POST['recipient_to']) ? explode(',', $_POST['recipient_to']) : array();
206
		$recipientList['bcc'] = isset($_POST['recipient_bcc']) ? explode(',', $_POST['recipient_bcc']) : array();
207
	}
208
	elseif (!empty($draft_info['to_list']) && empty($recipientList))
209
		$recipientList = $smcFunc['json_decode']($draft_info['to_list'], true);
210
211
	// prepare the data we got from the form
212
	$reply_id = empty($_POST['replied_to']) ? 0 : (int) $_POST['replied_to'];
213
	$draft['body'] = $smcFunc['htmlspecialchars']($_POST['message'], ENT_QUOTES);
0 ignored issues
show
Comprehensibility Best Practice introduced by
$draft was never initialized. Although not strictly required by PHP, it is generally a good practice to add $draft = array(); before regardless.
Loading history...
214
	$draft['subject'] = strtr($smcFunc['htmlspecialchars']($_POST['subject']), array("\r" => '', "\n" => '', "\t" => ''));
215
216
	// message and subject always need a bit more work
217
	preparsecode($draft['body']);
218
	if ($smcFunc['strlen']($draft['subject']) > 100)
219
		$draft['subject'] = $smcFunc['substr']($draft['subject'], 0, 100);
220
221
	// Modifying an existing PM draft?
222
	if (!empty($id_pm_draft) && !empty($draft_info))
223
	{
224
		$smcFunc['db_query']('', '
225
			UPDATE {db_prefix}user_drafts
226
			SET id_reply = {int:id_reply},
227
				type = {int:type},
228
				poster_time = {int:poster_time},
229
				subject = {string:subject},
230
				body = {string:body},
231
				to_list = {string:to_list}
232
			WHERE id_draft = {int:id_pm_draft}',
233
			array(
234
				'id_reply' => $reply_id,
235
				'type' => 1,
236
				'poster_time' => time(),
237
				'subject' => $draft['subject'],
238
				'body' => $draft['body'],
239
				'id_pm_draft' => $id_pm_draft,
240
				'to_list' => $smcFunc['json_encode']($recipientList),
241
			)
242
		);
243
244
		// some items to return to the form
245
		$context['draft_saved'] = true;
246
		$context['id_pm_draft'] = $id_pm_draft;
247
	}
248
	// otherwise creating a new PM draft.
249
	else
250
	{
251
		$id_pm_draft = $smcFunc['db_insert']('',
252
			'{db_prefix}user_drafts',
253
			array(
254
				'id_reply' => 'int',
255
				'type' => 'int',
256
				'poster_time' => 'int',
257
				'id_member' => 'int',
258
				'subject' => 'string-255',
259
				'body' => 'string-65534',
260
				'to_list' => 'string-255',
261
			),
262
			array(
263
				$reply_id,
264
				1,
265
				time(),
266
				$user_info['id'],
267
				$draft['subject'],
268
				$draft['body'],
269
				$smcFunc['json_encode']($recipientList),
270
			),
271
			array(
272
				'id_draft'
273
			),
274
			1
275
		);
276
277
		// everything go as expected, if not toss back an error
278
		if (!empty($id_pm_draft))
279
		{
280
			$context['draft_saved'] = true;
281
			$context['id_pm_draft'] = $id_pm_draft;
282
		}
283
		else
284
			$post_errors[] = 'draft_not_saved';
285
	}
286
287
	// if we were called from the autosave function, send something back
288
	if (!empty($id_pm_draft) && isset($_REQUEST['xml']) && !in_array('session_timeout', $post_errors))
0 ignored issues
show
Bug introduced by
$post_errors of type string is incompatible with the type array expected by parameter $haystack of in_array(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

288
	if (!empty($id_pm_draft) && isset($_REQUEST['xml']) && !in_array('session_timeout', /** @scrutinizer ignore-type */ $post_errors))
Loading history...
289
	{
290
		$context['draft_saved_on'] = time();
291
		XmlDraft($id_pm_draft);
292
	}
293
294
	return;
295
}
296
297
/**
298
 * Reads a draft in from the user_drafts table
299
 * Validates that the draft is the user''s draft
300
 * Optionally loads the draft in to context or superglobal for loading in to the form
301
 *
302
 * @param int $id_draft ID of the draft to load
303
 * @param int $type Type of draft - 0 for post or 1 for PM
304
 * @param boolean $check Validate that this draft belongs to the current user
305
 * @param boolean $load Whether or not to load the data into variables for use on a form
306
 * @return boolean|array False if the data couldn't be loaded, true if it's a PM draft or an array of info about the draft if it's a post draft
307
 */
308
function ReadDraft($id_draft, $type = 0, $check = true, $load = false)
309
{
310
	global $context, $user_info, $smcFunc, $modSettings;
311
312
	// like purell always clean to be sure
313
	$id_draft = (int) $id_draft;
314
	$type = (int) $type;
315
316
	// nothing to read, nothing to do
317
	if (empty($id_draft))
318
		return false;
319
320
	// load in this draft from the DB
321
	$request = $smcFunc['db_query']('', '
322
		SELECT is_sticky, locked, smileys_enabled, icon, body , subject,
323
			id_board, id_draft, id_reply, to_list
324
		FROM {db_prefix}user_drafts
325
		WHERE id_draft = {int:id_draft}' . ($check ? '
326
			AND id_member = {int:id_member}' : '') . '
327
			AND type = {int:type}' . (!empty($modSettings['drafts_keep_days']) ? '
328
			AND poster_time > {int:time}' : '') . '
329
		LIMIT 1',
330
		array(
331
			'id_member' => $user_info['id'],
332
			'id_draft' => $id_draft,
333
			'type' => $type,
334
			'time' => (!empty($modSettings['drafts_keep_days']) ? (time() - ($modSettings['drafts_keep_days'] * 86400)) : 0),
335
		)
336
	);
337
338
	// no results?
339
	if (!$smcFunc['db_num_rows']($request))
340
		return false;
341
342
	// load up the data
343
	$draft_info = $smcFunc['db_fetch_assoc']($request);
344
	$smcFunc['db_free_result']($request);
345
346
	// Load it up for the templates as well
347
	if (!empty($load))
348
	{
349
		if ($type === 0)
350
		{
351
			// a standard post draft?
352
			$context['sticky'] = !empty($draft_info['is_sticky']) ? $draft_info['is_sticky'] : '';
353
			$context['locked'] = !empty($draft_info['locked']) ? $draft_info['locked'] : '';
354
			$context['use_smileys'] = !empty($draft_info['smileys_enabled']) ? true : false;
355
			$context['icon'] = !empty($draft_info['icon']) ? $draft_info['icon'] : 'xx';
356
			$context['message'] = !empty($draft_info['body']) ? str_replace('<br>', "\n", un_htmlspecialchars(stripslashes($draft_info['body']))) : '';
357
			$context['subject'] = !empty($draft_info['subject']) ? stripslashes($draft_info['subject']) : '';
358
			$context['board'] = !empty($draft_info['id_board']) ? $draft_info['id_board'] : '';
359
			$context['id_draft'] = !empty($draft_info['id_draft']) ? $draft_info['id_draft'] : 0;
360
		}
361
		elseif ($type === 1)
362
		{
363
			// one of those pm drafts? then set it up like we have an error
364
			$_REQUEST['subject'] = !empty($draft_info['subject']) ? stripslashes($draft_info['subject']) : '';
365
			$_REQUEST['message'] = !empty($draft_info['body']) ? str_replace('<br>', "\n", un_htmlspecialchars(stripslashes($draft_info['body']))) : '';
366
			$_REQUEST['replied_to'] = !empty($draft_info['id_reply']) ? $draft_info['id_reply'] : 0;
367
			$context['id_pm_draft'] = !empty($draft_info['id_draft']) ? $draft_info['id_draft'] : 0;
368
			$recipients = $smcFunc['json_decode']($draft_info['to_list'], true);
369
370
			// make sure we only have integers in this array
371
			$recipients['to'] = array_map('intval', $recipients['to']);
372
			$recipients['bcc'] = array_map('intval', $recipients['bcc']);
373
374
			// pretend we messed up to populate the pm message form
375
			messagePostError(array(), array(), $recipients);
376
			return true;
377
		}
378
	}
379
380
	return $draft_info;
381
}
382
383
/**
384
 * Deletes one or many drafts from the DB
385
 * Validates the drafts are from the user
386
 * is supplied an array of drafts will attempt to remove all of them
387
 *
388
 * @param int $id_draft The ID of the draft to delete
389
 * @param boolean $check Whether or not to check that the draft belongs to the current user
390
 * @return boolean False if it couldn't be deleted (doesn't return anything otherwise)
391
 */
392
function DeleteDraft($id_draft, $check = true)
393
{
394
	global $user_info, $smcFunc;
395
396
	// Only a single draft.
397
	if (is_numeric($id_draft))
0 ignored issues
show
introduced by
The condition is_numeric($id_draft) is always true.
Loading history...
398
		$id_draft = array($id_draft);
399
400
	// can't delete nothing
401
	if (empty($id_draft) || ($check && empty($user_info['id'])))
402
		return false;
403
404
	$smcFunc['db_query']('', '
405
		DELETE FROM {db_prefix}user_drafts
406
		WHERE id_draft IN ({array_int:id_draft})' . ($check ? '
407
			AND  id_member = {int:id_member}' : ''),
408
		array(
409
			'id_draft' => $id_draft,
410
			'id_member' => empty($user_info['id']) ? -1 : $user_info['id'],
411
		)
412
	);
413
}
414
415
/**
416
 * Loads in a group of drafts for the user of a given type (0/posts, 1/pm's)
417
 * loads a specific draft for forum use if selected.
418
 * Used in the posting screens to allow draft selection
419
 * Will load a draft if selected is supplied via post
420
 *
421
 * @param int $member_id ID of the member to show drafts for
422
 * @param boolean|integer $topic If $type is 1, this can be set to only load drafts for posts in the specific topic
423
 * @param int $draft_type The type of drafts to show - 0 for post drafts, 1 for PM drafts
424
 * @return boolean False if the drafts couldn't be loaded, nothing otherwise
425
 */
426
function ShowDrafts($member_id, $topic = false, $draft_type = 0)
427
{
428
	global $smcFunc, $scripturl, $context, $txt, $modSettings;
429
430
	// Permissions
431
	if (($draft_type === 0 && empty($context['drafts_save'])) || ($draft_type === 1 && empty($context['drafts_pm_save'])) || empty($member_id))
432
		return false;
433
434
	$context['drafts'] = array();
435
436
	// has a specific draft has been selected?  Load it up if there is not a message already in the editor
437
	if (isset($_REQUEST['id_draft']) && empty($_POST['subject']) && empty($_POST['message']))
438
		ReadDraft((int) $_REQUEST['id_draft'], $draft_type, true, true);
439
440
	// load the drafts this user has available
441
	$request = $smcFunc['db_query']('', '
442
		SELECT subject, poster_time, id_board, id_topic, id_draft
443
		FROM {db_prefix}user_drafts
444
		WHERE id_member = {int:id_member}' . ((!empty($topic) && empty($draft_type)) ? '
445
			AND id_topic = {int:id_topic}' : (!empty($topic) ? '
446
			AND id_reply = {int:id_topic}' : '')) . '
447
			AND type = {int:draft_type}' . (!empty($modSettings['drafts_keep_days']) ? '
448
			AND poster_time > {int:time}' : '') . '
449
		ORDER BY poster_time DESC',
450
		array(
451
			'id_member' => $member_id,
452
			'id_topic' => (int) $topic,
453
			'draft_type' => $draft_type,
454
			'time' => (!empty($modSettings['drafts_keep_days']) ? (time() - ($modSettings['drafts_keep_days'] * 86400)) : 0),
455
		)
456
	);
457
458
	// add them to the draft array for display
459
	while ($row = $smcFunc['db_fetch_assoc']($request))
460
	{
461
		if (empty($row['subject']))
462
			$row['subject'] = $txt['no_subject'];
463
464
		// Post drafts
465
		if ($draft_type === 0)
466
		{
467
			$tmp_subject = shorten_subject(stripslashes($row['subject']), 24);
468
			$context['drafts'][] = array(
469
				'subject' => censorText($tmp_subject),
470
				'poster_time' => timeformat($row['poster_time']),
471
				'link' => '<a href="' . $scripturl . '?action=post;board=' . $row['id_board'] . ';' . (!empty($row['id_topic']) ? 'topic=' . $row['id_topic'] . '.0;' : '') . 'id_draft=' . $row['id_draft'] . '">' . $row['subject'] . '</a>',
472
			);
473
		}
474
		// PM drafts
475
		elseif ($draft_type === 1)
476
		{
477
			$tmp_subject = shorten_subject(stripslashes($row['subject']), 24);
478
			$context['drafts'][] = array(
479
				'subject' => censorText($tmp_subject),
480
				'poster_time' => timeformat($row['poster_time']),
481
				'link' => '<a href="' . $scripturl . '?action=pm;sa=send;id_draft=' . $row['id_draft'] . '">' . (!empty($row['subject']) ? $row['subject'] : $txt['drafts_none']) . '</a>',
482
			);
483
		}
484
	}
485
	$smcFunc['db_free_result']($request);
486
}
487
488
/**
489
 * Returns an xml response to an autosave ajax request
490
 * provides the id of the draft saved and the time it was saved
491
 *
492
 * @param int $id_draft
493
 */
494
function XmlDraft($id_draft)
495
{
496
	global $txt, $context;
497
498
	header('content-type: text/xml; charset=' . (empty($context['character_set']) ? 'ISO-8859-1' : $context['character_set']));
499
500
	echo '<?xml version="1.0" encoding="', $context['character_set'], '"?>
501
	<drafts>
502
		<draft id="', $id_draft, '"><![CDATA[', $txt['draft_saved_on'], ': ', timeformat($context['draft_saved_on']), ']]></draft>
503
	</drafts>';
504
505
	obExit(false);
506
}
507
508
/**
509
 * Show all drafts of a given type by the current user
510
 * Uses the showdraft template
511
 * Allows for the deleting and loading/editing of drafts
512
 *
513
 * @param int $memID
514
 * @param int $draft_type
515
 */
516
function showProfileDrafts($memID, $draft_type = 0)
517
{
518
	global $txt, $scripturl, $modSettings, $context, $smcFunc, $options;
519
520
	// Some initial context.
521
	$context['start'] = isset($_REQUEST['start']) ? (int) $_REQUEST['start'] : 0;
522
	$context['current_member'] = $memID;
523
524
	// If just deleting a draft, do it and then redirect back.
525
	if (!empty($_REQUEST['delete']))
526
	{
527
		checkSession('get');
528
		$id_delete = (int) $_REQUEST['delete'];
529
530
		$smcFunc['db_query']('', '
531
			DELETE FROM {db_prefix}user_drafts
532
			WHERE id_draft = {int:id_draft}
533
				AND id_member = {int:id_member}
534
				AND type = {int:draft_type}',
535
			array(
536
				'id_draft' => $id_delete,
537
				'id_member' => $memID,
538
				'draft_type' => $draft_type,
539
			)
540
		);
541
542
		redirectexit('action=profile;u=' . $memID . ';area=showdrafts;start=' . $context['start']);
543
	}
544
545
	// Default to 10.
546
	if (empty($_REQUEST['viewscount']) || !is_numeric($_REQUEST['viewscount']))
547
		$_REQUEST['viewscount'] = 10;
548
549
	// Get the count of applicable drafts on the boards they can (still) see ...
550
	// @todo .. should we just let them see their drafts even if they have lost board access ?
551
	$request = $smcFunc['db_query']('', '
552
		SELECT COUNT(*)
553
		FROM {db_prefix}user_drafts AS ud
554
			INNER JOIN {db_prefix}boards AS b ON (b.id_board = ud.id_board AND {query_see_board})
555
		WHERE id_member = {int:id_member}
556
			AND type={int:draft_type}' . (!empty($modSettings['drafts_keep_days']) ? '
557
			AND poster_time > {int:time}' : ''),
558
		array(
559
			'id_member' => $memID,
560
			'draft_type' => $draft_type,
561
			'time' => (!empty($modSettings['drafts_keep_days']) ? (time() - ($modSettings['drafts_keep_days'] * 86400)) : 0),
562
		)
563
	);
564
	list ($msgCount) = $smcFunc['db_fetch_row']($request);
565
	$smcFunc['db_free_result']($request);
566
567
	$maxPerPage = empty($modSettings['disableCustomPerPage']) && !empty($options['messages_per_page']) ? $options['messages_per_page'] : $modSettings['defaultMaxMessages'];
568
	$maxIndex = $maxPerPage;
569
570
	// Make sure the starting place makes sense and construct our friend the page index.
571
	$context['page_index'] = constructPageIndex($scripturl . '?action=profile;u=' . $memID . ';area=showdrafts', $context['start'], $msgCount, $maxIndex);
572
	$context['current_page'] = $context['start'] / $maxIndex;
573
574
	// Reverse the query if we're past 50% of the pages for better performance.
575
	$start = $context['start'];
576
	$reverse = $_REQUEST['start'] > $msgCount / 2;
577
	if ($reverse)
578
	{
579
		$maxIndex = $msgCount < $context['start'] + $maxPerPage + 1 && $msgCount > $context['start'] ? $msgCount - $context['start'] : $maxPerPage;
580
		$start = $msgCount < $context['start'] + $maxPerPage + 1 || $msgCount < $context['start'] + $maxPerPage ? 0 : $msgCount - $context['start'] - $maxPerPage;
581
	}
582
583
	// Find this user's drafts for the boards they can access
584
	// @todo ... do we want to do this?  If they were able to create a draft, do we remove thier access to said draft if they loose
585
	//           access to the board or if the topic moves to a board they can not see?
586
	$request = $smcFunc['db_query']('', '
587
		SELECT
588
			b.id_board, b.name AS bname,
589
			ud.id_member, ud.id_draft, ud.body, ud.smileys_enabled, ud.subject, ud.poster_time, ud.icon, ud.id_topic, ud.locked, ud.is_sticky
590
		FROM {db_prefix}user_drafts AS ud
591
			INNER JOIN {db_prefix}boards AS b ON (b.id_board = ud.id_board AND {query_see_board})
592
		WHERE ud.id_member = {int:current_member}
593
			AND type = {int:draft_type}' . (!empty($modSettings['drafts_keep_days']) ? '
594
			AND poster_time > {int:time}' : '') . '
595
		ORDER BY ud.id_draft ' . ($reverse ? 'ASC' : 'DESC') . '
596
		LIMIT {int:start}, {int:max}',
597
		array(
598
			'current_member' => $memID,
599
			'draft_type' => $draft_type,
600
			'time' => (!empty($modSettings['drafts_keep_days']) ? (time() - ($modSettings['drafts_keep_days'] * 86400)) : 0),
601
			'start' => $start,
602
			'max' => $maxIndex,
603
		)
604
	);
605
606
	// Start counting at the number of the first message displayed.
607
	$counter = $reverse ? $context['start'] + $maxIndex + 1 : $context['start'];
608
	$context['posts'] = array();
609
	while ($row = $smcFunc['db_fetch_assoc']($request))
610
	{
611
		// Censor....
612
		if (empty($row['body']))
613
			$row['body'] = '';
614
615
		$row['subject'] = $smcFunc['htmltrim']($row['subject']);
616
		if (empty($row['subject']))
617
			$row['subject'] = $txt['no_subject'];
618
619
		censorText($row['body']);
620
		censorText($row['subject']);
621
622
		// BBC-ilize the message.
623
		$row['body'] = parse_bbc($row['body'], $row['smileys_enabled'], 'draft' . $row['id_draft']);
624
625
		// And the array...
626
		$context['drafts'][$counter += $reverse ? -1 : 1] = array(
627
			'body' => $row['body'],
628
			'counter' => $counter,
629
			'board' => array(
630
				'name' => $row['bname'],
631
				'id' => $row['id_board']
632
			),
633
			'topic' => array(
634
				'id' => $row['id_topic'],
635
				'link' => empty($row['id']) ? $row['subject'] : '<a href="' . $scripturl . '?topic=' . $row['id_topic'] . '.0">' . $row['subject'] . '</a>',
636
			),
637
			'subject' => $row['subject'],
638
			'time' => timeformat($row['poster_time']),
639
			'timestamp' => $row['poster_time'],
640
			'icon' => $row['icon'],
641
			'id_draft' => $row['id_draft'],
642
			'locked' => $row['locked'],
643
			'sticky' => $row['is_sticky'],
644
			'quickbuttons' => array(
645
				'edit' => array(
646
					'label' => $txt['draft_edit'],
647
					'href' => $scripturl.'?action=post;'.(empty($row['id_topic']) ? 'board='.$row['id_board'] : 'topic='.$row['id_topic']).'.0;id_draft='.$row['id_draft'],
648
					'icon' => 'modify_button'
649
				),
650
				'delete' => array(
651
					'label' => $txt['draft_delete'],
652
					'href' => $scripturl.'?action=profile;u='.$context['member']['id'].';area=showdrafts;delete='.$row['id_draft'].';'.$context['session_var'].'='.$context['session_id'],
653
					'javascript' => 'data-confirm="'.$txt['draft_remove'].'"',
654
					'class' => 'you_sure',
655
					'icon' => 'remove_button'
656
				),
657
			),
658
		);
659
	}
660
	$smcFunc['db_free_result']($request);
661
662
	// If the drafts were retrieved in reverse order, get them right again.
663
	if ($reverse)
664
		$context['drafts'] = array_reverse($context['drafts'], true);
665
666
	// Menu tab
667
	$context[$context['profile_menu_name']]['tab_data'] = array(
668
		'title' => $txt['drafts_show'],
669
		'description' => $txt['drafts_show_desc'],
670
		'icon_class' => 'main_icons drafts'
671
	);
672
	$context['sub_template'] = 'showDrafts';
673
}
674
675
/**
676
 * Show all PM drafts of the current user
677
 * Uses the showpmdraft template
678
 * Allows for the deleting and loading/editing of drafts
679
 *
680
 * @param int $memID
681
 */
682
function showPMDrafts($memID = -1)
683
{
684
	global $txt, $user_info, $scripturl, $modSettings, $context, $smcFunc, $options;
685
686
	// init
687
	$draft_type = 1;
688
	$context['start'] = isset($_REQUEST['start']) ? (int) $_REQUEST['start'] : 0;
689
690
	// If just deleting a draft, do it and then redirect back.
691
	if (!empty($_REQUEST['delete']))
692
	{
693
		checkSession('get');
694
		$id_delete = (int) $_REQUEST['delete'];
695
		$start = isset($_REQUEST['start']) ? (int) $_REQUEST['start'] : 0;
696
697
		$smcFunc['db_query']('', '
698
			DELETE FROM {db_prefix}user_drafts
699
			WHERE id_draft = {int:id_draft}
700
				AND id_member = {int:id_member}
701
				AND type = {int:draft_type}',
702
			array(
703
				'id_draft' => $id_delete,
704
				'id_member' => $memID,
705
				'draft_type' => $draft_type,
706
			)
707
		);
708
709
		// now redirect back to the list
710
		redirectexit('action=pm;sa=showpmdrafts;start=' . $start);
711
	}
712
713
	// perhaps a draft was selected for editing? if so pass this off
714
	if (!empty($_REQUEST['id_draft']) && !empty($context['drafts_pm_save']) && $memID == $user_info['id'])
715
	{
716
		checkSession('get');
717
		$id_draft = (int) $_REQUEST['id_draft'];
718
		redirectexit('action=pm;sa=send;id_draft=' . $id_draft);
719
	}
720
721
	// Default to 10.
722
	if (empty($_REQUEST['viewscount']) || !is_numeric($_REQUEST['viewscount']))
723
		$_REQUEST['viewscount'] = 10;
724
725
	// Get the count of applicable drafts
726
	$request = $smcFunc['db_query']('', '
727
		SELECT COUNT(*)
728
		FROM {db_prefix}user_drafts
729
		WHERE id_member = {int:id_member}
730
			AND type={int:draft_type}' . (!empty($modSettings['drafts_keep_days']) ? '
731
			AND poster_time > {int:time}' : ''),
732
		array(
733
			'id_member' => $memID,
734
			'draft_type' => $draft_type,
735
			'time' => (!empty($modSettings['drafts_keep_days']) ? (time() - ($modSettings['drafts_keep_days'] * 86400)) : 0),
736
		)
737
	);
738
	list ($msgCount) = $smcFunc['db_fetch_row']($request);
739
	$smcFunc['db_free_result']($request);
740
741
	$maxPerPage = empty($modSettings['disableCustomPerPage']) && !empty($options['messages_per_page']) ? $options['messages_per_page'] : $modSettings['defaultMaxMessages'];
742
	$maxIndex = $maxPerPage;
743
744
	// Make sure the starting place makes sense and construct our friend the page index.
745
	$context['page_index'] = constructPageIndex($scripturl . '?action=pm;sa=showpmdrafts', $context['start'], $msgCount, $maxIndex);
746
	$context['current_page'] = $context['start'] / $maxIndex;
747
748
	// Reverse the query if we're past 50% of the total for better performance.
749
	$start = $context['start'];
750
	$reverse = $_REQUEST['start'] > $msgCount / 2;
751
	if ($reverse)
752
	{
753
		$maxIndex = $msgCount < $context['start'] + $maxPerPage + 1 && $msgCount > $context['start'] ? $msgCount - $context['start'] : $maxPerPage;
754
		$start = $msgCount < $context['start'] + $maxPerPage + 1 || $msgCount < $context['start'] + $maxPerPage ? 0 : $msgCount - $context['start'] - $maxPerPage;
755
	}
756
757
	// Load in this user's PM drafts
758
	$request = $smcFunc['db_query']('', '
759
		SELECT
760
			ud.id_member, ud.id_draft, ud.body, ud.subject, ud.poster_time, ud.id_reply, ud.to_list
761
		FROM {db_prefix}user_drafts AS ud
762
		WHERE ud.id_member = {int:current_member}
763
			AND type = {int:draft_type}' . (!empty($modSettings['drafts_keep_days']) ? '
764
			AND poster_time > {int:time}' : '') . '
765
		ORDER BY ud.id_draft ' . ($reverse ? 'ASC' : 'DESC') . '
766
		LIMIT {int:start}, {int:max}',
767
		array(
768
			'current_member' => $memID,
769
			'draft_type' => $draft_type,
770
			'time' => (!empty($modSettings['drafts_keep_days']) ? (time() - ($modSettings['drafts_keep_days'] * 86400)) : 0),
771
			'start' => $start,
772
			'max' => $maxIndex,
773
		)
774
	);
775
776
	// Start counting at the number of the first message displayed.
777
	$counter = $reverse ? $context['start'] + $maxIndex + 1 : $context['start'];
778
	$context['posts'] = array();
779
	while ($row = $smcFunc['db_fetch_assoc']($request))
780
	{
781
		// Censor....
782
		if (empty($row['body']))
783
			$row['body'] = '';
784
785
		$row['subject'] = $smcFunc['htmltrim']($row['subject']);
786
		if (empty($row['subject']))
787
			$row['subject'] = $txt['no_subject'];
788
789
		censorText($row['body']);
790
		censorText($row['subject']);
791
792
		// BBC-ilize the message.
793
		$row['body'] = parse_bbc($row['body'], true, 'draft' . $row['id_draft']);
794
795
		// Have they provide who this will go to?
796
		$recipients = array(
797
			'to' => array(),
798
			'bcc' => array(),
799
		);
800
		$recipient_ids = (!empty($row['to_list'])) ? $smcFunc['json_decode']($row['to_list'], true) : array();
801
802
		// @todo ... this is a bit ugly since it runs an extra query for every message, do we want this?
803
		// at least its only for draft PM's and only the user can see them ... so not heavily used .. still
804
		if (!empty($recipient_ids['to']) || !empty($recipient_ids['bcc']))
805
		{
806
			$recipient_ids['to'] = array_map('intval', $recipient_ids['to']);
807
			$recipient_ids['bcc'] = array_map('intval', $recipient_ids['bcc']);
808
			$allRecipients = array_merge($recipient_ids['to'], $recipient_ids['bcc']);
809
810
			$request_2 = $smcFunc['db_query']('', '
811
				SELECT id_member, real_name
812
				FROM {db_prefix}members
813
				WHERE id_member IN ({array_int:member_list})',
814
				array(
815
					'member_list' => $allRecipients,
816
				)
817
			);
818
			while ($result = $smcFunc['db_fetch_assoc']($request_2))
819
			{
820
				$recipientType = in_array($result['id_member'], $recipient_ids['bcc']) ? 'bcc' : 'to';
821
				$recipients[$recipientType][] = $result['real_name'];
822
			}
823
			$smcFunc['db_free_result']($request_2);
824
		}
825
826
		// Add the items to the array for template use
827
		$context['drafts'][$counter += $reverse ? -1 : 1] = array(
828
			'body' => $row['body'],
829
			'counter' => $counter,
830
			'subject' => $row['subject'],
831
			'time' => timeformat($row['poster_time']),
832
			'timestamp' => $row['poster_time'],
833
			'id_draft' => $row['id_draft'],
834
			'recipients' => $recipients,
835
			'age' => floor((time() - $row['poster_time']) / 86400),
836
			'remaining' => (!empty($modSettings['drafts_keep_days']) ? floor($modSettings['drafts_keep_days'] - ((time() - $row['poster_time']) / 86400)) : 0),
837
			'quickbuttons' => array(
838
				'edit' => array(
839
					'label' => $txt['draft_edit'],
840
					'href' => $scripturl.'?action=pm;sa=showpmdrafts;id_draft='.$row['id_draft'].';'.$context['session_var'].'='.$context['session_id'],
841
					'icon' => 'modify_button'
842
				),
843
				'delete' => array(
844
					'label' => $txt['draft_delete'],
845
					'href' => $scripturl.'?action=pm;sa=showpmdrafts;delete='.$row['id_draft'].';'.$context['session_var'].'='.$context['session_id'],
846
					'javascript' => 'data-confirm="'.$txt['draft_remove'].'?"',
847
					'class' => 'you_sure',
848
					'icon' => 'remove_button'
849
				),
850
			),
851
		);
852
	}
853
	$smcFunc['db_free_result']($request);
854
855
	// if the drafts were retrieved in reverse order, then put them in the right order again.
856
	if ($reverse)
857
		$context['drafts'] = array_reverse($context['drafts'], true);
858
859
	// off to the template we go
860
	$context['page_title'] = $txt['drafts'];
861
	$context['sub_template'] = 'showPMDrafts';
862
	$context['linktree'][] = array(
863
		'url' => $scripturl . '?action=pm;sa=showpmdrafts',
864
		'name' => $txt['drafts'],
865
	);
866
}
867
868
?>