PluginProbe
Easy Hotel – Powerful Hotel Booking / 2.0.2
Easy Hotel – Powerful Hotel Booking v2.0.2
2.0.8 2.0.7 2.0.6 2.0.5 2.0.4 2.0.3 2.0.2 2.0.1 2.0.0 1.9.9 1.9.8 1.9.7 1.9.6 1.9.5 1.9.4 1.9.3 1.9.2 1.8.1 1.8.2 1.8.3 1.8.4 1.8.5 1.8.6 1.8.7 1.8.8 All 110 releases
easy-hotel / admin / includes / native-checkout / account / class-account-ajax.php

class-account-ajax.php in Easy Hotel – Powerful Hotel Booking 2.0.2, at admin/includes/native-checkout/account/class-account-ajax.php

185 lines 7.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * AJAX endpoints for the Native Checkout account area.
4 *
5 * Every endpoint is logged-in only, nonce-verified, and re-checks
6 * ownership server-side — client-supplied booking ids are never trusted.
7 *
8 * @package EasyHotel\NativeCheckout\Account
9 */
10
11 if ( ! defined( 'ABSPATH' ) ) exit;
12
13 class ESHB_Native_Account_Ajax {
14
15 /** @var ESHB_Native_Account_Customer */
16 private $customer;
17
18 /** @var ESHB_Native_Account_Bookings */
19 private $bookings;
20
21 public function __construct( ESHB_Native_Account_Customer $customer, ESHB_Native_Account_Bookings $bookings ) {
22 $this->customer = $customer;
23 $this->bookings = $bookings;
24
25 // Logged-in only — no nopriv handlers on purpose.
26 add_action( 'wp_ajax_eshb_native_account_view_booking', [ $this, 'view_booking' ] );
27 add_action( 'wp_ajax_eshb_native_account_cancel_booking',[ $this, 'cancel_booking' ] );
28 add_action( 'wp_ajax_eshb_native_account_update_profile',[ $this, 'update_profile' ] );
29 add_action( 'wp_ajax_eshb_native_account_change_password',[ $this, 'change_password' ] );
30 }
31
32 /**
33 * Verify nonce + login. Sends a JSON error and dies on failure.
34 */
35 private function guard() {
36 if ( ! is_user_logged_in() ) {
37 wp_send_json_error( [ 'message' => __( 'Please log in to continue.', 'easy-hotel' ) ] );
38 }
39 if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'eshb_native_account' ) ) {
40 wp_send_json_error( [ 'message' => __( 'Security check failed. Please refresh the page.', 'easy-hotel' ) ] );
41 }
42 }
43
44 /**
45 * Read a booking id from the request and confirm the current user owns
46 * it. Sends a JSON error and dies when not.
47 */
48 private function require_owned_booking() {
49 // phpcs:ignore WordPress.Security.NonceVerification.Missing
50 $booking_id = isset( $_POST['booking_id'] ) ? absint( wp_unslash( $_POST['booking_id'] ) ) : 0;
51 if ( ! $booking_id || ! $this->customer->user_owns_booking( $booking_id ) ) {
52 wp_send_json_error( [ 'message' => __( 'Booking not found.', 'easy-hotel' ) ] );
53 }
54 return $booking_id;
55 }
56
57 /* -----------------------------------------------------------------
58 * Endpoints
59 * -------------------------------------------------------------- */
60
61 /**
62 * Return the booking-detail HTML for the modal.
63 */
64 public function view_booking() {
65 $this->guard();
66 $booking_id = $this->require_owned_booking();
67
68 $detail = $this->bookings->get_detail_view( $booking_id );
69 if ( empty( $detail ) ) {
70 wp_send_json_error( [ 'message' => __( 'Booking not found.', 'easy-hotel' ) ] );
71 }
72
73 ob_start();
74 ESHB_Native_Account::instance()->render_template( 'booking-view.php', [ 'b' => $detail ] );
75 $html = ob_get_clean();
76
77 wp_send_json_success( [ 'html' => $html ] );
78 }
79
80 /**
81 * Cancel a booking owned by the current user.
82 */
83 public function cancel_booking() {
84 $this->guard();
85 $booking_id = $this->require_owned_booking();
86
87 $can = $this->bookings->can_cancel_booking( $booking_id, true );
88 if ( is_wp_error( $can ) ) {
89 wp_send_json_error( [ 'message' => $can->get_error_message() ] );
90 }
91
92 // phpcs:disable WordPress.Security.NonceVerification.Missing
93 $reason_choice = isset( $_POST['reason'] ) ? sanitize_text_field( wp_unslash( $_POST['reason'] ) ) : '';
94 $reason_custom = isset( $_POST['reason_custom'] ) ? sanitize_textarea_field( wp_unslash( $_POST['reason_custom'] ) ) : '';
95 // phpcs:enable WordPress.Security.NonceVerification.Missing
96 $reason = ( 'other' === $reason_choice && $reason_custom !== '' ) ? $reason_custom : $reason_choice;
97
98 $result = $this->bookings->process_cancellation( $booking_id, $reason, 'customer' );
99 if ( is_wp_error( $result ) ) {
100 wp_send_json_error( [ 'message' => $result->get_error_message() ] );
101 }
102
103 $row = $this->bookings->get_row_view( $booking_id );
104 wp_send_json_success( [
105 'message' => __( 'Your booking has been cancelled.', 'easy-hotel' ),
106 'status' => $row['status'] ?? 'cancelled',
107 'status_label' => $row['status_label'] ?? __( 'Cancelled', 'easy-hotel' ),
108 ] );
109 }
110
111 /**
112 * Update the current user's profile fields.
113 */
114 public function update_profile() {
115 $this->guard();
116 $user_id = get_current_user_id();
117
118 // phpcs:disable WordPress.Security.NonceVerification.Missing
119 $first = isset( $_POST['first_name'] ) ? sanitize_text_field( wp_unslash( $_POST['first_name'] ) ) : '';
120 $last = isset( $_POST['last_name'] ) ? sanitize_text_field( wp_unslash( $_POST['last_name'] ) ) : '';
121 $display = isset( $_POST['display_name'] ) ? sanitize_text_field( wp_unslash( $_POST['display_name'] ) ) : '';
122 $email = isset( $_POST['email'] ) ? sanitize_email( wp_unslash( $_POST['email'] ) ) : '';
123 // phpcs:enable WordPress.Security.NonceVerification.Missing
124
125 if ( '' === $email || ! is_email( $email ) ) {
126 wp_send_json_error( [ 'message' => __( 'Please enter a valid email address.', 'easy-hotel' ) ] );
127 }
128 // Reject an email already used by a different account.
129 $existing = get_user_by( 'email', $email );
130 if ( $existing && (int) $existing->ID !== (int) $user_id ) {
131 wp_send_json_error( [ 'message' => __( 'That email address is already in use.', 'easy-hotel' ) ] );
132 }
133 if ( '' === $display ) {
134 $display = trim( $first . ' ' . $last );
135 }
136
137 $result = wp_update_user( [
138 'ID' => $user_id,
139 'first_name' => $first,
140 'last_name' => $last,
141 'display_name' => $display,
142 'user_email' => $email,
143 ] );
144 if ( is_wp_error( $result ) ) {
145 wp_send_json_error( [ 'message' => $result->get_error_message() ] );
146 }
147
148 wp_send_json_success( [ 'message' => __( 'Your details have been saved.', 'easy-hotel' ) ] );
149 }
150
151 /**
152 * Change the current user's password after verifying the current one.
153 */
154 public function change_password() {
155 $this->guard();
156 $user = wp_get_current_user();
157
158 // phpcs:disable WordPress.Security.NonceVerification.Missing
159 $current = isset( $_POST['current_password'] ) ? (string) wp_unslash( $_POST['current_password'] ) : '';
160 $new = isset( $_POST['new_password'] ) ? (string) wp_unslash( $_POST['new_password'] ) : '';
161 $confirm = isset( $_POST['confirm_password'] ) ? (string) wp_unslash( $_POST['confirm_password'] ) : '';
162 // phpcs:enable WordPress.Security.NonceVerification.Missing
163
164 if ( '' === $current || '' === $new || '' === $confirm ) {
165 wp_send_json_error( [ 'message' => __( 'Please fill in all password fields.', 'easy-hotel' ) ] );
166 }
167 if ( ! wp_check_password( $current, $user->user_pass, $user->ID ) ) {
168 wp_send_json_error( [ 'message' => __( 'Your current password is incorrect.', 'easy-hotel' ) ] );
169 }
170 if ( $new !== $confirm ) {
171 wp_send_json_error( [ 'message' => __( 'New password and confirmation do not match.', 'easy-hotel' ) ] );
172 }
173 if ( strlen( $new ) < 6 ) {
174 wp_send_json_error( [ 'message' => __( 'Password must be at least 6 characters.', 'easy-hotel' ) ] );
175 }
176
177 wp_set_password( $new, $user->ID );
178
179 wp_send_json_success( [
180 'message' => __( 'Password updated. Please log in again.', 'easy-hotel' ),
181 'redirect' => wp_login_url( ESHB_Native_Account::instance()->get_account_url() ),
182 ] );
183 }
184 }
185