! Reworked attachment permissions; now separate permissions to view, upload and delete attachments. ! Added inline attachment deletes [Feature 540]
gruffen

gruffen commited on 2011-04-22 18:36:13
Showing 12 changed files, with 160 additions and 13 deletions.

... ...
@@ -12,6 +12,27 @@
12 12
 			<add><![CDATA[
13 13
 	elseif (!empty($_REQUEST['ticket']))
14 14
 	{
15
+		$_REQUEST['ticket'] = (int) $_REQUEST['ticket'];
16
+		// First we check that we can see said ticket and figure out what department we're in.
17
+		$request = shd_db_query('', '
18
+			SELECT hdt.id_dept
19
+			FROM {db_prefix}helpdesk_tickets AS hdt
20
+			WHERE id_ticket = {int:ticket}
21
+				AND {query_see_ticket}',
22
+			array(
23
+				'ticket' => $_REQUEST['ticket'],
24
+			)
25
+		);
26
+
27
+		// If there's a row, we need to process it and then issue the follow on query. If not, fall through to the next cut-off point, outside of this edit.
28
+		if ($smcFunc['db_num_rows']($request) != 0)
29
+		{
30
+			list($dept) = $smcFunc['db_fetch_row']($request);
31
+			$smcFunc['db_free_result']($request);
32
+
33
+			// Now check their permission. If they don't have permission to view in this department, bye.
34
+			shd_is_allowed_to('shd_view_attachment', $dept);
35
+			
15 36
 			// Make sure the attachment is on this ticket, note right now we're forcing it to be "approved"
16 37
 			$request = shd_db_query('', '
17 38
 				SELECT a.id_folder, a.filename, a.file_hash, a.fileext, a.id_attach, a.attachment_type, a.mime_type, 1 AS approved, hdtr.id_member
... ...
@@ -19,8 +40,7 @@
19 40
 					INNER JOIN {db_prefix}helpdesk_attachments AS hda ON (a.id_attach = hda.id_attach)
20 41
 					INNER JOIN {db_prefix}helpdesk_ticket_replies AS hdtr ON (hda.id_msg = hdtr.id_msg)
21 42
 					INNER JOIN {db_prefix}helpdesk_tickets AS hdt ON (hdtr.id_ticket = hdt.id_ticket)
22
-			WHERE {query_see_ticket}
23
-				AND a.id_attach = {int:attach}
43
+				WHERE a.id_attach = {int:attach}
24 44
 					AND hdt.id_ticket = {int:ticket}
25 45
 				LIMIT 1',
26 46
 				array(
... ...
@@ -28,6 +48,7 @@
28 48
 					'ticket' => (int) $_REQUEST['ticket'],
29 49
 				)
30 50
 			);
51
+		}
31 52
 	}]]></add>
32 53
 		</operation>
33 54
 	</file>
... ...
@@ -155,6 +155,7 @@ $txt['error_invalid_fields'] = 'The following fields have values that cannot be
155 155
 $txt['error_missing_fields'] = 'The following fields were not completed and need to be: %1$s';
156 156
 $txt['shd_cannot_move_dept'] = 'You cannot move this ticket, there is nowhere to move it to.';
157 157
 $txt['shd_no_perm_move_dept'] = 'You are not permitted to move this ticket to another department.';
158
+$txt['cannot_shd_delete_attachment'] = 'You are not permitted to delete attachments.';
158 159
 
159 160
 // The main Helpdesk.
160 161
 $txt['shd_home'] = 'Helpdesk'; // separate string in case someone wants to change it independently of the main/admin menu
... ...
@@ -248,6 +249,8 @@ $txt['shd_ticket_unassign'] = 'Un-Assign';
248 249
 $txt['shd_ticket_delete'] = 'Delete';
249 250
 $txt['shd_delete_confirm'] = 'Are you sure you want to delete this ticket? If deleted, this ticket will be moved to recycling bin.';
250 251
 $txt['shd_delete_reply_confirm'] = 'Are you sure you want to delete this reply? If deleted, this reply will be moved to the recycling bin.';
252
+$txt['shd_delete_attach_confirm'] = 'Are you sure you want to delete this attachment? (This cannot be undone!)';
253
+$txt['shd_delete_attach'] = 'Delete this attachment';
251 254
 $txt['shd_ticket_restore'] = 'Restore';
252 255
 $txt['shd_delete_permanently'] = 'Delete permanently';
253 256
 $txt['shd_delete_permanently_confirm'] = 'Are you sure you want to permanently delete this ticket? This CANNOT be undone!';
... ...
@@ -190,8 +190,12 @@ $txt['permissionname_shd_restore_reply_any'] = 'Any replies';
190 190
 
191 191
 //! @name Attachments
192 192
 //@{
193
+$txt['permissionname_shd_view_attachment'] = 'View attachments';
194
+$txt['permissionhelp_shd_view_attachment'] = 'This permission allows a user to view the attachments on tickets.';
193 195
 $txt['permissionname_shd_post_attachment'] = 'Post attachments';
194 196
 $txt['permissionhelp_shd_post_attachment'] = 'This permission allows a user to post attachments to tickets.';
197
+$txt['permissionname_shd_delete_attachment'] = 'Delete attachments';
198
+$txt['permissionhelp_shd_delete_attachment'] = 'This permission allows a user to remove attachments previously added to tickets.';
195 199
 //@}
196 200
 
197 201
 //! @name Posting proxy tickets (i.e. posting new ticket on behalf of someone else)
... ...
@@ -299,6 +303,7 @@ $txt['shd_admin_permissions_homedesc'] = 'This area allows you to configure the
299 303
 $txt['shd_permgroup_general'] = 'General helpdesk permissions';
300 304
 $txt['shd_permgroup_posting'] = 'Ticket/reply posting';
301 305
 $txt['shd_permgroup_ticketactions'] = 'Ticket actions';
306
+$txt['shd_permgroup_attachments'] = 'Attachments to tickets and replies';
302 307
 $txt['shd_permgroup_relationships'] = 'Relationships between tickets';
303 308
 $txt['shd_permgroup_deletion'] = 'The recycle bin and ticket/reply deletion';
304 309
 $txt['shd_permgroup_moderation'] = 'Ticket moderation and management';
... ...
@@ -307,6 +312,7 @@ $txt['shd_permgroup_profile'] = 'User profiles and options';
307 312
 $txt['shd_permgroup_short_general'] = 'General';
308 313
 $txt['shd_permgroup_short_posting'] = 'Posting';
309 314
 $txt['shd_permgroup_short_ticketactions'] = 'Actions';
315
+$txt['shd_permgroup_short_attachments'] = 'Attachments';
310 316
 $txt['shd_permgroup_short_relationships'] = 'Relationships';
311 317
 $txt['shd_permgroup_short_deletion'] = 'Delete/Restore';
312 318
 $txt['shd_permgroup_short_moderation'] = 'Moderation';
... ...
@@ -431,6 +431,64 @@ function shd_perma_delete()
431 431
 		fatal_lang_error('shd_no_ticket');
432 432
 }
433 433
 
434
+// Delete a given attachment from the one-click interface.
435
+function shd_attach_delete()
436
+{
437
+	global $smcFunc, $user_info, $context, $sourcedir;
438
+
439
+	if (empty($context['ticket_id']) || empty($_GET['attach']) || (int) $_GET['attach'] == 0)
440
+		fatal_lang_error('no_access', false);
441
+
442
+	$_GET['attach'] = (int) $_GET['attach'];
443
+
444
+	// Well, we have a ticket id. Let's figure out what department we're in so we can check permissions.
445
+	$query = shd_db_query('', '
446
+		SELECT hdt.id_dept, a.filename, hda.id_msg, hdt.subject
447
+		FROM {db_prefix}attachments AS a
448
+			INNER JOIN {db_prefix}helpdesk_attachments AS hda ON (hda.id_attach = a.id_attach)
449
+			INNER JOIN {db_prefix}helpdesk_tickets AS hdt ON (hda.id_ticket = hdt.id_ticket)
450
+		WHERE {query_see_ticket}
451
+			AND hda.id_ticket = {int:ticket}
452
+			AND hda.id_attach = {int:attach}
453
+			AND a.attachment_type = 0',
454
+		array(
455
+			'attach' => $_GET['attach'],
456
+			'ticket' => $context['ticket_id'],
457
+		)
458
+	);
459
+	if ($smcFunc['db_num_rows']($query) == 0)
460
+	{
461
+		$smcFunc['db_free_result']($query);
462
+		fatal_lang_error('no_access');
463
+	}
464
+
465
+	list($dept, $filename, $id_msg, $subject) = $smcFunc['db_fetch_row']($query);
466
+	$smcFunc['db_free_result']($query);
467
+
468
+	shd_is_allowed_to('shd_delete_attachment', $dept);
469
+
470
+	// So, we can delete the attachment. We already know it exists, we know we have permission.
471
+	$log_params = array(
472
+		'subject' => $subject,
473
+		'ticket' => $context['ticket_id'],
474
+		'msg' => $id_msg,
475
+		'att_removed' => array(htmlspecialchars($filename)),
476
+	);
477
+
478
+	shd_log_action('editticket', $log_params);
479
+
480
+	// Now you can delete
481
+	require_once($sourcedir . '/ManageAttachments.php');
482
+	$attachmentQuery = array(
483
+		'attachment_type' => 0,
484
+		'id_msg' => 0,
485
+		'id_attach' => array($_GET['attach']),
486
+	);
487
+	removeAttachments($attachmentQuery);
488
+
489
+	redirectexit('action=helpdesk;sa=ticket;ticket=' . $context['ticket_id']);
490
+}
491
+
434 492
 // Restore the given ticket from the recycling bin.
435 493
 function shd_ticket_restore()
436 494
 {
... ...
@@ -904,6 +903,9 @@ function shd_display_load_attachments()
904 903
 
905 904
 	$context['ticket_attach'][$modSettings['shd_attachments_mode']] = array();
906 905
 
906
+	if (!shd_allowed_to('shd_view_attachment', $context['ticket']['dept']))
907
+		return;
908
+
907 909
 	if ($modSettings['shd_attachments_mode'] == 'ticket')
908 910
 	{
909 911
 		$query = shd_db_query('', '
... ...
@@ -973,6 +975,7 @@ function shd_attachment_info($attach_info)
973 975
 	global $scripturl, $context, $modSettings, $txt, $sourcedir, $smcFunc;
974 976
 
975 977
 	$filename = preg_replace('~&amp;#(\\d{1,7}|x[0-9a-fA-F]{1,6});~', '&#\\1;', htmlspecialchars($attach_info['filename']));
978
+	$deleteable = shd_allowed_to('shd_delete_attachment', $context['ticket']['dept']);
976 979
 
977 980
 	$attach = array(
978 981
 		'id' => $attach_info['id_attach'],
... ...
@@ -982,6 +985,7 @@ function shd_attachment_info($attach_info)
982 985
 		'href' => $scripturl . '?action=dlattach;ticket=' . $context['ticket_id'] . '.0;attach=' . $attach_info['id_attach'],
983 986
 		'link' => shd_attach_icon($filename) . '&nbsp;<a href="' . $scripturl . '?action=dlattach;ticket=' . $context['ticket_id'] . '.0;attach=' . $attach_info['id_attach'] . '">' . htmlspecialchars($attach_info['filename']) . '</a>',
984 987
 		'is_image' => !empty($modSettings['attachmentShowImages']) && !empty($attach_info['width']) && !empty($attach_info['height']),
988
+		'can_delete' => $deleteable,
985 989
 	);
986 990
 
987 991
 	if ($attach['is_image'])
... ...
@@ -657,6 +657,8 @@ function shd_save_ticket()
657 657
 			shd_modify_ticket_post($msgOptions, $ticketOptions, $posterOptions);
658 658
 
659 659
 			// OK, did we get any custom fields back?
660
+			if (!empty($context['custom_fields_updated']))
661
+			{
660 662
 				foreach ($context['custom_fields_updated'] as $field)
661 663
 				{
662 664
 					if ($field['oldvalue'] == $field['newvalue'])
... ...
@@ -666,6 +668,7 @@ function shd_save_ticket()
666 668
 					$field['subject'] = $ticketinfo['subject'];
667 669
 					shd_log_action($action, $field);
668 670
 				}
671
+			}
669 672
 			shd_clear_active_tickets($ticketinfo['id_member_started']);
670 673
 		}
671 674
 		shd_done_posting();
... ...
@@ -1524,6 +1527,7 @@ function shd_load_attachments()
1524 1527
 		$context['current_attachments'] = array();
1525 1528
 
1526 1529
 	$context['ticket_attach'][$modSettings['shd_attachments_mode']] = array();
1530
+	$deleteable = shd_allowed_to('shd_delete_attachment', $context['ticket_form']['dept']);
1527 1531
 
1528 1532
 	// Get existing attachments
1529 1533
 	$query = shd_db_query('', '
... ...
@@ -1544,6 +1548,7 @@ function shd_load_attachments()
1544 1548
 		$context['current_attachments'][] = array(
1545 1549
 			'id' => $row['id_attach'],
1546 1550
 			'name' => preg_replace('~&amp;#(\\d{1,7}|x[0-9a-fA-F]{1,6});~', '&#\\1;', htmlspecialchars($row['filename'])),
1551
+			'can_delete' => $deleteable,
1547 1552
 		);
1548 1553
 
1549 1554
 	$smcFunc['db_free_result']($query);
... ...
@@ -1747,6 +1752,8 @@ function shd_handle_attachments()
1747 1752
 	// Check if they are trying to delete any current attachments....
1748 1753
 	if (isset($_POST['attach_del']))
1749 1754
 	{
1755
+		shd_is_allowed_to('shd_delete_attachment', $context['ticket_form']['dept']);
1756
+
1750 1757
 		$del_temp = array();
1751 1758
 		foreach ($_POST['attach_del'] as $i => $dummy)
1752 1759
 			$del_temp[$i] = (int) $dummy;
... ...
@@ -116,6 +116,7 @@ function shd_main()
116 116
 		'permadelete' => array('SimpleDesk-Delete.php', 'shd_perma_delete'),
117 117
 		'deleteticket' => array('SimpleDesk-Delete.php', 'shd_ticket_delete'),
118 118
 		'deletereply' => array('SimpleDesk-Delete.php', 'shd_reply_delete'),
119
+		'deleteattach' => array('SimpleDesk-Delete.php', 'shd_attach_delete'),
119 120
 		'restoreticket' => array('SimpleDesk-Delete.php', 'shd_ticket_restore'),
120 121
 		'restorereply' => array('SimpleDesk-Delete.php', 'shd_reply_restore'),
121 122
 		'emaillog' => array('SimpleDesk-Notifications.php', 'shd_notify_popup'),
... ...
@@ -42,9 +42,10 @@ function shd_load_all_permission_sets()
42 42
 			'general' => 'status.png',
43 43
 			'posting' => 'log_newticket.png',
44 44
 			'deletion' => 'log_delete.png',
45
-			'profile' => 'profile.png',
45
+			'attachments' => 'attachments.png',
46 46
 		),
47 47
 		array(
48
+			'profile' => 'profile.png',
48 49
 			'ticketactions' => 'assign.png',
49 50
 			'relationships' => 'relationships.png',
50 51
 			'moderation' => 'modification.png',
... ...
@@ -65,7 +66,6 @@ function shd_load_all_permission_sets()
65 66
 		'shd_edit_ticket' => array(true, 'posting', 'log_editticket.png'),
66 67
 		'shd_reply_ticket' => array(true, 'posting', 'log_newreply.png'),
67 68
 		'shd_edit_reply' => array(true, 'posting', 'log_editreply.png'),
68
-		'shd_post_attachment' => array(false, 'posting', 'attachments.png'),
69 69
 		'shd_post_proxy' => array(false, 'posting', 'proxy.png'),
70 70
 		'shd_override_cf' => array(false, 'posting', 'custom_fields.png'),
71 71
 
... ...
@@ -77,6 +77,10 @@ function shd_load_all_permission_sets()
77 77
 		'shd_alter_privacy' => array(true, 'ticketactions', 'log_markprivate.png'),
78 78
 		'shd_assign_ticket' => array(true, 'ticketactions', 'log_assign.png'),
79 79
 
80
+		'shd_view_attachment' => array(false, 'attachments', 'attachments.png'),
81
+		'shd_post_attachment' => array(false, 'attachments', 'attachments_add.png'),
82
+		'shd_delete_attachment' => array(false, 'attachments', 'attachments_delete.png'),
83
+
80 84
 		'shd_view_profile' => array(true, 'profile', 'profile.png'),
81 85
 		'shd_view_profile_log' => array(true, 'profile', 'log.png'),
82 86
 		'shd_view_preferences' => array(true, 'profile', 'preferences.png'),
... ...
@@ -133,6 +137,7 @@ function shd_load_role_templates()
133 137
 				'shd_edit_ticket_own' => ROLEPERM_ALLOW,
134 138
 				'shd_reply_ticket_own' => ROLEPERM_ALLOW,
135 139
 				'shd_edit_reply_own' => ROLEPERM_ALLOW,
140
+				'shd_view_attachment' => ROLEPERM_ALLOW,
136 141
 				'shd_post_attachment' => ROLEPERM_ALLOW,
137 142
 				'shd_resolve_ticket_own' => ROLEPERM_ALLOW,
138 143
 				'shd_unresolve_ticket_own' => ROLEPERM_ALLOW,
... ...
@@ -159,8 +164,9 @@ function shd_load_role_templates()
159 164
 				'shd_edit_ticket_any' => ROLEPERM_ALLOW,
160 165
 				'shd_reply_ticket_any' => ROLEPERM_ALLOW,
161 166
 				'shd_edit_reply_any' => ROLEPERM_ALLOW,
162
-				'shd_post_attachment' => ROLEPERM_ALLOW,
163 167
 				'shd_post_proxy' => ROLEPERM_ALLOW,
168
+				'shd_view_attachment' => ROLEPERM_ALLOW,
169
+				'shd_post_attachment' => ROLEPERM_ALLOW,
164 170
 				'shd_resolve_ticket_any' => ROLEPERM_ALLOW,
165 171
 				'shd_unresolve_ticket_any' => ROLEPERM_ALLOW,
166 172
 				'shd_view_ticket_logs_any' => ROLEPERM_ALLOW,
... ...
@@ -200,9 +206,11 @@ function shd_load_role_templates()
200 206
 				'shd_edit_ticket_any' => ROLEPERM_ALLOW,
201 207
 				'shd_reply_ticket_any' => ROLEPERM_ALLOW,
202 208
 				'shd_edit_reply_any' => ROLEPERM_ALLOW,
203
-				'shd_post_attachment' => ROLEPERM_ALLOW,
204 209
 				'shd_post_proxy' => ROLEPERM_ALLOW,
205 210
 				'shd_override_cf' => ROLEPERM_ALLOW,
211
+				'shd_view_attachment' => ROLEPERM_ALLOW,
212
+				'shd_post_attachment' => ROLEPERM_ALLOW,
213
+				'shd_delete_attachment' => ROLEPERM_ALLOW,
206 214
 				'shd_resolve_ticket_any' => ROLEPERM_ALLOW,
207 215
 				'shd_unresolve_ticket_any' => ROLEPERM_ALLOW,
208 216
 				'shd_view_ticket_logs_any' => ROLEPERM_ALLOW,
... ...
@@ -357,14 +357,16 @@ function template_ticket_leftcolumn()
357 357
 */
358 358
 function template_viewticketattach()
359 359
 {
360
-	global $context, $settings, $txt;
360
+	global $context, $settings, $txt, $scripturl;
361
+
362
+	$remove_txt = JavaScriptEscape($txt['shd_delete_attach_confirm']);
361 363
 
362 364
 	if (!empty($context['ticket_attach']['ticket']))
363 365
 	{
364 366
 		echo '	<div class="tborder">
365 367
 					<div class="title_bar grid_header">
366 368
 						<h3 class="titlebg">
367
-							<img src="', $settings['default_images_url'], '/simpledesk/attachments.png" alt="x" />', $txt['shd_ticket_attachments'], ' (', count($context['ticket_attach']['ticket']), ')
369
+							<img src="', $settings['default_images_url'], '/simpledesk/attachments.png" alt="" />', $txt['shd_ticket_attachments'], ' (', count($context['ticket_attach']['ticket']), ')
368 370
 						</h3>
369 371
 					</div>
370 372
 					<div class="windowbg2">
... ...
@@ -388,7 +390,13 @@ function template_viewticketattach()
388 390
 			echo '
389 391
 								<strong>', $attachment['link'], '</strong>
390 392
 								<span class="smalltext">
391
-									(', $attachment['size'], ')
393
+									(', $attachment['size'], ')';
394
+
395
+			if (!empty($attachment['can_delete']))
396
+				echo '
397
+									<a href="', $scripturl, '?action=helpdesk;sa=deleteattach;ticket=', $context['ticket_id'], ';attach=', $attachment['id'], '" onclick="return confirm(', $remove_txt, ');"><img src="', $settings['default_images_url'], '/simpledesk/delete.png" title="', $txt['shd_delete_attach'], '" alt="', $txt['shd_delete_attach'], '" /></a>';
398
+
399
+			echo '
392 400
 								</span>
393 401
 							</div>';
394 402
 		}
... ...
@@ -537,7 +545,9 @@ function template_quickreply()
537 545
 // Arantor: I swear I spent more time farting around with this trying to make it not look like crap than I did the rest of the thumbnail code.
538 546
 function template_inline_attachments($msg)
539 547
 {
540
-	global $context, $txt;
548
+	global $context, $txt, $scripturl, $settings;
549
+
550
+	$remove_txt = JavaScriptEscape($txt['shd_delete_attach_confirm']);
541 551
 
542 552
 	if (!empty($context['ticket_attach']['reply'][$msg]))
543 553
 	{
... ...
@@ -576,7 +586,14 @@ function template_inline_attachments($msg)
576 586
 			}
577 587
 
578 588
 			echo '
579
-										', $attachment['link'], '
589
+										', $attachment['link'];
590
+
591
+
592
+			if (!empty($attachment['can_delete']))
593
+				echo '
594
+									<a href="', $scripturl, '?action=helpdesk;sa=deleteattach;ticket=', $context['ticket_id'], ';attach=', $attachment['id'], '" onclick="return confirm(', $remove_txt, ');"><img src="', $settings['default_images_url'], '/simpledesk/delete.png" title="', $txt['shd_delete_attach'], '" alt="', $txt['shd_delete_attach'], '" /></a>';
595
+
596
+			echo '
580 597
 									</td>';
581 598
 
582 599
 			$count++;
... ...
@@ -540,7 +540,7 @@ function template_preview()
540 540
 
541 541
 function template_ticket_additional_options()
542 542
 {
543
-	global $context, $options, $txt, $modSettings;
543
+	global $context, $options, $txt, $modSettings, $settings;
544 544
 
545 545
 	echo '
546 546
 					<div class="information shd_reply_attachments" id="shd_attach_container"', !empty($context['shd_display']) ? ' style="display:none;"' : '', '>
... ...
@@ -566,7 +566,20 @@ function template_ticket_additional_options()
566 566
 						<dl id="postAttachment">
567 567
 							<dt>
568 568
 								', $txt['attached'], ':
569
-							</dt>
569
+							</dt>';
570
+
571
+		$can_delete = false;
572
+		foreach ($context['current_attachments'] as $attachment)
573
+		{
574
+			if (!empty($attachment['can_delete']))
575
+				$can_delete = true;
576
+			break;
577
+		}
578
+
579
+		if ($can_delete)
580
+		{
581
+
582
+			echo '
570 583
 							<dd class="smalltext">
571 584
 								<input type="hidden" name="attach_del[]" value="0" />
572 585
 								', $txt['uncheck_unwatchd_attach'], ':
... ...
@@ -576,6 +589,14 @@ function template_ticket_additional_options()
576 589
 							<dd class="smalltext">
577 590
 								<label for="attachment_', $attachment['id'], '"><input type="checkbox" id="attachment_', $attachment['id'], '" name="attach_del[]" value="', $attachment['id'], '"', empty($attachment['unchecked']) ? ' checked="checked"' : '', ' class="input_check" onclick="javascript:oAttach.checkActive();" /> ', $attachment['name'], '</label>
578 591
 							</dd>';
592
+		}
593
+		else
594
+		{
595
+			foreach ($context['current_attachments'] as $attachment)
596
+				echo '
597
+							<dd class="smalltext">', $attachment['name'], '</dd>';
598
+		}
599
+
579 600
 		echo '
580 601
 						</dl>';
581 602
 	}
582 603