Failed Conditions
Branch release-2.1 (4e22cf)
by Rick
06:39
created

Drafts.php ➔ ShowDrafts()   C

Complexity

Conditions 20
Paths 23

Size

Total Lines 61
Code Lines 34

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 20
eloc 34
nc 23
nop 3
dl 0
loc 61
rs 6.1367
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 http://www.simplemachines.org
11
 * @copyright 2017 Simple Machines and individual contributors
12
 * @license http://www.simplemachines.org/about/smf/license.php BSD
13
 *
14
 * @version 2.1 Beta 4
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 View Code Duplication
	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
Coding Style Comprehensibility introduced by
$draft was never initialized. Although not strictly required by PHP, it is generally a good practice to add $draft = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
61
	$draft['smileys_enabled'] = isset($_POST['ns']) ? (int) $_POST['ns'] : 0;
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 View Code Duplication
	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 View Code Duplication
		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 View Code Duplication
	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
0 ignored issues
show
Documentation introduced by
Should the return type not be boolean|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
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 View Code Duplication
	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
Bug introduced by
The variable $id_draft seems to never exist, and therefore empty should always return true. Did you maybe rename this variable?

This check looks for calls to isset(...) or empty() on variables that are yet undefined. These calls will always produce the same result and can be removed.

This is most likely caused by the renaming of a variable or the removal of a function/method parameter.

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
Coding Style Comprehensibility introduced by
$draft was never initialized. Although not strictly required by PHP, it is generally a good practice to add $draft = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

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 View Code Duplication
	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
			LIMIT 1',
234
			array(
235
				'id_reply' => $reply_id,
236
				'type' => 1,
237
				'poster_time' => time(),
238
				'subject' => $draft['subject'],
239
				'body' => $draft['body'],
240
				'id_pm_draft' => $id_pm_draft,
241
				'to_list' => $smcFunc['json_encode']($recipientList),
242
			)
243
		);
244
245
		// some items to return to the form
246
		$context['draft_saved'] = true;
247
		$context['id_pm_draft'] = $id_pm_draft;
248
	}
249
	// otherwise creating a new PM draft.
250
	else
251
	{
252
		$id_pm_draft = $smcFunc['db_insert']('',
253
			'{db_prefix}user_drafts',
254
			array(
255
				'id_reply' => 'int',
256
				'type' => 'int',
257
				'poster_time' => 'int',
258
				'id_member' => 'int',
259
				'subject' => 'string-255',
260
				'body' => 'string-65534',
261
				'to_list' => 'string-255',
262
			),
263
			array(
264
				$reply_id,
265
				1,
266
				time(),
267
				$user_info['id'],
268
				$draft['subject'],
269
				$draft['body'],
270
				$smcFunc['json_encode']($recipientList),
271
			),
272
			array(
273
				'id_draft'
274
			),
275
			1
276
		);
277
278
		// everything go as expected, if not toss back an error
279 View Code Duplication
		if (!empty($id_pm_draft))
280
		{
281
			$context['draft_saved'] = true;
282
			$context['id_pm_draft'] = $id_pm_draft;
283
		}
284
		else
285
			$post_errors[] = 'draft_not_saved';
286
	}
287
288
	// if we were called from the autosave function, send something back
289 View Code Duplication
	if (!empty($id_pm_draft) && isset($_REQUEST['xml']) && !in_array('session_timeout', $post_errors))
290
	{
291
		$context['draft_saved_on'] = time();
292
		XmlDraft($id_pm_draft);
293
	}
294
295
	return;
296
}
297
298
/**
299
 * Reads a draft in from the user_drafts table
300
 * Validates that the draft is the user''s draft
301
 * Optionally loads the draft in to context or superglobal for loading in to the form
302
 *
303
 * @param int $id_draft ID of the draft to load
304
 * @param int $type Type of draft - 0 for post or 1 for PM
305
 * @param boolean $check Validate that this draft belongs to the current user
306
 * @param boolean $load Whether or not to load the data into variables for use on a form
307
 * @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
308
 */
309
function ReadDraft($id_draft, $type = 0, $check = true, $load = false)
310
{
311
	global $context, $user_info, $smcFunc, $modSettings;
312
313
	// like purell always clean to be sure
314
	$id_draft = (int) $id_draft;
315
	$type = (int) $type;
316
317
	// nothing to read, nothing to do
318
	if (empty($id_draft))
319
		return false;
320
321
	// load in this draft from the DB
322
	$request = $smcFunc['db_query']('', '
323
		SELECT is_sticky, locked, smileys_enabled, icon, body , subject,
324
			id_board, id_draft, id_reply, to_list
325
		FROM {db_prefix}user_drafts
326
		WHERE id_draft = {int:id_draft}' . ($check ? '
327
			AND id_member = {int:id_member}' : '') . '
328
			AND type = {int:type}' . (!empty($modSettings['drafts_keep_days']) ? '
329
			AND poster_time > {int:time}' : '') . '
330
		LIMIT 1',
331
		array(
332
			'id_member' => $user_info['id'],
333
			'id_draft' => $id_draft,
334
			'type' => $type,
335
			'time' => (!empty($modSettings['drafts_keep_days']) ? (time() - ($modSettings['drafts_keep_days'] * 86400)) : 0),
336
		)
337
	);
338
339
	// no results?
340
	if (!$smcFunc['db_num_rows']($request))
341
		return false;
342
343
	// load up the data
344
	$draft_info = $smcFunc['db_fetch_assoc']($request);
345
	$smcFunc['db_free_result']($request);
346
347
	// Load it up for the templates as well
348
	if (!empty($load))
349
	{
350
		if ($type === 0)
351
		{
352
			// a standard post draft?
353
			$context['sticky'] = !empty($draft_info['is_sticky']) ? $draft_info['is_sticky'] : '';
354
			$context['locked'] = !empty($draft_info['locked']) ? $draft_info['locked'] : '';
355
			$context['use_smileys'] = !empty($draft_info['smileys_enabled']) ? true : false;
356
			$context['icon'] = !empty($draft_info['icon']) ? $draft_info['icon'] : 'xx';
357
			$context['message'] = !empty($draft_info['body']) ? str_replace('<br>', "\n", un_htmlspecialchars(stripslashes($draft_info['body']))) : '';
358
			$context['subject'] = !empty($draft_info['subject']) ? stripslashes($draft_info['subject']) : '';
359
			$context['board'] = !empty($draft_info['id_board']) ? $draft_info['id_board'] : '';
360
			$context['id_draft'] = !empty($draft_info['id_draft']) ? $draft_info['id_draft'] : 0;
361
		}
362
		elseif ($type === 1)
363
		{
364
			// one of those pm drafts? then set it up like we have an error
365
			$_REQUEST['subject'] = !empty($draft_info['subject']) ? stripslashes($draft_info['subject']) : '';
366
			$_REQUEST['message'] = !empty($draft_info['body']) ? str_replace('<br>', "\n", un_htmlspecialchars(stripslashes($draft_info['body']))) : '';
367
			$_REQUEST['replied_to'] = !empty($draft_info['id_reply']) ? $draft_info['id_reply'] : 0;
368
			$context['id_pm_draft'] = !empty($draft_info['id_draft']) ? $draft_info['id_draft'] : 0;
369
			$recipients = $smcFunc['json_decode']($draft_info['to_list'], true);
370
371
			// make sure we only have integers in this array
372
			$recipients['to'] = array_map('intval', $recipients['to']);
373
			$recipients['bcc'] = array_map('intval', $recipients['bcc']);
374
375
			// pretend we messed up to populate the pm message form
376
			messagePostError(array(), array(), $recipients);
377
			return true;
378
		}
379
	}
380
381
	return $draft_info;
382
}
383
384
/**
385
 * Deletes one or many drafts from the DB
386
 * Validates the drafts are from the user
387
 * is supplied an array of drafts will attempt to remove all of them
388
 *
389
 * @param int $id_draft The ID of the draft to delete
390
 * @param boolean $check Whether or not to check that the draft belongs to the current user
391
 * @return boolean False if it couldn't be deleted (doesn't return anything otherwise)
0 ignored issues
show
Documentation introduced by
Should the return type not be false|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
392
 */
393
function DeleteDraft($id_draft, $check = true)
394
{
395
	global $user_info, $smcFunc;
396
397
	// Only a single draft.
398
	if (is_numeric($id_draft))
399
		$id_draft = array($id_draft);
400
401
	// can't delete nothing
402
	if (empty($id_draft) || ($check && empty($user_info['id'])))
403
		return false;
404
405
	$smcFunc['db_query']('', '
406
		DELETE FROM {db_prefix}user_drafts
407
		WHERE id_draft IN ({array_int:id_draft})' . ($check ? '
408
			AND  id_member = {int:id_member}' : ''),
409
		array(
410
			'id_draft' => $id_draft,
411
			'id_member' => empty($user_info['id']) ? -1 : $user_info['id'],
412
		)
413
	);
414
}
415
416
/**
417
 * Loads in a group of drafts for the user of a given type (0/posts, 1/pm's)
418
 * loads a specific draft for forum use if selected.
419
 * Used in the posting screens to allow draft selection
420
 * Will load a draft if selected is supplied via post
421
 *
422
 * @param int $member_id ID of the member to show drafts for
423
 * @param boolean|integer If $type is 1, this can be set to only load drafts for posts in the specific topic
424
 * @param int $draft_type The type of drafts to show - 0 for post drafts, 1 for PM drafts
425
 * @return boolean False if the drafts couldn't be loaded, nothing otherwise
0 ignored issues
show
Documentation introduced by
Should the return type not be false|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
426
 */
427
function ShowDrafts($member_id, $topic = false, $draft_type = 0)
428
{
429
	global $smcFunc, $scripturl, $context, $txt, $modSettings;
430
431
	// Permissions
432
	if (($draft_type === 0 && empty($context['drafts_save'])) || ($draft_type === 1 && empty($context['drafts_pm_save'])) || empty($member_id))
433
		return false;
434
435
	$context['drafts'] = array();
436
437
	// has a specific draft has been selected?  Load it up if there is not a message already in the editor
438
	if (isset($_REQUEST['id_draft']) && empty($_POST['subject']) && empty($_POST['message']))
439
		ReadDraft((int) $_REQUEST['id_draft'], $draft_type, true, true);
440
441
	// load the drafts this user has available
442
	$request = $smcFunc['db_query']('', '
443
		SELECT subject, poster_time, id_board, id_topic, id_draft
444
		FROM {db_prefix}user_drafts
445
		WHERE id_member = {int:id_member}' . ((!empty($topic) && empty($draft_type)) ? '
446
			AND id_topic = {int:id_topic}' : (!empty($topic) ? '
447
			AND id_reply = {int:id_topic}' : '')) . '
448
			AND type = {int:draft_type}' . (!empty($modSettings['drafts_keep_days']) ? '
449
			AND poster_time > {int:time}' : '') . '
450
		ORDER BY poster_time DESC',
451
		array(
452
			'id_member' => $member_id,
453
			'id_topic' => (int) $topic,
454
			'draft_type' => $draft_type,
455
			'time' => (!empty($modSettings['drafts_keep_days']) ? (time() - ($modSettings['drafts_keep_days'] * 86400)) : 0),
456
		)
457
	);
458
459
	// add them to the draft array for display
460
	while ($row = $smcFunc['db_fetch_assoc']($request))
461
	{
462
		if (empty($row['subject']))
463
			$row['subject'] = $txt['no_subject'];
464
465
		// Post drafts
466
		if ($draft_type === 0)
467
		{
468
			$tmp_subject = shorten_subject(stripslashes($row['subject']), 24);
469
			$context['drafts'][] = array(
470
				'subject' => censorText($tmp_subject),
471
				'poster_time' => timeformat($row['poster_time']),
472
				'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>',
473
			);
474
		}
475
		// PM drafts
476
		elseif ($draft_type === 1)
477
		{
478
			$tmp_subject = shorten_subject(stripslashes($row['subject']), 24);
479
			$context['drafts'][] = array(
480
				'subject' => censorText($tmp_subject),
481
				'poster_time' => timeformat($row['poster_time']),
482
				'link' => '<a href="' . $scripturl . '?action=pm;sa=send;id_draft=' . $row['id_draft'] . '">' . (!empty($row['subject']) ? $row['subject'] : $txt['drafts_none']) . '</a>',
483
			);
484
		}
485
	}
486
	$smcFunc['db_free_result']($request);
487
}
488
489
/**
490
 * Returns an xml response to an autosave ajax request
491
 * provides the id of the draft saved and the time it was saved
492
 *
493
 * @param int $id_draft
494
 */
495
function XmlDraft($id_draft)
496
{
497
	global $txt, $context;
498
499
	header('Content-Type: text/xml; charset=' . (empty($context['character_set']) ? 'ISO-8859-1' : $context['character_set']));
500
501
	echo '<?xml version="1.0" encoding="', $context['character_set'], '"?>
502
	<drafts>
503
		<draft id="', $id_draft, '"><![CDATA[', $txt['draft_saved_on'], ': ', timeformat($context['draft_saved_on']), ']]></draft>
504
	</drafts>';
505
506
	obExit(false);
507
}
508
509
/**
510
 * Show all drafts of a given type by the current user
511
 * Uses the showdraft template
512
 * Allows for the deleting and loading/editing of drafts
513
 *
514
 * @param int $memID
515
 * @param int $draft_type
516
 */
517
function showProfileDrafts($memID, $draft_type = 0)
518
{
519
	global $txt, $scripturl, $modSettings, $context, $smcFunc, $options;
520
521
	// Some initial context.
522
	$context['start'] = isset($_REQUEST['start']) ? (int) $_REQUEST['start'] : 0;
523
	$context['current_member'] = $memID;
524
525
	// If just deleting a draft, do it and then redirect back.
526
	if (!empty($_REQUEST['delete']))
527
	{
528
		checkSession('get');
529
		$id_delete = (int) $_REQUEST['delete'];
530
531
		$smcFunc['db_query']('', '
532
			DELETE FROM {db_prefix}user_drafts
533
			WHERE id_draft = {int:id_draft}
534
				AND id_member = {int:id_member}
535
				AND type = {int:draft_type}
536
			LIMIT 1',
537
			array(
538
				'id_draft' => $id_delete,
539
				'id_member' => $memID,
540
				'draft_type' => $draft_type,
541
			)
542
		);
543
544
		redirectexit('action=profile;u=' . $memID . ';area=showdrafts;start=' . $context['start']);
545
	}
546
547
	// Default to 10.
548 View Code Duplication
	if (empty($_REQUEST['viewscount']) || !is_numeric($_REQUEST['viewscount']))
549
		$_REQUEST['viewscount'] = 10;
550
551
	// Get the count of applicable drafts on the boards they can (still) see ...
552
	// @todo .. should we just let them see their drafts even if they have lost board access ?
0 ignored issues
show
Coding Style Best Practice introduced by
Comments for TODO tasks are often forgotten in the code; it might be better to use a dedicated issue tracker.
Loading history...
553
	$request = $smcFunc['db_query']('', '
554
		SELECT COUNT(id_draft)
555
		FROM {db_prefix}user_drafts AS ud
556
			INNER JOIN {db_prefix}boards AS b ON (b.id_board = ud.id_board AND {query_see_board})
557
		WHERE id_member = {int:id_member}
558
			AND type={int:draft_type}' . (!empty($modSettings['drafts_keep_days']) ? '
559
			AND poster_time > {int:time}' : ''),
560
		array(
561
			'id_member' => $memID,
562
			'draft_type' => $draft_type,
563
			'time' => (!empty($modSettings['drafts_keep_days']) ? (time() - ($modSettings['drafts_keep_days'] * 86400)) : 0),
564
		)
565
	);
566
	list ($msgCount) = $smcFunc['db_fetch_row']($request);
567
	$smcFunc['db_free_result']($request);
568
569
	$maxPerPage = empty($modSettings['disableCustomPerPage']) && !empty($options['messages_per_page']) ? $options['messages_per_page'] : $modSettings['defaultMaxMessages'];
570
	$maxIndex = $maxPerPage;
571
572
	// Make sure the starting place makes sense and construct our friend the page index.
573
	$context['page_index'] = constructPageIndex($scripturl . '?action=profile;u=' . $memID . ';area=showdrafts', $context['start'], $msgCount, $maxIndex);
574
	$context['current_page'] = $context['start'] / $maxIndex;
575
576
	// Reverse the query if we're past 50% of the pages for better performance.
577
	$start = $context['start'];
578
	$reverse = $_REQUEST['start'] > $msgCount / 2;
579 View Code Duplication
	if ($reverse)
580
	{
581
		$maxIndex = $msgCount < $context['start'] + $maxPerPage + 1 && $msgCount > $context['start'] ? $msgCount - $context['start'] : $maxPerPage;
582
		$start = $msgCount < $context['start'] + $maxPerPage + 1 || $msgCount < $context['start'] + $maxPerPage ? 0 : $msgCount - $context['start'] - $maxPerPage;
583
	}
584
585
	// Find this user's drafts for the boards they can access
586
	// @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
0 ignored issues
show
Coding Style Best Practice introduced by
Comments for TODO tasks are often forgotten in the code; it might be better to use a dedicated issue tracker.
Loading history...
587
	//           access to the board or if the topic moves to a board they can not see?
588
	$request = $smcFunc['db_query']('', '
589
		SELECT
590
			b.id_board, b.name AS bname,
591
			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
592
		FROM {db_prefix}user_drafts AS ud
593
			INNER JOIN {db_prefix}boards AS b ON (b.id_board = ud.id_board AND {query_see_board})
594
		WHERE ud.id_member = {int:current_member}
595
			AND type = {int:draft_type}' . (!empty($modSettings['drafts_keep_days']) ? '
596
			AND poster_time > {int:time}' : '') . '
597
		ORDER BY ud.id_draft ' . ($reverse ? 'ASC' : 'DESC') . '
598
		LIMIT {int:start}, {int:max}',
599
		array(
600
			'current_member' => $memID,
601
			'draft_type' => $draft_type,
602
			'time' => (!empty($modSettings['drafts_keep_days']) ? (time() - ($modSettings['drafts_keep_days'] * 86400)) : 0),
603
			'start' => $start,
604
			'max' => $maxIndex,
605
		)
606
	);
607
608
	// Start counting at the number of the first message displayed.
609
	$counter = $reverse ? $context['start'] + $maxIndex + 1 : $context['start'];
610
	$context['posts'] = array();
611
	while ($row = $smcFunc['db_fetch_assoc']($request))
612
	{
613
		// Censor....
614
		if (empty($row['body']))
615
			$row['body'] = '';
616
617
		$row['subject'] = $smcFunc['htmltrim']($row['subject']);
618
		if (empty($row['subject']))
619
			$row['subject'] = $txt['no_subject'];
620
621
		censorText($row['body']);
622
		censorText($row['subject']);
623
624
		// BBC-ilize the message.
625
		$row['body'] = parse_bbc($row['body'], $row['smileys_enabled'], 'draft' . $row['id_draft']);
626
627
		// And the array...
0 ignored issues
show
Unused Code Comprehensibility introduced by
43% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
628
		$context['drafts'][$counter += $reverse ? -1 : 1] = array(
629
			'body' => $row['body'],
630
			'counter' => $counter,
631
			'board' => array(
632
				'name' => $row['bname'],
633
				'id' => $row['id_board']
634
			),
635
			'topic' => array(
636
				'id' => $row['id_topic'],
637
				'link' => empty($row['id']) ? $row['subject'] : '<a href="' . $scripturl . '?topic=' . $row['id_topic'] . '.0">' . $row['subject'] . '</a>',
638
			),
639
			'subject' => $row['subject'],
640
			'time' => timeformat($row['poster_time']),
641
			'timestamp' => forum_time(true, $row['poster_time']),
642
			'icon' => $row['icon'],
643
			'id_draft' => $row['id_draft'],
644
			'locked' => $row['locked'],
645
			'sticky' => $row['is_sticky'],
646
		);
647
	}
648
	$smcFunc['db_free_result']($request);
649
650
	// If the drafts were retrieved in reverse order, get them right again.
651
	if ($reverse)
652
		$context['drafts'] = array_reverse($context['drafts'], true);
653
654
	// Menu tab
655
	$context[$context['profile_menu_name']]['tab_data'] = array(
656
		'title' => $txt['drafts_show'],
657
		'description' => $txt['drafts_show_desc'],
658
		'icon_class' => 'pm_icons inbox'
659
	);
660
	$context['sub_template'] = 'showDrafts';
661
}
662
663
/**
664
 * Show all PM drafts of the current user
665
 * Uses the showpmdraft template
666
 * Allows for the deleting and loading/editing of drafts
667
 *
668
 * @param int $memID
669
 */
670
function showPMDrafts($memID = -1)
671
{
672
	global $txt, $user_info, $scripturl, $modSettings, $context, $smcFunc, $options;
673
674
	// init
675
	$draft_type = 1;
676
677
	// If just deleting a draft, do it and then redirect back.
678
	if (!empty($_REQUEST['delete']))
679
	{
680
		checkSession('get');
681
		$id_delete = (int) $_REQUEST['delete'];
682
		$start = isset($_REQUEST['start']) ? (int) $_REQUEST['start'] : 0;
683
684
		$smcFunc['db_query']('', '
685
			DELETE FROM {db_prefix}user_drafts
686
			WHERE id_draft = {int:id_draft}
687
				AND id_member = {int:id_member}
688
				AND type = {int:draft_type}
689
			LIMIT 1',
690
			array(
691
				'id_draft' => $id_delete,
692
				'id_member' => $memID,
693
				'draft_type' => $draft_type,
694
			)
695
		);
696
697
		// now redirect back to the list
698
		redirectexit('action=pm;sa=showpmdrafts;start=' . $start);
699
	}
700
701
	// perhaps a draft was selected for editing? if so pass this off
702
	if (!empty($_REQUEST['id_draft']) && !empty($context['drafts_pm_save']) && $memID == $user_info['id'])
703
	{
704
		checkSession('get');
705
		$id_draft = (int) $_REQUEST['id_draft'];
706
		redirectexit('action=pm;sa=send;id_draft=' . $id_draft);
707
	}
708
709
	// Default to 10.
710 View Code Duplication
	if (empty($_REQUEST['viewscount']) || !is_numeric($_REQUEST['viewscount']))
711
		$_REQUEST['viewscount'] = 10;
712
713
	// Get the count of applicable drafts
714
	$request = $smcFunc['db_query']('', '
715
		SELECT COUNT(id_draft)
716
		FROM {db_prefix}user_drafts
717
		WHERE id_member = {int:id_member}
718
			AND type={int:draft_type}' . (!empty($modSettings['drafts_keep_days']) ? '
719
			AND poster_time > {int:time}' : ''),
720
		array(
721
			'id_member' => $memID,
722
			'draft_type' => $draft_type,
723
			'time' => (!empty($modSettings['drafts_keep_days']) ? (time() - ($modSettings['drafts_keep_days'] * 86400)) : 0),
724
		)
725
	);
726
	list ($msgCount) = $smcFunc['db_fetch_row']($request);
727
	$smcFunc['db_free_result']($request);
728
729
	$maxPerPage = empty($modSettings['disableCustomPerPage']) && !empty($options['messages_per_page']) ? $options['messages_per_page'] : $modSettings['defaultMaxMessages'];
730
	$maxIndex = $maxPerPage;
731
732
	// Make sure the starting place makes sense and construct our friend the page index.
733
	$context['page_index'] = constructPageIndex($scripturl . '?action=pm;sa=showpmdrafts', $context['start'], $msgCount, $maxIndex);
734
	$context['current_page'] = $context['start'] / $maxIndex;
735
736
	// Reverse the query if we're past 50% of the total for better performance.
737
	$start = $context['start'];
738
	$reverse = $_REQUEST['start'] > $msgCount / 2;
739 View Code Duplication
	if ($reverse)
740
	{
741
		$maxIndex = $msgCount < $context['start'] + $maxPerPage + 1 && $msgCount > $context['start'] ? $msgCount - $context['start'] : $maxPerPage;
742
		$start = $msgCount < $context['start'] + $maxPerPage + 1 || $msgCount < $context['start'] + $maxPerPage ? 0 : $msgCount - $context['start'] - $maxPerPage;
743
	}
744
745
	// Load in this user's PM drafts
746
	$request = $smcFunc['db_query']('', '
747
		SELECT
748
			ud.id_member, ud.id_draft, ud.body, ud.subject, ud.poster_time, ud.id_reply, ud.to_list
749
		FROM {db_prefix}user_drafts AS ud
750
		WHERE ud.id_member = {int:current_member}
751
			AND type = {int:draft_type}' . (!empty($modSettings['drafts_keep_days']) ? '
752
			AND poster_time > {int:time}' : '') . '
753
		ORDER BY ud.id_draft ' . ($reverse ? 'ASC' : 'DESC') . '
754
		LIMIT {int:start}, {int:max}',
755
		array(
756
			'current_member' => $memID,
757
			'draft_type' => $draft_type,
758
			'time' => (!empty($modSettings['drafts_keep_days']) ? (time() - ($modSettings['drafts_keep_days'] * 86400)) : 0),
759
			'start' => $start,
760
			'max' => $maxIndex,
761
		)
762
	);
763
764
	// Start counting at the number of the first message displayed.
765
	$counter = $reverse ? $context['start'] + $maxIndex + 1 : $context['start'];
766
	$context['posts'] = array();
767
	while ($row = $smcFunc['db_fetch_assoc']($request))
768
	{
769
		// Censor....
770
		if (empty($row['body']))
771
			$row['body'] = '';
772
773
		$row['subject'] = $smcFunc['htmltrim']($row['subject']);
774
		if (empty($row['subject']))
775
			$row['subject'] = $txt['no_subject'];
776
777
		censorText($row['body']);
778
		censorText($row['subject']);
779
780
		// BBC-ilize the message.
781
		$row['body'] = parse_bbc($row['body'], true, 'draft' . $row['id_draft']);
782
783
		// Have they provide who this will go to?
784
		$recipients = array(
785
			'to' => array(),
786
			'bcc' => array(),
787
		);
788
		$recipient_ids = (!empty($row['to_list'])) ? $smcFunc['json_decode']($row['to_list'], true) : array();
789
790
		// @todo ... this is a bit ugly since it runs an extra query for every message, do we want this?
0 ignored issues
show
Coding Style Best Practice introduced by
Comments for TODO tasks are often forgotten in the code; it might be better to use a dedicated issue tracker.
Loading history...
791
		// at least its only for draft PM's and only the user can see them ... so not heavily used .. still
792
		if (!empty($recipient_ids['to']) || !empty($recipient_ids['bcc']))
793
		{
794
			$recipient_ids['to'] = array_map('intval', $recipient_ids['to']);
795
			$recipient_ids['bcc'] = array_map('intval', $recipient_ids['bcc']);
796
			$allRecipients = array_merge($recipient_ids['to'], $recipient_ids['bcc']);
797
798
			$request_2 = $smcFunc['db_query']('', '
799
				SELECT id_member, real_name
800
				FROM {db_prefix}members
801
				WHERE id_member IN ({array_int:member_list})',
802
				array(
803
					'member_list' => $allRecipients,
804
				)
805
			);
806
			while ($result = $smcFunc['db_fetch_assoc']($request_2))
807
			{
808
				$recipientType = in_array($result['id_member'], $recipient_ids['bcc']) ? 'bcc' : 'to';
809
				$recipients[$recipientType][] = $result['real_name'];
810
			}
811
			$smcFunc['db_free_result']($request_2);
812
		}
813
814
		// Add the items to the array for template use
815
		$context['drafts'][$counter += $reverse ? -1 : 1] = array(
816
			'body' => $row['body'],
817
			'counter' => $counter,
818
			'subject' => $row['subject'],
819
			'time' => timeformat($row['poster_time']),
820
			'timestamp' => forum_time(true, $row['poster_time']),
821
			'id_draft' => $row['id_draft'],
822
			'recipients' => $recipients,
823
			'age' => floor((time() - $row['poster_time']) / 86400),
824
			'remaining' => (!empty($modSettings['drafts_keep_days']) ? floor($modSettings['drafts_keep_days'] - ((time() - $row['poster_time']) / 86400)) : 0),
825
		);
826
	}
827
	$smcFunc['db_free_result']($request);
828
829
	// if the drafts were retrieved in reverse order, then put them in the right order again.
830
	if ($reverse)
831
		$context['drafts'] = array_reverse($context['drafts'], true);
832
833
	// off to the template we go
834
	$context['page_title'] = $txt['drafts'];
835
	$context['sub_template'] = 'showPMDrafts';
836
	$context['linktree'][] = array(
837
		'url' => $scripturl . '?action=pm;sa=showpmdrafts',
838
		'name' => $txt['drafts'],
839
	);
840
}
841
842
?>