PluginProbe
SupportCandy – AI Customer Support Ticket System & Live Chatbot Agent / 3.4.1
SupportCandy – AI Customer Support Ticket System & Live Chatbot Agent v3.4.1
3.5.4 3.5.3 3.5.2 3.5.1 3.4.9 3.5.0 3.4.8 3.4.7 trunk 2.3.1 3.3.6 3.3.7 3.3.8 3.3.9 3.4.0 3.4.1 3.4.2 3.4.3 3.4.4 3.4.5 3.4.6
supportcandy / includes / models / class-wpsc-attachment.php

class-wpsc-attachment.php in SupportCandy – AI Customer Support Ticket System & Live Chatbot Agent 3.4.1, at includes/models/class-wpsc-attachment.php

1,290 lines 39.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 if ( ! defined( 'ABSPATH' ) ) {
3 exit; // Exit if accessed directly!
4 }
5
6 if ( ! class_exists( 'WPSC_Attachment' ) ) :
7
8 final class WPSC_Attachment {
9
10 /**
11 * Object data in key => val pair.
12 *
13 * @var array
14 */
15 private $data = array();
16
17 /**
18 * Set whether or not current object properties modified
19 *
20 * @var boolean
21 */
22 private $is_modified = false;
23
24 /**
25 * Schema for this model
26 *
27 * @var array
28 */
29 public static $schema = array();
30
31 /**
32 * Prevent fields to modify
33 *
34 * @var array
35 */
36 public static $prevent_modify = array();
37
38 /**
39 * Catche for search results for ticket list of attachments.
40 *
41 * @var array
42 */
43 private static $tl_search_items;
44
45 /**
46 * Initialize this class
47 *
48 * @return void
49 */
50 public static function init() {
51
52 // Apply schema for this model.
53 add_action( 'init', array( __CLASS__, 'apply_schema' ), 2 );
54
55 // Get object of this class.
56 add_filter( 'wpsc_load_ref_classes', array( __CLASS__, 'load_ref_class' ) );
57
58 // File upload.
59 add_action( 'wp_ajax_wpsc_file_upload', array( __CLASS__, 'file_upload' ) );
60 add_action( 'wp_ajax_nopriv_wpsc_file_upload', array( __CLASS__, 'file_upload' ) );
61
62 // Custom image in tinymce.
63 add_action( 'wp_ajax_wpsc_add_custom_image_tinymce', array( __CLASS__, 'add_custom_image_tinymce' ) );
64 add_action( 'wp_ajax_nopriv_wpsc_add_custom_image_tinymce', array( __CLASS__, 'add_custom_image_tinymce' ) );
65 add_action( 'wp_ajax_wpsc_edit_custom_image_tinymce', array( __CLASS__, 'edit_custom_image_tinymce' ) );
66 add_action( 'wp_ajax_nopriv_wpsc_edit_custom_image_tinymce', array( __CLASS__, 'edit_custom_image_tinymce' ) );
67
68 // Check download file.
69 add_action( 'init', array( __CLASS__, 'check_download_file' ), 100 );
70
71 // Upload tinymce image.
72 add_action( 'wp_ajax_wpsc_tinymce_upload_file', array( __CLASS__, 'tinymce_upload_file' ) );
73 add_action( 'wp_ajax_nopriv_wpsc_tinymce_upload_file', array( __CLASS__, 'tinymce_upload_file' ) );
74
75 // Attachment garbage collector.
76 add_action( 'wpsc_attach_garbage_collector', array( __CLASS__, 'garbage_collector' ) );
77 }
78
79 /**
80 * Change file upload path
81 *
82 * @param array $param - file upload array.
83 * @return array
84 */
85 public static function wpsc_upload_dir( $param ) {
86
87 $today = new DateTime();
88 $file_path = $param['basedir'] . '/wpsc/' . $today->format( 'Y' ) . '/' . $today->format( 'm' );
89 if ( ! file_exists( $file_path ) ) {
90 mkdir( $file_path, 0755, true );
91 }
92
93 $param['path'] = $file_path;
94
95 return $param;
96 }
97
98 /**
99 * Custom upload mime types
100 *
101 * @param array $existing_mimes - file upload array.
102 * @return array
103 */
104 public static function wpsc_custom_upload_mimes( $existing_mimes ) {
105
106 $settings = get_option( 'wpsc-gs-file-attachments', array() );
107
108 // Merge allowed-file-ext-mimes first.
109 if ( isset( $settings['allowed-file-ext-mimes'] ) ) {
110 $existing_mimes = array_merge( $existing_mimes, $settings['allowed-file-ext-mimes'] );
111 }
112
113 // Then apply mime-exceptions to give them priority.
114 if ( isset( $settings['mime-exceptions'] ) && is_array( $settings['mime-exceptions'] ) ) {
115 foreach ( $settings['mime-exceptions'] as $type ) {
116 $type_array = explode( ':', $type );
117 if ( count( $type_array ) === 2 ) {
118 $existing_mimes[ $type_array[0] ] = $type_array[1];
119 }
120 }
121 }
122
123 return $existing_mimes;
124 }
125
126 /**
127 * Apply schema for this model
128 *
129 * @return void
130 */
131 public static function apply_schema() {
132
133 $schema = array(
134 'id' => array(
135 'has_ref' => false,
136 'ref_class' => '',
137 'has_multiple_val' => false,
138 ),
139 'name' => array(
140 'has_ref' => false,
141 'ref_class' => '',
142 'has_multiple_val' => false,
143 ),
144 'file_path' => array(
145 'has_ref' => false,
146 'ref_class' => '',
147 'has_multiple_val' => false,
148 ),
149 'is_image' => array(
150 'has_ref' => false,
151 'ref_class' => '',
152 'has_multiple_val' => false,
153 ),
154 'is_active' => array(
155 'has_ref' => false,
156 'ref_class' => '',
157 'has_multiple_val' => false,
158 ),
159 'is_uploaded' => array(
160 'has_ref' => false,
161 'ref_class' => '',
162 'has_multiple_val' => false,
163 ),
164 'date_created' => array(
165 'has_ref' => true,
166 'ref_class' => 'datetime',
167 'has_multiple_val' => false,
168 ),
169 'source' => array(
170 'has_ref' => false,
171 'ref_class' => '',
172 'has_multiple_val' => false,
173 ),
174 'source_id' => array(
175 'has_ref' => false,
176 'ref_class' => '',
177 'has_multiple_val' => false,
178 ),
179 'ticket_id' => array(
180 'has_ref' => false,
181 'ref_class' => '',
182 'has_multiple_val' => false,
183 ),
184 'customer_id' => array(
185 'has_ref' => false,
186 'ref_class' => '',
187 'has_multiple_val' => false,
188 ),
189 );
190 self::$schema = apply_filters( 'wpsc_attachment_schema', $schema );
191
192 // Prevent modify.
193 $prevent_modify = array( 'id' );
194 self::$prevent_modify = apply_filters( 'wpsc_attachment_prevent_modify', $prevent_modify );
195 }
196
197 /**
198 * Model constructor
199 *
200 * @param int $id - Optional. Data record id to retrive object for.
201 */
202 public function __construct( $id = 0 ) {
203
204 global $wpdb;
205
206 $id = intval( $id );
207
208 if ( $id > 0 ) {
209
210 $attachment = $wpdb->get_row( "SELECT * FROM {$wpdb->prefix}psmsc_attachments WHERE id = " . $id, ARRAY_A );
211 if ( ! is_array( $attachment ) ) {
212 return;
213 }
214
215 foreach ( $attachment as $key => $val ) {
216 $this->data[ $key ] = $val !== null ? $val : '';
217 }
218 }
219 }
220
221 /**
222 * Convert object into an array
223 *
224 * @return array
225 */
226 public function to_array() {
227
228 return $this->data;
229 }
230
231 /**
232 * Magic get function to use with object arrow function
233 *
234 * @param string $var_name - variable name.
235 * @return mixed
236 */
237 public function __get( $var_name ) {
238
239 if ( ! isset( $this->data[ $var_name ] ) ||
240 $this->data[ $var_name ] == null ||
241 $this->data[ $var_name ] == ''
242 ) {
243 return self::$schema[ $var_name ]['has_multiple_val'] ? array() : '';
244 }
245
246 if ( self::$schema[ $var_name ]['has_multiple_val'] ) {
247
248 $response = array();
249 $values = $this->data[ $var_name ] ? explode( '|', $this->data[ $var_name ] ) : array();
250 foreach ( $values as $val ) {
251 $response[] = self::$schema[ $var_name ]['has_ref'] ?
252 WPSC_Functions::get_object( self::$schema[ $var_name ]['ref_class'], $val ) :
253 $val;
254 }
255 return $response;
256
257 } else {
258
259 return self::$schema[ $var_name ]['has_ref'] && $this->data[ $var_name ] ?
260 WPSC_Functions::get_object( self::$schema[ $var_name ]['ref_class'], $this->data[ $var_name ] ) :
261 $this->data[ $var_name ];
262 }
263 }
264
265 /**
266 * Magic function to use setting object field with arrow function
267 *
268 * @param string $var_name - (Required) property slug.
269 * @param mixed $value - (Required) value to set for a property.
270 * @return void
271 */
272 public function __set( $var_name, $value ) {
273
274 if (
275 ! isset( $this->data[ $var_name ] ) ||
276 in_array( $var_name, self::$prevent_modify )
277 ) {
278 return;
279 }
280
281 $data_val = '';
282 if ( self::$schema[ $var_name ]['has_multiple_val'] ) {
283
284 $data_vals = array_map(
285 fn( $val ) => is_object( $val ) ? WPSC_Functions::set_object( self::$schema[ $var_name ]['ref_class'], $val ) : $val,
286 $value
287 );
288
289 $data_val = $data_vals ? implode( '|', $data_vals ) : '';
290
291 } else {
292
293 $data_val = is_object( $value ) ? WPSC_Functions::set_object( self::$schema[ $var_name ]['ref_class'], $value ) : $value;
294 }
295
296 if ( $this->data[ $var_name ] == $data_val ) {
297 return;
298 }
299
300 $this->data[ $var_name ] = $data_val;
301 $this->is_modified = true;
302 }
303
304 /**
305 * Save changes made
306 *
307 * @return boolean
308 */
309 public function save() {
310
311 global $wpdb;
312
313 if ( ! $this->is_modified ) {
314 return true;
315 }
316
317 $data = $this->data;
318 $success = true;
319
320 if ( ! isset( $data['id'] ) ) {
321
322 $at = self::insert( $data );
323 if ( $at ) {
324 $this->data = $at->data;
325 $success = true;
326 } else {
327 $success = false;
328 }
329 } else {
330
331 unset( $data['id'] );
332 $success = $wpdb->update(
333 $wpdb->prefix . 'psmsc_attachments',
334 $data,
335 array( 'id' => $this->data['id'] )
336 );
337 }
338 $this->is_modified = false;
339 return $success ? true : false;
340 }
341
342 /**
343 * Insert new attachment
344 *
345 * @param array $data - insert data.
346 * @return WPSC_Attachment
347 */
348 public static function insert( $data ) {
349
350 global $wpdb;
351
352 $data['is_active'] = isset( $data['is_active'] ) ? $data['is_active'] : 0;
353
354 $success = $wpdb->insert(
355 $wpdb->prefix . 'psmsc_attachments',
356 $data
357 );
358
359 if ( ! $success ) {
360 return false;
361 }
362
363 $attachment = new WPSC_Attachment( $wpdb->insert_id );
364 return $attachment;
365 }
366
367 /**
368 * Make it inactive so that garbage collector will delete files associated in
369 * background and then delete the record. This will improve its performance.
370 *
371 * @param WPSC_Attachment $attachment - attachment object.
372 * @return boolean
373 */
374 public static function destroy( $attachment ) {
375
376 $attachment->is_active = 0;
377 $attachment->save();
378 return true;
379 }
380
381 /**
382 * Set data to create new object using direct data. Used in find method
383 *
384 * @param array $data - data to set for object.
385 * @return void
386 */
387 private function set_data( $data ) {
388
389 foreach ( $data as $var_name => $val ) {
390 $this->data[ $var_name ] = $val !== null ? $val : '';
391 }
392 }
393
394 /**
395 * Find records based on given filters
396 *
397 * @param array $filter - array containing array items like search, where, orderby, order, page_no, items_per_page, etc.
398 * @param boolean $is_object - return data as array or object. Default object.
399 * @return mixed
400 */
401 public static function find( $filter = array(), $is_object = true ) {
402
403 global $wpdb;
404
405 $sql = 'SELECT * FROM ' . $wpdb->prefix . 'psmsc_attachments ';
406 $where = self::get_where( $filter );
407
408 $filter['items_per_page'] = isset( $filter['items_per_page'] ) ? $filter['items_per_page'] : 5;
409 $filter['page_no'] = isset( $filter['page_no'] ) ? $filter['page_no'] : 1;
410 $filter['orderby'] = isset( $filter['orderby'] ) ? $filter['orderby'] : 'id';
411 $filter['order'] = isset( $filter['order'] ) ? $filter['order'] : 'ASC';
412
413 $order = WPSC_Functions::parse_order( $filter );
414 $limit = WPSC_Functions::parse_limit( $filter );
415
416 $sql = $sql . $where . $order . $limit;
417 $results = $wpdb->get_results( $sql, ARRAY_A );
418
419 // total results.
420 $sql = 'SELECT count(id) FROM ' . $wpdb->prefix . 'psmsc_attachments ';
421 $total_items = $wpdb->get_var( $sql . $where );
422
423 $response = WPSC_Functions::parse_response( $results, $total_items, $filter );
424
425 // Return array.
426 if ( ! $is_object ) {
427 return $response;
428 }
429
430 // create and return array of objects.
431 $temp_results = array();
432 foreach ( $response['results'] as $attachment ) {
433
434 $ob = new WPSC_Attachment();
435 $data = array();
436 foreach ( $attachment as $key => $val ) {
437 $data[ $key ] = $val;
438 }
439 $ob->set_data( $data );
440 $temp_results[] = $ob;
441 }
442 $response['results'] = $temp_results;
443
444 return $response;
445 }
446
447 /**
448 * Get where for find method
449 *
450 * @param array $filter - user filter.
451 * @return array
452 */
453 private static function get_where( $filter ) {
454
455 $where = array( '1=1' );
456
457 // Set user defined filters.
458 $meta_query = isset( $filter['meta_query'] ) ? $filter['meta_query'] : array();
459 if ( $meta_query ) {
460 $where[] = WPSC_Functions::parse_user_filters( __CLASS__, $meta_query );
461 }
462
463 // Search.
464 $search = WPSC_Functions::get_filter_search_str( $filter );
465 if ( $search ) {
466 $search_query = array(
467 'CONVERT(name USING utf8) LIKE \'%' . $search . '%\'',
468 );
469 $search_query = apply_filters( 'wpsc_attachment_search_query', $search_query, $filter );
470 $where[] = '( ' . implode( ' OR ', $search_query ) . ' )';
471 }
472
473 return 'WHERE ' . implode( ' AND ', $where ) . ' ';
474 }
475
476 /**
477 * Load current class to reference classes
478 *
479 * @param array $classes - Associative array of class names indexed by its slug.
480 * @return array
481 */
482 public static function load_ref_class( $classes ) {
483
484 $classes['wpsc_attachment'] = array(
485 'class' => __CLASS__,
486 'save-key' => 'id',
487 );
488 return $classes;
489 }
490
491 /**
492 * Clear records and actual files for attachments that are not active for more than 24 hrs.
493 * This uses cron-job for background running to improve performace of load-time while deleting attachments.
494 *
495 * @return void
496 */
497 public static function garbage_collector() {
498
499 global $wpdb;
500 $d = ( new DateTime() )->sub( new DateInterval( 'P1D' ) );
501
502 $attachments = self::find(
503 array(
504 'items_per_page' => 20,
505 'meta_query' => array(
506 'relation' => 'AND',
507 array(
508 'slug' => 'date_created',
509 'compare' => '<',
510 'val' => $d->format( 'Y-m-d H:i:s' ),
511 ),
512 array(
513 'relation' => 'OR',
514 array(
515 'slug' => 'is_active',
516 'compare' => '=',
517 'val' => '0',
518 ),
519 array(
520 'slug' => 'source',
521 'compare' => '=',
522 'val' => 'img_editor_tmp',
523 ),
524 ),
525 ),
526 )
527 )['results'];
528 foreach ( $attachments as $attachment ) {
529
530 $upload_dir = wp_upload_dir();
531 $file_path = $upload_dir['basedir'] . $attachment->file_path;
532 if ( file_exists( $file_path ) ) {
533 wp_delete_file( $file_path );
534 }
535 $wpdb->query( "DELETE FROM {$wpdb->prefix}psmsc_attachments WHERE id=" . $attachment->id );
536 }
537 }
538
539 /**
540 * Ajax callback for attachment file upload
541 *
542 * @return void
543 */
544 public static function file_upload() {
545
546 if ( check_ajax_referer( 'wpsc_file_upload', '_ajax_nonce', false ) != 1 ) {
547 wp_send_json_error( 'Unauthorised request!', 401 );
548 }
549
550 if ( ! WPSC_Text_Editor::is_allow_attachments() ) {
551 wp_send_json_error( new WP_Error( '001', 'Unauthorized' ), 401 );
552 }
553
554 $recaptcha = get_option( 'wpsc-recaptcha-settings' );
555 if ( $recaptcha['allow-recaptcha'] === 1 && $recaptcha['recaptcha-version'] == 3 && $recaptcha['recaptcha-site-key'] && $recaptcha['recaptcha-secret-key'] ) {
556 WPSC_MS_Recaptcha::validate( 'file_upload' );
557 }
558
559 $file = isset( $_FILES['wpscFileAttachment'] ) ? $_FILES['wpscFileAttachment'] : false; // phpcs:ignore
560 if ( ! $file ) {
561 wp_send_json_error( 'File not found!', 400 );
562 }
563
564 $file_settings = get_option( 'wpsc-gs-file-attachments' );
565 $original_name = sanitize_file_name( $file['name'] );
566 $filename = time() . '_' . sanitize_file_name( $file['name'] );
567 $extension = strtolower( pathinfo( $filename, PATHINFO_EXTENSION ) );
568 $today = new DateTime();
569 $upload_dir = wp_upload_dir();
570
571 // Allowed file extension.
572 $allowed_file_extensions = explode( ',', $file_settings['allowed-file-extensions'] );
573 $allowed_file_extensions = array_map( 'trim', $allowed_file_extensions );
574 $allowed_file_extensions = array_map( 'strtolower', $allowed_file_extensions );
575 if ( ! ( in_array( $extension, $allowed_file_extensions ) ) ) {
576 wp_send_json_error( 'File extension not allowed!', 400 );
577 }
578
579 // Allowed file size.
580 $allowed_file_size = intval( $file_settings['attachments-max-filesize'] ) * 1000000;
581 if ( ! ( isset( $file['size'] ) && $file['size'] <= $allowed_file_size ) ) {
582 wp_send_json_error( 'File size exceeds allowed limit!', 400 );
583 }
584
585 // Init attachment data.
586 $data = array(
587 'name' => $original_name,
588 'date_created' => $today->format( 'Y-m-d H:i:s' ),
589 );
590
591 // Check for image type. Add a ".txt" extension to non-image file to prevent executing uploaded files on server.
592 $img_extensions = array( 'png', 'jpeg', 'jpg', 'bmp', 'pdf', 'gif' );
593 if ( ! in_array( $extension, $img_extensions ) ) {
594 $data['is_image'] = 0;
595 } else {
596 $data['is_image'] = 1;
597 }
598
599 $ext = pathinfo( $filename, PATHINFO_EXTENSION );
600 $file_name = substr( $filename, 0, -( strlen( $ext ) + 1 ) );
601 $filename = $file_name . '.' . strtolower( $ext );
602 $filepath_short = '/wpsc/' . $today->format( 'Y' ) . '/' . $today->format( 'm' ) . '/' . $filename;
603 $data['file_path'] = $filepath_short;
604
605 // Set up upload overrides.
606 $upload_overrides = array(
607 'test_form' => false,
608 );
609 $file['name'] = $filename;
610 add_filter( 'upload_dir', array( __CLASS__, 'wpsc_upload_dir' ) );
611 add_filter( 'upload_mimes', array( __CLASS__, 'wpsc_custom_upload_mimes' ) );
612 $uploaded_file = wp_handle_upload( $file, $upload_overrides );
613 // Insert record in database.
614 if ( $uploaded_file && empty( $uploaded_file['error'] ) ) {
615
616 $pos = strpos( $uploaded_file['file'], 'wpsc/' );
617 if ( $pos === false ) {
618 wp_send_json_error( 'Something went wrong!', 500 );
619 }
620 $new_path = substr( $uploaded_file['file'], $pos );
621 if ( $new_path[0] !== '/' ) {
622 $new_path = '/' . $new_path;
623 }
624 $data['file_path'] = $new_path;
625 $attachment = self::insert( $data );
626 if ( ! $attachment->id ) {
627 wp_send_json_error( 'Something went wrong!', 500 );
628 }
629
630 wp_send_json( array( 'id' => $attachment->id ) );
631
632 } else {
633
634 wp_send_json_error( 'Something went wrong!', 500 );
635 }
636 }
637
638 /**
639 * Returns attachment ids to be used for search in ticket list
640 *
641 * @param string $search - search string.
642 * @return array
643 */
644 public static function get_tl_search_string( $search ) {
645
646 $search_items = array();
647 if ( is_array( self::$tl_search_items ) ) {
648 $search_items = self::$tl_search_items;
649 } else {
650 $attachments = self::find(
651 array(
652 'search' => $search,
653 'items_per_page' => 0,
654 )
655 )['results'];
656 if ( $attachments ) {
657 foreach ( $attachments as $attachment ) {
658 $search_items[] = $attachment->id;
659 }
660 }
661 self::$tl_search_items = $search_items;
662 }
663
664 return $search_items;
665 }
666
667 /**
668 * Custom tinymce image popup
669 *
670 * @return void
671 */
672 public static function add_custom_image_tinymce() {
673
674 if ( check_ajax_referer( 'wpsc_add_custom_image_tinymce', '_ajax_nonce', false ) != 1 ) {
675 wp_send_json_error( 'Unauthorised request!', 401 );
676 }
677
678 $title = esc_attr__( 'Insert/edit image', 'supportcandy' );
679
680 $editor_id = isset( $_POST['editor_id'] ) ? sanitize_text_field( wp_unslash( $_POST['editor_id'] ) ) : '';
681 if ( ! $editor_id ) {
682 wp_send_json_error( 'Something went wrong!', 400 );
683 }
684
685 ob_start();?>
686 <form action="#" onsubmit="return false;" class="wpsc-insert-edit-image">
687 <div class="wpsc-input-group">
688 <div class="label-container">
689 <label for=""><?php esc_attr_e( 'Source', 'supportcandy' ); ?></label>
690 <span class="required-char">*</span>
691 </div>
692 <div style="display:flex;">
693 <input type="text" accept="image/*" id="wpsc-tinymce-image-url" class="wpsc-tinymce-image-url" style="flex-grow: 1;" autocomplete="off">
694 <button id="wpsc-tinymce-get-file-url" class="wpsc-button small secondary" style="margin-left: 2px; width:100px;" onclick="wpsc_tinymce_image_picker();"><?php esc_attr_e( 'Upload', 'supportcandy' ); ?></button>
695 <input type='file' accept="image/*" name='fileupload' id='wpsc-fileupload' style='display: none;'>
696 </div>
697 </div>
698 <div class="wpsc-input-group">
699 <div class="label-container">
700 <label for=""><?php esc_attr_e( 'Dimentions', 'supportcandy' ); ?></label>
701 <span class="required-char">*</span>
702 </div>
703 <div style="display: flex; align-items:center;">
704 <input type="text" id="wpsc-tinymce-image-width" aria-label="width" class="wpsc-image-dimention" style="width:70px; margin-right:5px;" autocomplete="off">
705 <span class="wpsc-image-dimention-x-sign" style="margin-right:5px;">x</span>
706 <input type="text" id="wpsc-tinymce-image-height" aria-label="height" class="wpsc-image-dimention" style="width:70px; margin-right:10px;" autocomplete="off">
707 <div class="checkbox-container">
708 <?php $unique_id = uniqid( 'wpsc_' ); ?>
709 <input id="<?php echo esc_attr( $unique_id ); ?>" type="checkbox" checked value="1"/>
710 <label for="<?php echo esc_attr( $unique_id ); ?>"><?php esc_attr_e( 'Constraint properties', 'supportcandy' ); ?></label>
711 </div>
712 </div>
713 </div>
714 <script>
715 jQuery(".wpsc-tinymce-image-url").change(function(){
716
717 var img = new Image();
718 img.src = jQuery(this).val();
719 img.onload = function() {
720 jQuery('#wpsc-tinymce-image-height').val(this.height);
721 jQuery('#wpsc-tinymce-image-width').val(this.width);
722 var aspectRatio = this.width/this.height;
723 //Get new height:
724 jQuery("#wpsc-tinymce-image-width").on("change", function(){
725
726 if(jQuery("#<?php echo esc_attr( $unique_id ); ?>").prop('checked') == true){
727 newWidth = jQuery(this).val();
728 newHeight = Math.round(newWidth/aspectRatio);
729 jQuery("#wpsc-tinymce-image-height").val(newHeight);
730 }
731 });
732 //Get new width:
733 jQuery("#wpsc-tinymce-image-height").on("change", function(){
734
735 if(jQuery("#<?php echo esc_attr( $unique_id ); ?>").prop('checked') == true){
736 newHeight = jQuery(this).val();
737 newWidth = Math.round(newHeight*aspectRatio);
738 jQuery("#wpsc-tinymce-image-width").val(newWidth);
739 }
740 });
741 }
742 });
743
744 /**
745 * Tinymce image picker
746 */
747 function wpsc_tinymce_image_picker() {
748
749 jQuery("#wpsc-fileupload").trigger("click");
750 jQuery("#wpsc-fileupload").unbind('change');
751
752 jQuery("#wpsc-fileupload").on("change", function() {
753 var file = this.files[0];
754 var dataform = new FormData();
755 dataform.append('file', file);
756 dataform.append('file_name', file.name);
757 dataform.append('action', 'wpsc_tinymce_upload_file');
758 dataform.append('_ajax_nonce', '<?php echo esc_attr( wp_create_nonce( 'wpsc_tinymce_upload_file' ) ); ?>');
759
760 jQuery.ajax({
761 url: supportcandy.ajax_url,
762 type: 'POST',
763 data: dataform,
764 processData: false,
765 contentType: false
766 }).done(function (res) {
767
768 jQuery('.wpsc-tinymce-image-url').val(res.imgURL);
769 var img = new Image();
770 img.src = res.imgURL;
771 img.onload = function() {
772
773 jQuery('#wpsc-tinymce-image-height').val(this.height);
774 jQuery('#wpsc-tinymce-image-width').val(this.width);
775 var aspectRatio = this.width/this.height;
776
777 //Get new height:
778 jQuery("#wpsc-tinymce-image-width").on("change", function() {
779
780 if(jQuery("#<?php echo esc_attr( $unique_id ); ?>").prop('checked') == true){
781 newWidth = jQuery(this).val();
782 newHeight = Math.round(newWidth/aspectRatio);
783 jQuery("#wpsc-tinymce-image-height").val(newHeight);
784 }
785 });
786
787 //Get new width:
788 jQuery("#wpsc-tinymce-image-height").on("change", function() {
789
790 if(jQuery("#<?php echo esc_attr( $unique_id ); ?>").prop('checked') == true){
791 newHeight = jQuery(this).val();
792 newWidth = Math.round(newHeight*aspectRatio);
793 jQuery("#wpsc-tinymce-image-width").val(newWidth);
794 }
795 });
796 };
797 });
798 });
799 }
800 </script>
801 </form>
802 <?php
803 $body = ob_get_clean();
804
805 ob_start();
806 ?>
807 <button class="wpsc-button small primary" onclick="wpsc_insert_editor_img('<?php echo esc_attr( $editor_id ); ?>');">
808 <?php esc_attr_e( 'Submit', 'supportcandy' ); ?>
809 </button>
810 <button class="wpsc-button small secondary" onclick="wpsc_close_modal();">
811 <?php esc_attr_e( 'Cancel', 'supportcandy' ); ?>
812 </button>
813 <?php
814 $footer = ob_get_clean();
815
816 $response = array(
817 'title' => $title,
818 'body' => $body,
819 'footer' => $footer,
820 );
821 wp_send_json( $response );
822 }
823
824 /**
825 * Custom tinymce image popup
826 *
827 * @return void
828 */
829 public static function edit_custom_image_tinymce() {
830
831 if ( check_ajax_referer( 'wpsc_edit_custom_image_tinymce', '_ajax_nonce', false ) != 1 ) {
832 wp_send_json_error( 'Unauthorised request!', 401 );
833 }
834
835 $title = esc_attr__( 'Edit image', 'supportcandy' );
836
837 $editor_id = isset( $_POST['editor_id'] ) ? sanitize_text_field( wp_unslash( $_POST['editor_id'] ) ) : '';
838 if ( ! $editor_id ) {
839 wp_send_json_error( 'Something went wrong!', 400 );
840 }
841
842 $height = isset( $_POST['height'] ) ? intval( $_POST['height'] ) : '';
843 if ( ! $height ) {
844 wp_send_json_error( 'Something went wrong!', 400 );
845 }
846
847 $width = isset( $_POST['width'] ) ? intval( $_POST['width'] ) : '';
848 if ( ! $width ) {
849 wp_send_json_error( 'Something went wrong!', 400 );
850 }
851
852 $src = isset( $_POST['src'] ) ? esc_url_raw( wp_unslash( $_POST['src'] ) ) : '';
853 if ( ! $src ) {
854 wp_send_json_error( 'Something went wrong!', 400 );
855 }
856
857 ob_start();
858 ?>
859 <form action="#" onsubmit="return false;" class="wpsc-insert-edit-image">
860 <div class="wpsc-input-group">
861 <div class="label-container">
862 <label for=""><?php esc_attr_e( 'Source', 'supportcandy' ); ?></label>
863 <span class="required-char">*</span>
864 </div>
865 <div style="display:flex;">
866 <input type="text" id="wpsc-tinymce-image-url" class="wpsc-tinymce-image-url" style="flex-grow: 1;" autocomplete="off" value="<?php echo esc_attr( $src ); ?>">
867 <button id="wpsc-tinymce-get-file-url" class="wpsc-button small secondary" style="margin-left: 2px; width:100px" onclick="wpsc_tinymce_image_picker();"><?php esc_attr_e( 'Upload', 'supportcandy' ); ?></button>
868 <input type='file' accept="image/*" name='fileupload' id='wpsc-fileupload' style='display: none;'>
869 </div>
870 </div>
871 <div class="wpsc-input-group">
872 <div class="label-container">
873 <label for=""><?php esc_attr_e( 'Dimentions', 'supportcandy' ); ?></label>
874 <span class="required-char">*</span>
875 </div>
876 <div style="display: flex; align-items:center;">
877 <input type="text" id="wpsc-tinymce-image-width" aria-label="width" class="wpsc-image-dimention" style="width:70px; margin-right:5px;" autocomplete="off" value="<?php echo esc_attr( $width ); ?>">
878 <span class="wpsc-image-dimention-x-sign" style="margin-right:5px;">x</span>
879 <input type="text" id="wpsc-tinymce-image-height" aria-label="height" class="wpsc-image-dimention" style="width:70px; margin-right:10px;" autocomplete="off" value="<?php echo esc_attr( $height ); ?>" >
880 <div class="checkbox-container">
881 <?php $unique_id = uniqid( 'wpsc_' ); ?>
882 <input id="<?php echo esc_attr( $unique_id ); ?>" type="checkbox" checked value="1"/>
883 <label for="<?php echo esc_attr( $unique_id ); ?>"><?php esc_attr_e( 'Constraint properties', 'supportcandy' ); ?></label>
884 </div>
885 </div>
886 </div>
887 <script>
888 jQuery(".wpsc-tinymce-image-url").change(function(){
889
890 var img = new Image();
891 img.src = jQuery(this).val();
892 img.onload = function() {
893 jQuery('#wpsc-tinymce-image-height').val(this.height);
894 jQuery('#wpsc-tinymce-image-width').val(this.width);
895 var aspectRatio = this.width/this.height;
896 //Get new height:
897 jQuery("#wpsc-tinymce-image-width").on("change", function(){
898
899 if(jQuery("#<?php echo esc_attr( $unique_id ); ?>").prop('checked') == true){
900 newWidth = jQuery(this).val();
901 newHeight = Math.round(newWidth/aspectRatio);
902 jQuery("#wpsc-tinymce-image-height").val(newHeight);
903 }
904 });
905 //Get new width:
906 jQuery("#wpsc-tinymce-image-height").on("change", function(){
907
908 if(jQuery("#<?php echo esc_attr( $unique_id ); ?>").prop('checked') == true){
909 newHeight = jQuery(this).val();
910 newWidth = Math.round(newHeight*aspectRatio);
911 jQuery("#wpsc-tinymce-image-width").val(newWidth);
912 }
913 });
914 }
915 });
916 var height = <?php echo esc_attr( $height ); ?>;
917 var width = <?php echo esc_attr( $width ); ?>;
918 var aspectRatio = width/height;
919 jQuery("#wpsc-tinymce-image-width").on("change", function(){
920
921 if(jQuery("#<?php echo esc_attr( $unique_id ); ?>").prop('checked') == true){
922 newWidth = jQuery(this).val();
923 newHeight = Math.round(newWidth/aspectRatio);
924 jQuery("#wpsc-tinymce-image-height").val(newHeight);
925 }
926 });
927 //Get new width:
928 jQuery("#wpsc-tinymce-image-height").on("change", function(){
929
930 if(jQuery("#<?php echo esc_attr( $unique_id ); ?>").prop('checked') == true){
931 newHeight = jQuery(this).val();
932 newWidth = Math.round(newHeight*aspectRatio);
933 jQuery("#wpsc-tinymce-image-width").val(newWidth);
934 }
935 });
936
937 /**
938 * Tinymce image picker
939 */
940 function wpsc_tinymce_image_picker() {
941
942 jQuery("#wpsc-fileupload").trigger("click");
943 jQuery("#wpsc-fileupload").unbind('change');
944
945 jQuery("#wpsc-fileupload").on("change", function() {
946 var file = this.files[0];
947 var dataform = new FormData();
948 dataform.append('file', file);
949 dataform.append('file_name', file.name);
950 dataform.append('action', 'wpsc_tinymce_upload_file');
951 dataform.append('_ajax_nonce', '<?php echo esc_attr( wp_create_nonce( 'wpsc_tinymce_upload_file' ) ); ?>');
952
953 jQuery.ajax({
954 url: supportcandy.ajax_url,
955 type: 'POST',
956 data: dataform,
957 processData: false,
958 contentType: false
959 }).done(function (res) {
960
961 jQuery('.wpsc-tinymce-image-url').val(res.imgURL);
962 var img = new Image();
963 img.src = res.imgURL;
964 img.onload = function() {
965
966 jQuery('#wpsc-tinymce-image-height').val(this.height);
967 jQuery('#wpsc-tinymce-image-width').val(this.width);
968 var aspectRatio = this.width/this.height;
969
970 //Get new height:
971 jQuery("#wpsc-tinymce-image-width").on("change", function() {
972
973 if(jQuery("#<?php echo esc_attr( $unique_id ); ?>").prop('checked') == true){
974 newWidth = jQuery(this).val();
975 newHeight = Math.round(newWidth/aspectRatio);
976 jQuery("#wpsc-tinymce-image-height").val(newHeight);
977 }
978 });
979
980 //Get new width:
981 jQuery("#wpsc-tinymce-image-height").on("change", function() {
982
983 if(jQuery("#<?php echo esc_attr( $unique_id ); ?>").prop('checked') == true){
984 newHeight = jQuery(this).val();
985 newWidth = Math.round(newHeight*aspectRatio);
986 jQuery("#wpsc-tinymce-image-width").val(newWidth);
987 }
988 });
989 };
990 });
991 });
992 }
993 </script>
994 </form>
995 <?php
996 $body = ob_get_clean();
997
998 ob_start();
999 ?>
1000 <button class="wpsc-button small primary" onclick="wpsc_insert_editor_img('<?php echo esc_attr( $editor_id ); ?>');">
1001 <?php esc_attr_e( 'Submit', 'supportcandy' ); ?>
1002 </button>
1003 <button class="wpsc-button small secondary" onclick="wpsc_close_modal();">
1004 <?php esc_attr_e( 'Cancel', 'supportcandy' ); ?>
1005 </button>
1006 <?php
1007 $footer = ob_get_clean();
1008
1009 $response = array(
1010 'title' => $title,
1011 'body' => $body,
1012 'footer' => $footer,
1013 );
1014 wp_send_json( $response );
1015 }
1016
1017 /**
1018 * Check download file
1019 *
1020 * @return void
1021 */
1022 public static function check_download_file() {
1023
1024 if ( isset( $_REQUEST['wpsc_attachment'] ) ) { // phpcs:ignore
1025
1026 if ( WPSC_Functions::is_site_admin() && ! extension_loaded( 'fileinfo' ) ) {
1027 echo 'The fileinfo extension is not available. Please enable it in your PHP configuration.';
1028 exit;
1029 }
1030
1031 $current_user = WPSC_Current_User::$current_user;
1032 $has_auth = true;
1033 if ( isset( $_REQUEST['user'] ) && ! $current_user ) { // phpcs:ignore
1034
1035 $customer = new WPSC_Customer( intval( $_REQUEST['user'] ) ); // phpcs:ignore
1036 if ( ! $customer->id ) {
1037 wp_send_json_error( __( 'Bad request!', 'supportcandy' ), 400 );
1038 }
1039
1040 $current_user = WPSC_Current_User::change_current_user( $customer->email );
1041 $has_auth = false;
1042 }
1043
1044 $attachment_id = intval( $_REQUEST['wpsc_attachment'] ); // phpcs:ignore
1045 $attachment = new WPSC_Attachment( $attachment_id );
1046 if ( ! $attachment->id ) {
1047 return;
1048 }
1049 $auth_code = isset($_REQUEST['auth_code']) ? sanitize_text_field( $_REQUEST['auth_code'] ) : ''; // phpcs:ignore
1050 $advanced = get_option( 'wpsc-ms-advanced-settings' );
1051 switch ( $attachment->source ) {
1052
1053 case 'cf':
1054 $cf = new WPSC_Custom_Field( $attachment->source_id );
1055 if ( ! $cf->id ) {
1056 wp_send_json_error( __( 'Bad request!', 'supportcandy' ), 400 );
1057 }
1058
1059 if ( in_array( $cf->field, array( 'ticket', 'agentonly' ) ) ) { // ticket field.
1060
1061 $ticket = new WPSC_Ticket( $attachment->ticket_id );
1062 if ( ! $ticket->id ) {
1063 wp_send_json_error( __( 'Bad request!', 'supportcandy' ), 400 );
1064 }
1065
1066 if ( ! $has_auth ) {
1067 $auth_code = isset( $_REQUEST['auth_code'] ) ? sanitize_text_field( $_REQUEST['auth_code'] ) : ''; // phpcs:ignore
1068 if ( ! $auth_code || $auth_code != $ticket->auth_code ) {
1069 wp_send_json_error( 'Unauthorized!', 401 );
1070 }
1071 }
1072
1073 WPSC_Individual_Ticket::$ticket = $ticket;
1074 if ( ! (
1075 ( $current_user->is_agent && WPSC_Individual_Ticket::has_ticket_cap( 'view' ) ) ||
1076 WPSC_Individual_Ticket::is_customer() ||
1077 ( ! $advanced['ticket-url-auth'] && $ticket->auth_code == $auth_code )
1078 ) ) {
1079 wp_send_json_error( 'Unauthorized!', 401 );
1080 }
1081
1082 self::file_download( $attachment );
1083
1084 } else { // customer field.
1085
1086 $customer = new WPSC_Customer( intval( $attachment->customer_id ) );
1087 $ticket_widgets = get_option( 'wpsc-ticket-widget', array() );
1088 $raised_by = $ticket_widgets['raised-by'];
1089
1090 if (
1091 $current_user->customer->id == $customer->id ||
1092 (
1093 $current_user->is_agent &&
1094 in_array( $current_user->agent->role, $raised_by['allowed-agent-roles'] )
1095 )
1096 ) {
1097 self::file_download( $attachment );
1098 }
1099 }
1100 break;
1101
1102 case 'reply':
1103 case 'report':
1104 $ticket = new WPSC_Ticket( $attachment->ticket_id );
1105 if ( ! $ticket->id ) {
1106 wp_send_json_error( __( 'Bad request!', 'supportcandy' ), 400 );
1107 }
1108
1109 if ( ! $has_auth ) {
1110 $auth_code = isset( $_REQUEST['auth_code'] ) ? sanitize_text_field( $_REQUEST['auth_code'] ) : ''; // phpcs:ignore
1111 if ( ! $auth_code || $auth_code != $ticket->auth_code ) {
1112 wp_send_json_error( 'Unauthorized!', 401 );
1113 }
1114 }
1115
1116 WPSC_Individual_Ticket::$ticket = $ticket;
1117 if ( ! (
1118 ( $current_user->is_agent && WPSC_Individual_Ticket::has_ticket_cap( 'view' ) ) ||
1119 WPSC_Individual_Ticket::is_customer() ||
1120 ( ! $advanced['ticket-url-auth'] && $ticket->auth_code == $auth_code )
1121 ) ) {
1122 wp_send_json_error( 'Unauthorized!', 401 );
1123 }
1124
1125 self::file_download( $attachment );
1126 break;
1127
1128 case 'note':
1129 $ticket = new WPSC_Ticket( $attachment->ticket_id );
1130 if ( ! $ticket->id ) {
1131 wp_send_json_error( __( 'Bad request!', 'supportcandy' ), 400 );
1132 }
1133
1134 if ( ! $has_auth ) {
1135 $auth_code = isset( $_REQUEST['auth_code'] ) ? sanitize_text_field( $_REQUEST['auth_code'] ) : ''; // phpcs:ignore
1136 if ( ! $auth_code || $auth_code != $ticket->auth_code ) {
1137 wp_send_json_error( 'Unauthorized!', 401 );
1138 }
1139 }
1140
1141 WPSC_Individual_Ticket::$ticket = $ticket;
1142 if ( ! (
1143 $current_user->is_agent && WPSC_Individual_Ticket::has_ticket_cap( 'pn' )
1144 ) ) {
1145 wp_send_json_error( 'Unauthorized!', 401 );
1146 }
1147
1148 self::file_download( $attachment );
1149 break;
1150
1151 case 'img_editor':
1152 $ticket = new WPSC_Ticket( $attachment->ticket_id );
1153 if ( ! $ticket->id ) {
1154 wp_send_json_error( __( 'Bad request!', 'supportcandy' ), 400 );
1155 }
1156
1157 WPSC_Individual_Ticket::$ticket = $ticket;
1158 if ( ! (
1159 ( $current_user->is_agent && WPSC_Individual_Ticket::has_ticket_cap( 'view' ) ) ||
1160 WPSC_Individual_Ticket::is_customer() ||
1161 ( $ticket->auth_code == $auth_code )
1162 ) ) {
1163 wp_send_json_error( 'Unauthorized!', 401 );
1164 }
1165 self::file_download( $attachment );
1166 break;
1167 case 'img_editor_tmp':
1168 self::file_download( $attachment );
1169 }
1170 }
1171 }
1172
1173 /**
1174 * Download attachment
1175 *
1176 * @param WPSC_Attachment $attachment - attachment object.
1177 * @return void
1178 */
1179 public static function file_download( $attachment ) {
1180
1181 // Turn off all output buffering.
1182 while ( ob_get_level() ) {
1183 ob_end_clean();
1184 }
1185
1186 $upload_dir = wp_upload_dir();
1187 $file_path = $upload_dir['basedir'] . $attachment->file_path;
1188 if ( ! file_exists( $file_path ) ) {
1189 echo 'File does not exists!';
1190 exit;
1191 }
1192
1193 // Check whether attachment is of image type.
1194 $attach_settings = get_option( 'wpsc-gs-file-attachments' );
1195 if ( $attachment->is_image && $attach_settings['image-download-behaviour'] == 'open-browser' ) {
1196 header( 'Content-Type: ' . mime_content_type( $file_path ) );
1197 readfile( $file_path ); // phpcs:ignore
1198 exit( 0 );
1199 }
1200
1201 header( 'Content-Description: File Transfer' );
1202 header( 'Cache-Control: public' );
1203 header( 'Content-Type: application/force-download' );
1204 header( 'Content-Disposition: attachment;filename="' . $attachment->name . '"' );
1205 header( 'Content-Length: ' . filesize( $file_path ) );
1206 flush();
1207 readfile( $file_path ); // phpcs:ignore
1208 exit( 0 );
1209 }
1210
1211 /**
1212 * Upload tinymce image file to database
1213 *
1214 * @return void
1215 */
1216 public static function tinymce_upload_file() {
1217
1218 if ( check_ajax_referer( 'wpsc_tinymce_upload_file', '_ajax_nonce', false ) != 1 ) {
1219 wp_send_json_error( 'Unauthorised request!', 401 );
1220 }
1221
1222 $file = isset( $_FILES['file'] ) ? $_FILES['file'] : false; // phpcs:ignore
1223 if ( ! $file ) {
1224 wp_send_json_error( 'File not found!', 400 );
1225 }
1226
1227 $file_settings = get_option( 'wpsc-gs-file-attachments' );
1228 $original_name = sanitize_file_name( $file['name'] );
1229 $filename = time() . '_' . sanitize_file_name( $file['name'] );
1230 $extension = strtolower( pathinfo( $filename, PATHINFO_EXTENSION ) );
1231 $today = new DateTime();
1232 $upload_dir = wp_upload_dir();
1233
1234 // Check file extension.
1235 $img_extensions = array( 'jpg', 'jpeg', 'png', 'gif' );
1236 if ( ! ( in_array( $extension, $img_extensions ) ) ) {
1237 wp_send_json_error( 'Invalid file extension!', 400 );
1238 }
1239
1240 // Allowed file size.
1241 $allowed_file_size = intval( $file_settings['attachments-max-filesize'] ) * 1000000;
1242 if ( ! ( isset( $file['size'] ) && $file['size'] <= $allowed_file_size ) ) {
1243 wp_send_json_error( 'File size exceeds allowed limit!', 400 );
1244 }
1245
1246 $filepath_short = '/wpsc/' . $today->format( 'Y' ) . '/' . $today->format( 'm' ) . '/' . $filename;
1247
1248 // Init attachment data.
1249 $data = array(
1250 'name' => $original_name,
1251 'file_path' => $filepath_short,
1252 'is_image' => 1,
1253 'date_created' => $today->format( 'Y-m-d H:i:s' ),
1254 'is_active' => 0,
1255 'source' => 'img_editor_tmp',
1256 );
1257
1258 // Set up upload overrides.
1259 $upload_overrides = array(
1260 'test_form' => false,
1261 );
1262 $file['name'] = $filename;
1263 add_filter( 'upload_dir', array( __CLASS__, 'wpsc_upload_dir' ) );
1264 $uploaded_file = wp_handle_upload( $file, $upload_overrides );
1265 // Insert record in database.
1266 if ( $uploaded_file && empty( $uploaded_file['error'] ) ) {
1267
1268 $pos = strpos( $uploaded_file['file'], '/wpsc/' );
1269 if ( $pos === false ) {
1270 wp_send_json_error( 'Something went wrong 1!', 500 );
1271 }
1272 $new_path = substr( $uploaded_file['file'], $pos );
1273 $data['file_path'] = $new_path;
1274 $attachment = self::insert( $data );
1275 if ( ! $attachment->id ) {
1276 wp_send_json_error( 'Something went wrong 2!', 500 );
1277 }
1278
1279 wp_send_json( array( 'imgURL' => home_url( '/' ) . '?wpsc_attachment=' . $attachment->id ) );
1280
1281 } else {
1282
1283 wp_send_json_error( 'Something went wrong 3!', 500 );
1284 }
1285 }
1286 }
1287 endif;
1288
1289 WPSC_Attachment::init();
1290