PluginProbe
Timetics – Appointment Booking Calendar & Scheduling / trunk
Timetics – Appointment Booking Calendar & Scheduling vtrunk
1.0.61 1.0.60 1.0.59 1.0.58 1.0.57 1.0.56 trunk 1.0.0 1.0.1 1.0.10 1.0.11 1.0.12 1.0.13 1.0.14 1.0.15 1.0.16 1.0.17 1.0.18 1.0.19 1.0.2 1.0.20 1.0.21 1.0.22 1.0.23 1.0.24 All 62 releases
timetics / core / customers / api-customer.php

api-customer.php in Timetics – Appointment Booking Calendar & Scheduling trunk, at core/customers/api-customer.php

640 lines 19.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Api Customer
4 *
5 * @package Timetics
6 */
7 namespace Timetics\Core\Customers;
8
9 defined( 'ABSPATH' ) || exit;
10
11 use Timetics\Base\Api;
12 use Timetics\Core\Bookings\Api_Booking;
13 use Timetics\Utils\Singleton;
14 use WP_HTTP_Response;
15 use WP_User_Query;
16
17 /**
18 * Class Api_customer
19 */
20 class Api_Customer extends Api {
21 use Singleton;
22
23 /**
24 * Store namespace
25 *
26 * @var string
27 */
28 protected $namespace = 'timetics/v1';
29
30 /**
31 * Store rest base
32 *
33 * @var string
34 */
35 protected $rest_base = 'customers';
36
37 /**
38 * Register rest route
39 *
40 * @return void
41 */
42 public function register_routes() {
43 register_rest_route(
44 $this->namespace, $this->rest_base, [
45 [
46 'methods' => \WP_REST_Server::READABLE,
47 'callback' => [$this, 'get_items'],
48 'permission_callback' => function () {
49 return current_user_can( 'manage_timetics' );
50 },
51 ],
52 [
53 'methods' => \WP_REST_Server::CREATABLE,
54 'callback' => [$this, 'create_item'],
55 'permission_callback' => function () {
56 return current_user_can( 'manage_timetics' );
57 },
58 ],
59 [
60 'methods' => \WP_REST_Server::DELETABLE,
61 'callback' => [$this, 'bulk_delete'],
62 'permission_callback' => function () {
63 return current_user_can( 'manage_options' );
64 },
65 ],
66 ]
67 );
68
69 /**
70 * Register route
71 *
72 * @var void
73 */
74 register_rest_route(
75 $this->namespace, '/' . $this->rest_base . '/(?P<customer_id>[\d]+)', [
76 [
77 'methods' => \WP_REST_Server::READABLE,
78 'callback' => [$this, 'get_item'],
79 'permission_callback' => function ( $request ) {
80 $customer_id = (int) $request['customer_id'];
81
82 if ( timetics_can_view_all_data() || get_current_user_id() === $customer_id ) {
83 return true;
84 }
85
86 // manage_timetics is not admin-only — staff may only view a
87 // customer they actually have a visible booking with.
88 return current_user_can( 'manage_timetics' )
89 && in_array( $customer_id, timetics_get_visible_customer_ids(), true );
90 },
91 ],
92 [
93 'methods' => \WP_REST_Server::EDITABLE,
94 'callback' => [$this, 'update_item'],
95 'permission_callback' => [$this, 'update_item_permission_callback'],
96 ],
97 [
98 'methods' => \WP_REST_Server::DELETABLE,
99 'callback' => [$this, 'delete_item'],
100 'permission_callback' => function () {
101 return current_user_can( 'manage_options' );
102 },
103 ],
104 ]
105 );
106
107 register_rest_route(
108 $this->namespace, $this->rest_base . '/search', [
109 [
110 'methods' => \WP_REST_Server::READABLE,
111 'callback' => [$this, 'search_items'],
112 'permission_callback' => function () {
113 return current_user_can( 'manage_timetics' );
114 },
115 ],
116 ]
117 );
118
119 /**
120 * Register route for booking single customer
121 *
122 * @var void
123 */
124 register_rest_route(
125 $this->namespace, '/' . $this->rest_base . '/(?P<customer_id>[\d]+)/bookings', [
126 [
127 'methods' => \WP_REST_Server::READABLE,
128 'callback' => [$this, 'get_bookings'],
129 'permission_callback' => function ( $request ) {
130 $customer_id = (int) $request['customer_id'];
131
132 if ( timetics_can_view_all_data() || get_current_user_id() === $customer_id ) {
133 return true;
134 }
135
136 return current_user_can( 'manage_timetics' )
137 && in_array( $customer_id, timetics_get_visible_customer_ids(), true );
138 },
139 ],
140 ]
141 );
142
143 }
144 /**
145 * Get all customers
146 *
147 * @param WP_Rest_Request $request
148 *
149 * @return JSON
150 */
151 public function get_items( $request ) {
152 $per_page = ! empty( $request['per_page'] ) ? intval( $request['per_page'] ) : 20;
153 $paged = ! empty( $request['paged'] ) ? intval( $request['paged'] ) : 1;
154
155 $args = [
156 'number' => $per_page,
157 'paged' => $paged,
158 ];
159
160 // Staff only see customers from their own bookings, administrators see everyone.
161 if ( ! timetics_can_view_all_data() ) {
162 $args['include'] = timetics_get_visible_customer_ids( get_current_user_id() );
163 }
164
165 $customer = Customer::all( $args );
166
167 $items = [];
168
169 foreach ( $customer['items'] as $item ) {
170 $items[] = $this->prepare_item( $item->ID );
171 }
172
173 /**
174 * Added temporary for leagacy sass. It will remove in future.
175 */
176 $items = apply_filters( 'timetics/admin/customer/get_items', $items );
177
178 $data = [
179 'success' => 1,
180 'data' => [
181 'total' => $customer['total'],
182 'items' => $items,
183 ],
184 ];
185
186 return rest_ensure_response( $data );
187 }
188
189 /**
190 * Get single customer
191 *
192 * @param WP_Rest_Requesr $request
193 *
194 * @return JSON Single customer data
195 */
196 public function get_item( $request ) {
197 $customer_id = (int) $request['customer_id'];
198 $customer = new Customer( $customer_id );
199
200 if ( ! $customer->is_customer() ) {
201 return [
202 'status_code' => 404,
203 'message' => esc_html__( 'Invalid customer id.', 'timetics' ),
204 'data' => [],
205 ];
206 }
207
208 /**
209 * Added temporary for leagacy sass. It will remove in future.
210 */
211 $item = apply_filters( 'timetics/admin/customer/get_item', $this->prepare_item( $customer ) );
212
213 $response = [
214 'status_code' => 200,
215 'data' => $item,
216 ];
217
218 return rest_ensure_response( $response );
219 }
220
221 /**
222 * Search customer
223 *
224 * @return JSON
225 */
226 public function search_items( $request ) {
227
228 // Prepare search args.
229 $per_page = ! empty( $request['per_page'] ) ? intval( $request['per_page'] ) : 20;
230 $paged = ! empty( $request['paged'] ) ? intval( $request['paged'] ) : 1;
231 $search = ! empty( $request['search'] ) ? sanitize_text_field( $request['search'] ) : '';
232
233 $query_args = array(
234 'role' => 'timetics-customer',
235 'number' => $per_page,
236 'paged' => $paged,
237 );
238
239 // Staff only see customers from their own bookings, administrators see everyone.
240 if ( ! timetics_can_view_all_data() ) {
241 $query_args['include'] = timetics_get_visible_customer_ids( get_current_user_id() );
242 }
243
244 // Get search.
245 $users = new WP_User_Query(
246 array_merge(
247 $query_args,
248 array(
249 // @codingStandardsIgnoreStart
250 'meta_query' => array(
251 'relation' => 'OR',
252 array(
253 'key' => '_timetics_customer_first_name',
254 'value' => $search,
255 'compare' => 'LIKE',
256 ),
257 array(
258 'key' => '_timetics_customer_last_name',
259 'value' => $search,
260 'compare' => 'LIKE',
261 ),
262 array(
263 'key' => '_timetics_customer_email',
264 'value' => $search,
265 'compare' => 'LIKE',
266 ),
267 array(
268 'key' => '_timetics_customer_phone',
269 'value' => $search,
270 'compare' => 'LIKE',
271 ),
272 ),
273 // @codingStandardsIgnoreEnd
274 )
275 )
276 );
277
278 // Prepare items for response.
279 $items = [];
280
281 foreach ( $users->get_results() as $item ) {
282 $items[] = $this->prepare_item( $item->ID );
283 }
284
285 $data = [
286 'success' => 1,
287 'status' => 200,
288 'data' => [
289 'total' => $users->get_total(),
290 'items' => $items,
291 ],
292 ];
293
294 return rest_ensure_response( $data );
295 }
296
297 /**
298 * Create Customer
299 *
300 * @param WP_Rest_Request $request
301 *
302 * @return JSON | WP_Error
303 */
304 public function create_item( $request ) {
305 return $this->save_customer( $request );
306 }
307
308 /**
309 * Update customer Permission check
310 *
311 * @param WP_Rest_Request $request
312 *
313 * @return JSON | WP_Error
314 */
315 public function update_item_permission_callback( $request ) {
316 $customer_id = (int) $request['customer_id'];
317
318 // Admins can always update any customer. manage_timetics is not
319 // admin-only — every timetics-staff account has it — so it must not
320 // grant edit access to someone else's customer record.
321 if ( current_user_can( 'manage_options' ) ) {
322 return true;
323 }
324
325 // Customers can update themselves with a valid nonce
326 $nonce = $request->get_header( 'X-WP-Nonce' );
327 if ( ! empty( $nonce ) && wp_verify_nonce( $nonce, 'wp_rest' ) ) {
328 $current_user_id = get_current_user_id();
329 if ( $customer_id === $current_user_id && $current_user_id > 0 ) {
330 return true;
331 }
332 }
333
334 return false;
335 }
336
337 /**
338 * Update customer
339 *
340 * @param WP_Rest_Request $request
341 *
342 * @return JSON | WP_Error
343 */
344 public function update_item( $request ) {
345 $customer_id = (int) $request['customer_id'];
346 $customer = new Customer( $customer_id );
347
348 if ( ! $customer->is_customer() ) {
349 $data = [
350 'status_code' => 404,
351 'message' => esc_html__( 'Invalid customer id.', 'timetics' ),
352 'data' => [],
353 ];
354
355 return new WP_HTTP_Response( $data, 404 );
356 }
357
358 return $this->save_customer( $request, $customer_id );
359 }
360
361 /**
362 * Delete customer
363 *
364 * @param WP_Rest_Request $request
365 *
366 * @return JSON
367 */
368 public function delete_item( $request ) {
369 $customer_id = (int) $request['customer_id'];
370 $customer = new Customer( $customer_id );
371
372 if ( ! $customer->is_customer() ) {
373 $data = [
374 'status_code' => 404,
375 'message' => esc_html__( 'Invalid customer id.', 'timetics' ),
376 'data' => [],
377 ];
378
379 return new WP_HTTP_Response( $data, 404 );
380 }
381
382 $customer->delete();
383
384 /**
385 * Added temporary for leagacy sass. It will remove in future.
386 */
387 do_action( 'timetics/admin/customer/delete_item', $customer );
388
389 $response = [
390 'status_code' => 200,
391 'message' => esc_html__( 'Successfully deleted customer', 'timetics' ),
392 'data' => [],
393 ];
394
395 return rest_ensure_response( $response );
396 }
397
398 /**
399 * Delete multiples
400 *
401 * @param WP_Rest_Request $request
402 *
403 * @return JSON
404 */
405 public function bulk_delete( $request ) {
406 $customers = json_decode( $request->get_body(), true );
407
408 foreach ( $customers as $customer ) {
409 $customer = new customer( $customer );
410
411 if ( ! $customer->is_customer() ) {
412 $data = [
413 'success' => 1,
414 'status' => 404,
415 'message' => esc_html__( 'Invalid customer id.', 'timetics' ),
416 'data' => [],
417 ];
418
419 return new WP_HTTP_Response( $data, 404 );
420 }
421
422 $customer->delete();
423 }
424
425 /**
426 * Added temporary for leagacy sass. It will remove in future.
427 */
428 do_action( 'timetics/admin/customer/bulk_delete', $customers );
429
430 return [
431 'success' => 1,
432 'status' => 200,
433 'message' => esc_html__( 'Successfully deleted customer', 'timetics' ),
434 'data' => [
435 'items' => $customers,
436 ],
437 ];
438 }
439
440 /**
441 * Save customer
442 *
443 * @param WP_Rest_Request $request
444 * @param integer $id [$id description]
445 *
446 * @return JSON | WP_Error
447 */
448 public function save_customer( $request, $id = 0 ) {
449 $data = json_decode( $request->get_body(), true );
450
451 $first_name = ! empty( $data['first_name'] ) ? $data['first_name'] : '';
452 $last_name = ! empty( $data['last_name'] ) ? $data['last_name'] : '';
453 $email = ! empty( $data['email'] ) ? $data['email'] : '';
454 $phone = ! empty( $data['phone'] ) ? $data['phone'] : '';
455 $image = ! empty( $data['image'] ) ? intval( $data['image'] ) : '';
456 $password = ! empty( $data['password'] ) ? $data['password'] : '';
457 $action = $id ? 'updated' : 'created';
458
459 // Validate input data.
460 $validate = $this->validate(
461 $data, [
462 'first_name',
463 'last_name',
464 'email',
465 ]
466 );
467
468 if ( is_wp_error( $validate ) ) {
469 $data = [
470 'success' => 0,
471 'status_code' => 409,
472 'message' => $validate->get_error_messages(),
473 'data' => [],
474 ];
475
476 return new WP_HTTP_Response( $data, 409 );
477 }
478
479 // Save customer data.
480 $customer = new Customer( $id );
481
482 $customer->set_props(
483 [
484 'first_name' => $first_name,
485 'last_name' => $last_name,
486 'email' => $email,
487 'user_name' => $this->generate_username( $email ),
488 'phone' => $phone,
489 'image' => $image,
490 'password' => $password,
491 ]
492 );
493
494 $customer->save();
495
496 if ( is_wp_error( $customer->error ) ) {
497 return [
498 'success' => 0,
499 'status' => 409,
500 'message' => $customer->error->get_error_message(),
501 'data' => [],
502 ];
503 }
504 // Prepare for response.
505 $item = $this->prepare_item( $customer );
506
507 /**
508 * Added temporary for leagacy sass. It will remove in future.
509 */
510 do_action( 'timetics/admin/customer/create_item', $item );
511
512 $data = [
513 'success' => 1,
514 'status' => 200,
515 /* translators: Action */
516 'message' => sprintf( esc_html__( 'Successfully %s customer', 'timetics' ), $action ),
517 'data' => $item,
518 ];
519
520 return rest_ensure_response( $data );
521 }
522
523 /**
524 * Generate username from email
525 *
526 * @param string $email
527 *
528 * @return string
529 */
530 public function generate_username( $email ) {
531 $username = strtok( $email, '@' );
532
533 if ( username_exists( $username ) ) {
534 $username = $username . wp_rand( 10, 100 );
535 }
536
537 return $username;
538 }
539
540 /**
541 * Prepare item
542 *
543 * @param integer | customer $customer_id customer Id
544 *
545 * @return array customer data
546 */
547 public function prepare_item( $customer ) {
548 $customer = new Customer( $customer );
549
550 return [
551 'id' => $customer->get_id(),
552 'full_name' => $customer->get_display_name(),
553 'first_name' => $customer->get_first_name(),
554 'last_name' => $customer->get_last_name(),
555 'email' => $customer->get_email(),
556 'phone' => $customer->get_phone(),
557 'image' => $customer->get_image(),
558 'total_booking' => $customer->get_total_booking(),
559 ];
560 }
561
562 /**
563 * Get booking list for single customer
564 *
565 * @param integer | customer $customer_id customer Id
566 *
567 * @return array booking data
568 */
569 public function get_bookings( $request ) {
570 $customer_id = (int) $request['customer_id'];
571 $customer = new Customer( $customer_id );
572
573 if ( ! $customer->is_customer() ) {
574 $data = [
575 'status_code' => 404,
576 'message' => esc_html__( 'Invalid customer id.', 'timetics' ),
577 'data' => [],
578 ];
579
580 return new WP_HTTP_Response( $data, 404 );
581 }
582
583 return $this->get_booking_list( $request, $customer_id );
584 }
585
586 /**
587 * Save customer
588 *
589 * @param WP_Rest_Request $request
590 * @param integer $id [$id description]
591 *
592 * @return JSON | WP_Error
593 */
594 public function get_booking_list( $request, $customer_id = 0 ) {
595
596 $per_page = ! empty( $request['per_page'] ) ? intval( $request['per_page'] ) : 20;
597 $paged = ! empty( $request['paged'] ) ? intval( $request['paged'] ) : 1;
598
599 $args = [
600 'post_type' => 'timetics-booking',
601 'posts_per_page' => $per_page,
602 'paged' => $paged,
603 'post_status' => 'any',
604 // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Meta query is necessary for filtering bookings by customer
605 'meta_query' => array(
606 'relation' => 'OR',
607 array(
608 'key' => '_tt_booking_customer',
609 'value' => $customer_id,
610 'compare' => '=',
611 ),
612
613 ),
614 ];
615
616 $bookings = new \WP_Query( $args );
617
618 // Prepare items for response.
619 $items = [];
620 $booking = new Api_Booking();
621
622 foreach ( $bookings->posts as $item ) {
623 $items[] = $booking->prepare_item( $item->ID, false );
624 }
625
626 $data = [
627 'success' => 1,
628 'status' => 200,
629 'data' => [
630 'total' => $bookings->found_posts,
631 'items' => $items,
632 ],
633 ];
634
635 return rest_ensure_response( $data );
636
637 }
638
639 }
640