PluginProbe
Booktics – Appointment Booking Calendar for Service Businesses / 1.0.3
Booktics – Appointment Booking Calendar for Service Businesses v1.0.3
1.0.29 1.0.28 1.0.27 1.0.26 1.0.25 1.0.24 1.0.23 1.0.22 1.0.21 1.0.20 1.0.19 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.2 1.0.3 All 31 releases
booktics / trunk / core / team-member / controllers / team-member-controller.php

team-member-controller.php in Booktics – Appointment Booking Calendar for Service Businesses 1.0.3, at trunk/core/team-member/controllers/team-member-controller.php

588 lines 20.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Booktics\Team_Member\Controllers;
4
5 use Booktics\Abstracts\Base_Rest_Controller;
6 use Booktics\Abstracts\User_Model;
7 use Booktics\Models\Service_Model;
8 use Booktics\Models\Team_Member_Model;
9 use Booktics\Services\Schedule_Manager;
10 use Booktics\Services\Schedule_Record;
11 use Booktics\Team_Member\Handlers\Team_Member_Event_Handler;
12 use Exception;
13 use WP_Error;
14 use WP_HTTP_Response;
15 use WP_REST_Response;
16 use WP_REST_Server;
17
18 /**
19 * Team member controller
20 *
21 * @package Booktics/Team_Member
22 */
23 class Team_Member_Controller extends Base_Rest_Controller {
24
25 /**
26 * Endpoint namespace
27 *
28 * @var string
29 */
30 protected $namespace = 'booktics/v1';
31
32 /**
33 * Route name
34 *
35 * @var string
36 */
37 protected $base = 'team-members';
38
39 /**
40 * Register routes
41 *
42 * @return void
43 */
44 public function register_routes(): void {
45 register_rest_route(
46 $this->namespace, $this->base, array(
47 array(
48 'methods' => WP_REST_Server::CREATABLE,
49 'callback' => array( $this, 'create_item' ),
50 'permission_callback' => array(
51 $this,
52 'create_team_member_permission',
53 ),
54 ),
55 array(
56 'methods' => WP_REST_Server::READABLE,
57 'callback' => array( $this, 'get_items' ),
58 'permission_callback' => array(
59 $this,
60 'get_team_member_permission',
61 ),
62 ),
63 array(
64 'methods' => WP_REST_Server::DELETABLE,
65 'callback' => array( $this, 'delete_items' ),
66 'permission_callback' => array(
67 $this,
68 'delete_team_member_permission',
69 ),
70 ),
71 )
72 );
73
74 register_rest_route(
75 $this->namespace, '/' . $this->base . '/(?P<id>[\d]+)', array(
76 array(
77 'methods' => WP_REST_Server::EDITABLE,
78 'callback' => array( $this, 'update_item' ),
79 'permission_callback' => array(
80 $this,
81 'update_team_member_permission',
82 ),
83 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
84 ),
85 array(
86 'methods' => WP_REST_Server::DELETABLE,
87 'callback' => array( $this, 'delete_item' ),
88 'permission_callback' => array(
89 $this,
90 'delete_team_member_permission',
91 ),
92 ),
93 array(
94 'method' => WP_REST_Server::READABLE,
95 'callback' => array( $this, 'get_item' ),
96 'permission_callback' => array(
97 $this,
98 'get_team_member_permission',
99 ),
100 ),
101 )
102 );
103
104 register_rest_route(
105 $this->namespace, '/' . $this->base . '/(?P<id>[\d]+)/reinvites', array(
106 array(
107 'methods' => WP_REST_Server::READABLE,
108 'callback' => array( $this, 'reinvite' ),
109 'permission_callback' => array(
110 $this,
111 'create_team_member_permission',
112 ),
113 ),
114 )
115 );
116 }
117
118 /**
119 * Check if a given request has access to create items.
120 *
121 * @param $request
122 *
123 * @return mixed
124 */
125 public function create_team_member_permission( $request ) {
126 return current_user_can( 'manage_options' );
127 }
128
129 /**
130 * Prepare and validate team member data
131 *
132 * @param $request
133 *
134 * @return array|bool|WP_Error
135 */
136 protected function prepare_team_member_data( $request ) {
137 $input_data = json_decode( $request->get_body(), true );
138
139 $validate = booktics_validate(
140 $input_data, array(
141 'first_name' => array(
142 'required',
143 ),
144 'email' => array(
145 'required',
146 'unique:wp_users,email',
147 ),
148 )
149 );
150
151 if ( is_wp_error( $validate ) ) {
152 return $validate;
153 }
154
155 return array(
156 'first_name' => $input_data['first_name'],
157 'last_name' => $input_data['last_name'],
158 'user_email' => $input_data['email'],
159 'user_login' => User_Model::generate_username( $input_data['email'] ),
160 'phone' => $input_data['phone'],
161 'email' => $input_data['email'],
162 'status' => 'pending',
163 'enable_custom_holiday' => $input_data['enable_custom_holiday'] ?? false,
164 'enable_custom_schedule' => $input_data['enable_custom_schedule'] ?? false,
165 );
166 }
167
168 /**
169 * Store new team member data
170 *
171 * @param $request
172 *
173 * @return array|WP_Error|WP_HTTP_Response|WP_REST_Response
174 */
175 public function create_item( $request ) {
176 $prepared_data = $this->prepare_team_member_data( $request );
177 if ( is_wp_error( $prepared_data ) ) {
178 return $this->error(
179 $prepared_data->get_error_message(),
180 422,
181 'Validation',
182 $prepared_data->errors
183 );
184 }
185
186 $all_team_members = ( new Team_Member_Model() )->all( array() );
187 if ( ! is_booktics_pro() && isset( $all_team_members['total'] ) && $all_team_members['total'] >= 3 ) {
188 return $this->error(
189 'Team member limit reached for free plan.',
190 422,
191 'Validation'
192 );
193 }
194
195 $team_member = new Team_Member_Model();
196 $created = $team_member->save( $prepared_data );
197
198 $image_url = $request->get_param( 'image' );
199 if ( $image_url ) {
200 $team_member->update( array( 'image' => esc_url_raw( $image_url ) ) );
201 }
202
203 if ( ! $created ) {
204 return $this->error( __( 'Team member create error', 'booktics' ), 500 );
205 }
206
207 do_action( 'booktics_team_member_created', $team_member, $request );
208
209 ( new Team_Member_Event_Handler() )->on_team_member_create( $created );
210
211 return $this->response( $team_member->find( $created )->to_array(), __( 'Successfully created team member', 'booktics' ), 201 );
212 }
213
214 /**
215 * Check if a given request has access to get all team member
216 *
217 * @param $request
218 *
219 * @return bool
220 */
221 public function get_team_member_permission( $request ) {
222 return true;
223 }
224
225 /**
226 * Get paginated list items for team member
227 *
228 * @param $request
229 *
230 * @return WP_Error|WP_HTTP_Response|WP_REST_Response
231 */
232 public function get_items( $request ) {
233 $per_page = ! empty( $request['per_page'] ) ? intval( $request['per_page'] ) : 20;
234 $paged = ! empty( $request['paged'] ) ? intval( $request['paged'] ) : 1;
235 $first_name = ! empty( $request['first_name'] ) ? trim( $request['first_name'] ) : '';
236 $last_name = ! empty( $request['last_name'] ) ? trim( $request['last_name'] ) : '';
237 $email = ! empty( $request['email'] ) ? trim( $request['email'] ) : '';
238 $phone = ! empty( $request['phone'] ) ? trim( $request['phone'] ) : '';
239 $user_name = ! empty( $request['user_name'] ) ? trim( $request['user_name'] ) : '';
240 $status = ! empty( $request['status'] ) ? trim( $request['status'] ) : '';
241 $service_id = ! empty( $request['service_id'] ) ? trim( $request['service_id'] ) : '';
242 $search = ! empty( $request['search'] ) ? trim( $request['search'] ) : '';
243
244 $team_members = ( new Team_Member_Model() )
245 ->when(
246 $first_name, function ( $q, $v ) {
247 $q->where( 'first_name', $v, 'LIKE' );
248 }
249 )
250 ->when(
251 $last_name, function ( $q, $v ) {
252 $q->where( 'last_name', $v, 'LIKE' );
253 }
254 )
255 ->when(
256 $email, function ( $q, $v ) {
257 $q->where( 'user_email', $v, 'LIKE' );
258 }
259 )
260 ->when(
261 $phone, function ( $q, $v ) {
262 $q->where( 'phone', $v, 'LIKE' );
263 }
264 )
265 ->when(
266 $user_name, function ( $q, $v ) {
267 $q->where( 'user_login', $v, 'LIKE' );
268 }
269 )
270 ->when(
271 $service_id, function ( $q, $v ) {
272 $q->where( 'services', $v, 'LIKE' );
273 }
274 )
275 ->when(
276 $status, function ( $q, $v ) {
277 $q->where( 'status', $v, 'LIKE' );
278 }
279 )
280 ->when(
281 $search, function ( $q, $v ) {
282 $q->where( 'first_name', $v, 'LIKE' )
283 ->or_where( 'last_name', $v, 'LIKE' )
284 ->or_where( 'phone', $v, 'LIKE' );
285 }
286 )->all(
287 array(
288 'paged' => $paged,
289 'number' => $per_page,
290 )
291 );
292
293 return $this->response( $team_members );
294 }
295
296 /**
297 * Checks if a given request has access to update a team member.
298 *
299 * @param $request
300 *
301 * @return bool
302 */
303 public function update_team_member_permission( $request ) {
304 return current_user_can( 'manage_options' );
305 }
306
307 /**
308 * Updates a single team member.
309 *
310 * @param $request
311 *
312 * @return array|WP_Error|WP_HTTP_Response|WP_REST_Response
313 * @throws Exception
314 */
315 public function update_item( $request ) {
316 if ( ! isset( $request['id'] ) ) {
317 return $this->error( __( 'Invalid team member id', 'booktics' ), 400 );
318 }
319 $team_member = ( new Team_Member_Model( $request['id'] ) );
320
321 if ( isset( $request['password'] ) ) {
322 $current_password = sanitize_text_field( $request['current_password'] ?? '' );
323 $new_password = sanitize_text_field( $request['password'] ?? '' );
324 $confirm_password = sanitize_text_field( $request['confirm_password'] ?? '' );
325
326 $validate = booktics_validate(
327 array(
328 'current_password' => $current_password,
329 'password' => $new_password,
330 'confirm_password' => $confirm_password,
331 ), array(
332 'current_password' => array( 'required' ),
333 'password' => array( 'required' ),
334 'confirm_password' => array( 'required' ),
335 )
336 );
337
338 if ( is_wp_error( $validate ) ) {
339 return $validate;
340 }
341
342 $user = wp_get_current_user();
343
344 if ( ! wp_check_password( $current_password, $user->user_pass, $user->ID ) ) {
345 return $this->error( __( 'Current password is incorrect.', 'booktics' ), 401 );
346 }
347
348 wp_set_password( $new_password, $user->ID );
349
350 return $this->response(
351 $team_member->find( $request['id'] )->to_array(),
352 __( 'Successfully updated team member', 'booktics' )
353 );
354 }
355
356 $prepared_data = $this->prepare_team_member_update( $request );
357 if ( is_wp_error( $prepared_data ) ) {
358 return $this->error( $prepared_data->get_error_message(), 422, 'Validation', $prepared_data->errors );
359 }
360
361 $updated = $team_member->update( $prepared_data );
362 // First handle adding team member to new services
363 foreach ( $prepared_data['services'] as $service ) {
364 $service_model = Service_Model::find( $service );
365 $service_team_member = $service_model->team_member == '' ? array() : $service_model->team_member;
366 if ( ! in_array( (int) $team_member->id, $service_team_member ) ) {
367 $service_team_member[] = (int) $request['id'];
368 if ( $service_model ) {
369 $service_model->update( array( 'team_member' => $service_team_member ) );
370 }
371 }
372 }
373
374 // Then remove team member from services they're no longer assigned to
375 $services = Service_Model::query()
376 ->where( 'team_member', $request['id'], 'LIKE' )
377 ->where_not_ids( $prepared_data['services'] )
378 ->get();
379
380 foreach ( $services as $service ) {
381 if ( $service->team_member ) {
382 $service_team_members = array_diff( $service->team_member, array( (int) $request['id'] ) );
383 Service_Model::find( $service->id )->update( array( 'team_member' => $service_team_members ) );
384 }
385 }
386 $image_url = $request->get_param( 'image' );
387 if ( $image_url ) {
388 $team_member->update( array( 'image' => esc_url_raw( $image_url ) ) );
389 }
390
391 if ( ! $updated ) {
392 return $this->error( __( 'Team member update error', 'booktics' ), 500 );
393 }
394 if ( isset( $request['schedule'] ) || isset( $request['custom'] ) || isset( $request['holiday'] ) ) {
395 $input_data = json_decode( $request->get_body(), true );
396 $team_member_schedule = Schedule_Manager::make( $input_data );
397 $team_member_schedule->with_team_member_id( $request['id'] );
398 $team_member_schedule->save();
399 }
400
401 do_action( 'booktics_team_member_updated', $team_member, $request );
402
403 $team_member = $team_member->find( $request['id'] )->to_array();
404 $schedule_record = ( new Schedule_Record() )->get_schedules( $request['id'] );
405 $team_member['schedule'] = empty( $schedule_record['schedule'] )
406 ? (object) array() : $schedule_record['schedule'];
407 $team_member['custom'] = $schedule_record['custom'];
408 $team_member['holiday'] = $schedule_record['holiday'];
409
410 return $this->response(
411 $team_member,
412 __( 'Successfully updated team member', 'booktics' )
413 );
414 }
415
416 /**
417 * Prepare data for team member update
418 *
419 * @param $request
420 *
421 * @return array|bool|WP_Error
422 */
423 public function prepare_team_member_update( $request ) {
424 $input_data = json_decode( $request->get_body(), true );
425 $validation_rules = array(
426 'first_name' => array(
427 'required',
428 ),
429 'email' => array(
430 'required',
431 'unique:wp_users,email,' . $request['id'],
432 ),
433 );
434 $update_validation_rules = array();
435 $validated_data = array();
436 foreach ( $input_data as $key => $value ) {
437 $validated_data[ $key ] = $value;
438 if ( ! isset( $validation_rules[ $key ] ) ) {
439 continue;
440 }
441 $update_validation_rules[ $key ] = $validation_rules[ $key ];
442 if ( $key == 'email' ) {
443 $update_validation_rules[ $key ] = $validation_rules[ $key ];
444 $validated_data['user_email'] = sanitize_email( $value );
445 }
446 }
447 $validate = booktics_validate( $input_data, $update_validation_rules );
448
449 if ( is_wp_error( $validate ) ) {
450 return $validate;
451 }
452
453 $validated_data['services'] = ! empty( $input_data['services'] ) ? $input_data['services'] : array();
454 $validated_data['status'] = 'active';
455
456 return $validated_data;
457 }
458
459 /**
460 * Checks if a given request has access to delete a team member.
461 *
462 * @param $request
463 *
464 * @return bool
465 */
466 public function delete_team_member_permission( $request ) {
467 return current_user_can( 'manage_options' );
468 }
469
470 /**
471 * Delete a team member
472 *
473 * @param $request
474 *
475 * @return array|WP_Error|WP_HTTP_Response|WP_REST_Response
476 */
477 public function delete_item( $request ) {
478 $id = intval( $request['id'] );
479
480 $team_member = new Team_Member_Model( $id );
481 $previous = $team_member->find( $id );
482
483 // Remove team member from assigned services
484 $services = Service_Model::query()->where( 'team_member', $id, 'LIKE' )->get();
485 foreach ( $services as $service ) {
486 if ( $service->team_member ) {
487 $service_team_members = array_diff( $service->team_member, array( $id ) );
488 Service_Model::find( $service->id )->update( array( 'team_member' => $service_team_members ) );
489 }
490 }
491
492 $deleted = $team_member->delete();
493
494 if ( ! $deleted ) {
495 return $this->error( __( 'Team member delete error', 'booktics' ), 500 );
496 }
497
498 do_action( 'booktics_team_members_deleted', $request );
499
500 return $this->response( $previous, __( 'Successfully deleted team member', 'booktics' ) );
501 }
502
503 /**
504 * Delete multiple team member
505 *
506 * @param $request
507 *
508 * @return array|WP_Error|WP_HTTP_Response
509 */
510 public function delete_items( $request ) {
511 $ids = ! empty( $request['ids'] ) ? $request['ids'] : array();
512
513 if ( ! $ids ) {
514 return $this->error( __( 'Team member ids cannot be empty', 'booktics' ), 500 );
515 }
516 $count = 0;
517 foreach ( $ids as $id ) {
518 $team_member = new Team_Member_Model( $id );
519 if ( $team_member->delete() ) {
520 ++$count;
521 }
522 }
523 if ( $count == 0 ) {
524 return $this->error( __( 'Team member delete error', 'booktics' ), 500 );
525 }
526
527 do_action( 'booktics_team_members_deleted', $request );
528
529 return $this->response( array(), __( 'Successfully deleted team member', 'booktics' ) );
530 }
531
532 /**
533 * Get single team member
534 *
535 * @param $request
536 *
537 * @return array|WP_Error|WP_HTTP_Response|WP_REST_Response
538 */
539 public function get_item( $request ) {
540 $id = intval( $request['id'] );
541 $team_member = new Team_Member_Model( $id );
542 $team_member = $team_member->find( $id );
543 if ( ! $team_member ) {
544 return $this->error( __( 'Team member not found', 'booktics' ), 404 );
545 }
546 $team_member = $team_member->to_array();
547 $schedule_record = ( new Schedule_Record() )->get_schedules( $request['id'] );
548 $team_member['schedule'] = ! empty( $schedule_record['schedule'] ) ? $schedule_record['schedule'] : $team_member['schedule'];
549 $team_member['custom'] = ! empty( $schedule_record['custom'] ) ? $schedule_record['custom'] : $team_member['custom'];
550 $team_member['holiday'] = ! empty( $schedule_record['holiday'] ) ? $schedule_record['holiday'] : $team_member['holiday'];
551
552 // Add filter to allow modifying team member data
553 $team_member = apply_filters( 'booktics_team_member_data', $team_member, $id );
554
555 return $this->response( $team_member, __( 'Team member successfully fetched', 'booktics' ) );
556 }
557
558 /**
559 * Check if a given request has access to create items.
560 *
561 * @param $request
562 *
563 * @return mixed
564 */
565 public function create_team_member_schedule_permission( $request ) {
566 return current_user_can( 'manage_options' );
567 }
568
569 /**
570 * Team member reinvite
571 *
572 * @param $request
573 *
574 * @return array|WP_HTTP_Response
575 */
576 public function reinvite( $request ) {
577 $id = intval( $request['id'] );
578
579 $invite = ( new Team_Member_Event_Handler() )->on_team_member_create( $id );
580
581 if ( ! $invite ) {
582 return $this->error( __( 'Team member reinvite error', 'booktics' ) );
583 }
584
585 return $this->response( array(), __( 'Team member reinvited successfully', 'booktics' ) );
586 }
587 }
588