PluginProbe
Booking Calendar / 11.9
Booking Calendar v11.9
11.9 11.8.4 11.8.3 11.8.2 11.8.1 11.8 11.7 11.6.1 11.6 11.5 11.4.3 11.4.2 11.4.1 11.4 11.3 11.2.1 11.2 11.1 11.0 10.15.7 10.15.6 10.1.3 10.10 10.10.1 10.10.2 All 205 releases
booking / includes / page-catalog-booking-resources / ajax / booking-resources-list.php

booking-resources-list.php in Booking Calendar 11.9, at includes/page-catalog-booking-resources/ajax/booking-resources-list.php

217 lines 8.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Read-only list endpoint for the independent Booking Resources catalog.
4 *
5 * @package Booking Calendar
6 * @since 11.6.0
7 */
8
9 if ( ! defined( 'ABSPATH' ) ) {
10 exit;
11 }
12
13 /**
14 * Send a normalized catalog error without exposing internal diagnostics.
15 *
16 * @param int $request_id Client request sequence when safely available.
17 * @param WP_Error $error Safe WordPress error.
18 * @param int $status HTTP status code.
19 * @param bool $retryable Whether the browser may retry the request.
20 *
21 * @return void Terminates the AJAX request with JSON.
22 */
23 function wpbc_catalog_booking_resources_send_list_error( $request_id, $error, $status, $retryable = false ) {
24 wp_send_json(
25 WPBC_UI_Catalog_Response::from_wp_error(
26 'catalog_booking_resources',
27 $request_id,
28 $error,
29 $retryable
30 ),
31 absint( $status )
32 );
33 }
34
35 /**
36 * Return the client request sequence without trusting any other request data.
37 *
38 * @param mixed $request_values Untrusted request payload.
39 *
40 * @return int Non-negative request sequence or zero.
41 */
42 function wpbc_catalog_booking_resources_get_list_request_id( $request_values ) {
43 if ( ! is_array( $request_values ) || ! isset( $request_values['request_id'] ) || ! is_scalar( $request_values['request_id'] ) ) {
44 return 0;
45 }
46
47 return preg_match( '/^\d+$/', (string) $request_values['request_id'] ) ? (int) $request_values['request_id'] : 0;
48 }
49
50 /**
51 * Serve an authorized normalized Booking Resources list response.
52 *
53 * The endpoint owns transport authorization only. Shared and domain request
54 * objects validate input, the repository owns SQL/visibility, the DTO owns the
55 * JSON item contract, and no layer produces row HTML.
56 *
57 * @return void Terminates the AJAX request with JSON.
58 */
59 function wpbc_catalog_booking_resources_ajax_list() {
60 $registry = WPBC_UI_Catalog_Registry::get_instance();
61 $configuration = $registry->get_configuration( 'catalog_booking_resources' );
62 if ( empty( $configuration ) ) {
63 wpbc_catalog_booking_resources_send_list_error(
64 0,
65 new WP_Error( 'wpbc_catalog_booking_resources_unavailable', __( 'The Booking Resources catalog is unavailable.', 'booking' ) ),
66 503,
67 true
68 );
69 }
70
71 // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Verified immediately below using the registered nonce action.
72 $raw_request = is_array( $_POST ) ? wp_unslash( $_POST ) : array();
73 $request_id = wpbc_catalog_booking_resources_get_list_request_id( $raw_request );
74
75 if ( false === check_ajax_referer( $configuration['nonce_name'], 'nonce', false ) ) {
76 wpbc_catalog_booking_resources_send_list_error(
77 $request_id,
78 new WP_Error( 'wpbc_catalog_booking_resources_invalid_nonce', __( 'Security check failed.', 'booking' ) ),
79 403
80 );
81 }
82
83 if ( ! current_user_can( wpbc_catalog_booking_resources_get_manage_capability() ) ) {
84 wpbc_catalog_booking_resources_send_list_error(
85 $request_id,
86 new WP_Error( 'wpbc_catalog_booking_resources_forbidden', __( 'You do not have permission to view Booking Resources.', 'booking' ) ),
87 403
88 );
89 }
90
91 $preference_action = isset( $raw_request['preference_action'] ) && is_scalar( $raw_request['preference_action'] )
92 ? sanitize_key( (string) $raw_request['preference_action'] )
93 : '';
94 if ( ! in_array( $preference_action, array( '', 'save', 'reset' ), true ) ) {
95 wpbc_catalog_booking_resources_send_list_error(
96 $request_id,
97 new WP_Error( 'wpbc_catalog_booking_resources_invalid_preference_action', __( 'The catalog preference request is invalid.', 'booking' ) ),
98 400
99 );
100 }
101 $has_preference_revision = isset( $raw_request['preference_revision'] )
102 && is_scalar( $raw_request['preference_revision'] )
103 && preg_match( '/^\d+$/', (string) $raw_request['preference_revision'] );
104 $preference_revision = $has_preference_revision
105 ? ltrim( (string) $raw_request['preference_revision'], '0' )
106 : '0';
107 $preference_revision = '' === $preference_revision ? '0' : $preference_revision;
108 if ( '' !== $preference_action && '0' === $preference_revision ) {
109 wpbc_catalog_booking_resources_send_list_error(
110 $request_id,
111 new WP_Error( 'wpbc_catalog_booking_resources_invalid_preference_revision', __( 'The catalog preference request is invalid.', 'booking' ) ),
112 400
113 );
114 }
115 if (
116 isset( $raw_request['preferences_only'] )
117 && ( ! is_scalar( $raw_request['preferences_only'] ) || ! in_array( (string) $raw_request['preferences_only'], array( '0', '1' ), true ) )
118 ) {
119 wpbc_catalog_booking_resources_send_list_error(
120 $request_id,
121 new WP_Error( 'wpbc_catalog_booking_resources_invalid_preference_request', __( 'The catalog preference request is invalid.', 'booking' ) ),
122 400
123 );
124 }
125 $preferences_only = isset( $raw_request['preferences_only'] ) && '1' === (string) $raw_request['preferences_only'];
126 if ( $preferences_only && 'save' !== $preference_action ) {
127 wpbc_catalog_booking_resources_send_list_error(
128 $request_id,
129 new WP_Error( 'wpbc_catalog_booking_resources_invalid_preference_request', __( 'The catalog preference request is invalid.', 'booking' ) ),
130 400
131 );
132 }
133 if ( 'reset' === $preference_action ) {
134 $preference_reset = WPBC_UI_Catalog_Preferences::reset( 'catalog_booking_resources', 0, $preference_revision );
135 if ( ! $preference_reset ) {
136 wpbc_catalog_booking_resources_send_list_error(
137 $request_id,
138 new WP_Error( 'wpbc_catalog_booking_resources_preference_reset_failed', __( 'The catalog preferences could not be reset.', 'booking' ) ),
139 500,
140 true
141 );
142 }
143 }
144 $stored_preferences = WPBC_UI_Catalog_Preferences::load( 'catalog_booking_resources' );
145
146 $shared_keys = array(
147 'request_id',
148 'page_number',
149 'items_per_page',
150 'sort_by',
151 'sort_order',
152 'search',
153 'visible_columns',
154 'column_order',
155 'template_pack',
156 );
157 $shared_values = array_intersect_key( $raw_request, array_fill_keys( $shared_keys, true ) );
158 $request = WPBC_UI_Catalog_Request::create( $configuration, $shared_values, $stored_preferences );
159 if ( is_wp_error( $request ) ) {
160 wpbc_catalog_booking_resources_send_list_error( $request_id, $request, 400 );
161 }
162
163 $stored_resource_values = array_intersect_key( $stored_preferences, array( 'resource_type' => true, 'hierarchy_state' => true ) );
164 $stored_resource_request = WPBC_Catalog_Booking_Resources_Request::create( $stored_resource_values );
165 if ( is_wp_error( $stored_resource_request ) ) {
166 $stored_resource_request = WPBC_Catalog_Booking_Resources_Request::create();
167 }
168 $resource_values = array(
169 'resource_type' => $stored_resource_request->get( 'resource_type', 'all' ),
170 'hierarchy_state' => $stored_resource_request->get( 'hierarchy_state', array() ),
171 );
172 foreach ( array( 'resource_type', 'hierarchy_state' ) as $resource_key ) {
173 if ( array_key_exists( $resource_key, $raw_request ) ) {
174 $resource_values[ $resource_key ] = $raw_request[ $resource_key ];
175 }
176 }
177 $resource_request = WPBC_Catalog_Booking_Resources_Request::create( $resource_values );
178 if ( is_wp_error( $resource_request ) ) {
179 wpbc_catalog_booking_resources_send_list_error( $request_id, $resource_request, 400 );
180 }
181 if ( 'save' === $preference_action ) {
182 $preference_result = WPBC_UI_Catalog_Preferences::save(
183 'catalog_booking_resources',
184 $request,
185 array(
186 'resource_type' => $resource_request->get( 'resource_type', 'all' ),
187 'hierarchy_state' => $resource_request->get_hierarchy_state_json(),
188 ),
189 0,
190 $preference_revision
191 );
192 if ( is_wp_error( $preference_result ) ) {
193 wpbc_catalog_booking_resources_send_list_error( $request_id, $preference_result, 400 );
194 }
195 }
196 if ( $preferences_only ) {
197 wp_send_json(
198 array(
199 'success' => true,
200 'request_id' => $request_id,
201 ),
202 200
203 );
204 }
205
206 $repository = new WPBC_Catalog_Booking_Resources_Repository();
207 $provider = new WPBC_Catalog_Booking_Resources_Provider( $repository, null, $resource_request );
208 $response = $provider->get_response( $request );
209 if ( is_wp_error( $response ) ) {
210 $is_retryable = 'wpbc_catalog_booking_resources_query_failed' === $response->get_error_code();
211 wpbc_catalog_booking_resources_send_list_error( $request_id, $response, $is_retryable ? 500 : 400, $is_retryable );
212 }
213
214 wp_send_json( $response->to_array(), 200 );
215 }
216 add_action( 'wp_ajax_WPBC_AJX_CATALOG_BOOKING_RESOURCES_LIST', 'wpbc_catalog_booking_resources_ajax_list' );
217