\WP_REST_Server::READABLE, 'callback' => [ $this, 'index' ], 'permission_callback' => [ $this, 'canBook' ], 'args' => [ 'instructor_id' => [ 'type' => 'integer', 'default' => 0, ], 'offering_id' => [ 'type' => 'integer', 'default' => 0, ], 'duration_minutes' => [ 'type' => 'integer', 'default' => 0, ], 'from' => [ 'type' => 'string', 'default' => '', ], 'to' => [ 'type' => 'string', 'default' => '', ], ], ], [ 'methods' => \WP_REST_Server::CREATABLE, 'callback' => [ $this, 'create' ], 'permission_callback' => [ $this, 'canManage' ], 'args' => [ 'start_dt' => [ 'type' => 'string', 'required' => true, 'sanitize_callback' => 'sanitize_text_field', ], 'end_dt' => [ 'type' => 'string', 'required' => true, 'sanitize_callback' => 'sanitize_text_field', ], 'duration_minutes' => [ 'type' => 'integer', 'default' => 60, ], 'offering_id' => [ 'type' => 'integer', 'default' => 0, ], 'recurrence' => [ 'type' => 'string', 'default' => 'single', ], 'weeks' => [ 'type' => 'integer', 'default' => 1, ], ], ], ] ); register_rest_route( $route_namespace, '/availability/(?P\d+)', [ [ 'methods' => \WP_REST_Server::DELETABLE, 'callback' => [ $this, 'delete' ], 'permission_callback' => [ $this, 'canManage' ], ], ] ); } public function index( \WP_REST_Request $request ): \WP_REST_Response { $slots = $this->repository->findAvailable( (int) $request->get_param( 'instructor_id' ), (int) $request->get_param( 'offering_id' ), (int) $request->get_param( 'duration_minutes' ), (string) $request->get_param( 'from' ), (string) $request->get_param( 'to' ), ); return new \WP_REST_Response( array_map( fn( AvailabilitySlot $s ) => $s->toArray(), $slots ), 200 ); } public function create( \WP_REST_Request $request ): \WP_REST_Response { $offeringId = absint( $request->get_param( 'offering_id' ) ); $duration = absint( $request->get_param( 'duration_minutes' ) ); $slot = new AvailabilitySlot( instructorId: get_current_user_id(), startDt: (string) $request->get_param( 'start_dt' ), endDt: (string) $request->get_param( 'end_dt' ), durationMinutes: $duration > 0 ? $duration : 60, offeringId: $offeringId > 0 ? $offeringId : null, ); if ( 'weekly' === $request->get_param( 'recurrence' ) ) { $ids = $this->repository->createWeeklySeries( $slot, absint( $request->get_param( 'weeks' ) ) ); return new \WP_REST_Response( [ 'ids' => $ids ], 201 ); } $id = $this->repository->insert( $slot ); return new \WP_REST_Response( [ 'id' => $id ], 201 ); } public function delete( \WP_REST_Request $request ): \WP_REST_Response|\WP_Error { $id = absint( $request->get_param( 'id' ) ); $slot = $this->repository->findById( $id ); if ( null === $slot ) { return new \WP_Error( 'not_found', __( 'Slot not found.', 'unsupervised-schedular' ), [ 'status' => 404 ] ); } if ( get_current_user_id() !== $slot->instructorId ) { return new \WP_Error( 'forbidden', __( 'You cannot delete this slot.', 'unsupervised-schedular' ), [ 'status' => 403 ] ); } if ( $slot->isBooked ) { return new \WP_Error( 'slot_booked', __( 'Cannot delete a booked slot.', 'unsupervised-schedular' ), [ 'status' => 409 ] ); } $this->repository->delete( $id ); return new \WP_REST_Response( null, 204 ); } public function canBook(): bool { return is_user_logged_in() && current_user_can( RoleManager::CAP_BOOK_LESSON ); } public function canManage(): bool { return is_user_logged_in() && current_user_can( RoleManager::CAP_MANAGE_AVAILABILITY ); } }