PluginProbe ʕ •ᴥ•ʔ
Appointment Booking Plugin – LatePoint | Calendar & Scheduling for WordPress / 5.2.10
Appointment Booking Plugin – LatePoint | Calendar & Scheduling for WordPress v5.2.10
5.6.11 5.6.10 5.6.9 5.6.8 5.6.7 5.6.6 5.6.5 5.6.4 5.6.3 5.6.2 5.6.1 5.6.0 5.5.2 5.5.1 5.5.0 5.4.2 trunk 5.1.0 5.1.1 5.1.2 5.1.3 5.1.4 5.1.5 5.1.6 5.1.7 5.1.8 5.1.9 5.1.91 5.1.92 5.1.93 5.1.94 5.2.0 5.2.1 5.2.10 5.2.11 5.2.2 5.2.3 5.2.4 5.2.5 5.2.6 5.2.7 5.2.8 5.2.9 5.3.0 5.3.1 5.3.2 5.4.0 5.4.1
latepoint / lib / helpers / auth_helper.php
latepoint / lib / helpers Last commit date
activities_helper.php 1 year ago agent_helper.php 1 year ago analytics_helper.php 6 months ago auth_helper.php 6 months ago blocks_helper.php 1 year ago booking_helper.php 6 months ago bricks_helper.php 1 year ago bundles_helper.php 1 year ago calendar_helper.php 11 months ago carts_helper.php 1 year ago connector_helper.php 11 months ago csv_helper.php 6 months ago customer_helper.php 6 months ago customer_import_helper.php 6 months ago database_helper.php 11 months ago debug_helper.php 1 year ago defaults_helper.php 1 year ago elementor_helper.php 1 year ago email_helper.php 11 months ago encrypt_helper.php 1 year ago events_helper.php 11 months ago form_helper.php 6 months ago icalendar_helper.php 1 year ago image_helper.php 1 year ago invoices_helper.php 6 months ago license_helper.php 1 year ago location_helper.php 1 year ago marketing_systems_helper.php 1 year ago meeting_systems_helper.php 1 year ago menu_helper.php 11 months ago meta_helper.php 6 months ago migrations_helper.php 1 year ago money_helper.php 6 months ago notifications_helper.php 11 months ago nps_survey_helper.php 6 months ago order_intent_helper.php 11 months ago orders_helper.php 1 year ago otp_helper.php 11 months ago pages_helper.php 1 year ago params_helper.php 1 year ago payments_helper.php 1 year ago price_breakdown_helper.php 1 year ago process_jobs_helper.php 1 year ago processes_helper.php 1 year ago replacer_helper.php 1 year ago resource_helper.php 1 year ago roles_helper.php 8 months ago router_helper.php 1 year ago service_helper.php 1 year ago sessions_helper.php 6 months ago settings_helper.php 6 months ago short_links_systems_helper.php 11 months ago shortcodes_helper.php 11 months ago sms_helper.php 1 year ago steps_helper.php 6 months ago stripe_connect_helper.php 11 months ago styles_helper.php 11 months ago support_topics_helper.php 1 year ago time_helper.php 11 months ago timeline_helper.php 11 months ago transaction_helper.php 6 months ago transaction_intent_helper.php 1 year ago util_helper.php 8 months ago version_specific_updates_helper.php 11 months ago whatsapp_helper.php 1 year ago work_periods_helper.php 7 months ago wp_datetime.php 1 year ago wp_user_helper.php 1 year ago
auth_helper.php
824 lines
1 <?php
2
3 class OsAuthHelper {
4
5 public static ?\LatePoint\Misc\User $current_user = null;
6 public static $logged_in_customer_id = false;
7
8 private static int $max_login_attempts_per_contact = 20;
9 private static int $max_login_attempts_per_ip = 20;
10 private static int $login_lockout_minutes = 5;
11
12 public static function set_current_user() {
13 if ( \OsWpUserHelper::is_user_logged_in() ) {
14 // if wp user is logged in - load from it
15 self::$current_user = \LatePoint\Misc\User::load_from_wp_user( \OsWpUserHelper::get_current_user() );
16 } else {
17 self::$current_user = new \LatePoint\Misc\User();
18 }
19 $customer = self::get_logged_in_customer();
20 if ( $customer ) {
21 self::$current_user->customer = $customer;
22 }
23 }
24
25 public static function get_current_user(): \LatePoint\Misc\User {
26 if ( ! self::$current_user ) {
27 self::set_current_user();
28 }
29
30 return self::$current_user;
31 }
32
33 public static function get_highest_current_user_id() {
34 $user_id = false;
35 switch ( self::get_highest_current_user_type() ) {
36 case LATEPOINT_USER_TYPE_ADMIN:
37 case LATEPOINT_USER_TYPE_CUSTOM:
38 $user_id = self::get_logged_in_wp_user_id();
39 break;
40 case LATEPOINT_USER_TYPE_AGENT:
41 $user_id = self::get_logged_in_agent_id();
42 break;
43 case LATEPOINT_USER_TYPE_CUSTOMER:
44 $user_id = self::get_logged_in_customer_id();
45 break;
46 }
47
48 return $user_id;
49 }
50
51 public static function get_admin_or_agent_avatar_url() {
52 $avatar_url = LATEPOINT_DEFAULT_AVATAR_URL;
53 if ( self::is_agent_logged_in() ) {
54 $agent = self::get_logged_in_agent();
55 $avatar_url = $agent->get_avatar_url();
56 } elseif ( self::get_logged_in_wp_user_id() ) {
57 $wp_user = self::get_logged_in_wp_user();
58 $avatar_url = get_avatar_url( $wp_user->user_email );
59 }
60
61 return $avatar_url;
62 }
63
64 public static function get_highest_current_user_type() {
65 // check if WP admin is logged in
66 $user_type = false;
67 if ( self::get_current_user()->backend_user_type ) {
68 // backend user, admin, agent or custom role
69 return self::get_current_user()->backend_user_type;
70 } elseif ( self::get_current_user()->customer ) {
71 // customer
72 return LATEPOINT_USER_TYPE_CUSTOMER;
73 }
74
75 return $user_type;
76 }
77
78
79 public static function login_wp_user( $user ) {
80 clean_user_cache( $user->ID );
81 wp_set_current_user( $user->ID );
82 wp_set_auth_cookie( $user->ID );
83 update_user_caches( $user );
84 }
85
86 public static function login_customer( $contact_value, $password, $contact_type = 'email' ) {
87 if ( empty( $contact_value ) || empty( $password ) || ! in_array( $contact_type, self::get_enabled_contact_types_for_customer_auth() ) ) {
88 return false;
89 }
90 $available_contact_types = OsAuthHelper::get_available_contact_types_for_customer_auth();
91 if ( ! isset( $available_contact_types[ $contact_type ] ) ) {
92 return false;
93 }
94
95 if ( ! self::check_login_rate_limit( $contact_value, $contact_type ) ) {
96 return false;
97 }
98
99 if ( self::can_wp_users_login_as_customers() ) {
100 // if WP users enabled - customers can only login using existing password of the wordpress account
101 $wp_user_id = false;
102 if ( $contact_type == 'email' ) {
103 $email = sanitize_email( $contact_value );
104 $wp_user_id = email_exists( $email );
105 } elseif ( $contact_type == 'phone' ) {
106 $phone = OsUtilHelper::sanitize_phone_number( $contact_value );
107 // find latepoint customer by phone because wp users don't have a phone field
108 $customer = new OsCustomerModel();
109 $customer = $customer->where( array( 'phone' => $phone ) )->set_limit( 1 )->get_results_as_models();
110 if ( $customer ) {
111 $email = $customer->email;
112 if ( $customer->wordpress_user_id ) {
113 $wp_user_id = $customer->wordpress_user_id;
114 } else {
115 $wp_user_id = email_exists( $customer->email );
116 }
117 }
118 }
119 if ( $wp_user_id && ! empty( $email ) && ! empty( $password ) ) {
120 $wp_user = wp_signon( [ 'user_login' => $email, 'user_password' => $password ] );
121 if ( ! is_wp_error( $wp_user ) ) {
122 // successfully logged into wp user
123 // check if latepoint customer exists in db for this wp user
124 wp_set_current_user( $wp_user->ID );
125 $customer = OsCustomerHelper::get_customer_for_wp_user( $wp_user );
126 if ( $customer->id ) {
127 self::clear_login_rate_limits( $contact_value, $contact_type );
128 return $customer;
129 } else {
130 OsDebugHelper::log( 'Can not login because can not create LatePoint Customer from WP User', 'customer_login_error', $customer->get_error_messages() );
131
132 return false;
133 }
134 } else {
135 self::record_failed_login_attempt( $contact_value, $contact_type );
136 return false;
137 }
138 } else {
139 return false;
140 }
141 } else {
142 $customer = new OsCustomerModel();
143 if ( $contact_type == 'email' ) {
144 $email = sanitize_email( $contact_value );
145 $customer = $customer->where( array( 'email' => $email ) )->set_limit( 1 )->get_results_as_models();
146 } elseif ( $contact_type == 'phone' ) {
147 $phone = OsUtilHelper::sanitize_phone_number( $contact_value );
148 $customer = $customer->where( array( 'phone' => $phone ) )->set_limit( 1 )->get_results_as_models();
149 }
150 if ( $customer && OsAuthHelper::verify_password( $password, $customer->password ) ) {
151 OsAuthHelper::authorize_customer( $customer->id );
152 self::clear_login_rate_limits( $contact_value, $contact_type );
153
154 return $customer;
155 } else {
156 self::record_failed_login_attempt( $contact_value, $contact_type );
157 return false;
158 }
159 }
160 }
161
162 private static function check_login_rate_limit( string $contact_value, string $contact_type ) : bool {
163 // Per-contact check
164 $contact_key = self::get_login_rate_limit_key( 'contact', $contact_value . '::' . $contact_type );
165 $attempts = absint( get_transient( $contact_key ) );
166 if ( $attempts >= self::$max_login_attempts_per_contact ) {
167 OsDebugHelper::log( 'Too many login attempts for contact', 'login_rate_limit', [ 'contact' => $contact_value, 'type' => $contact_type ] );
168 return false;
169 }
170
171 // Per-IP check
172 $client_ip = OsUtilHelper::get_user_ip();
173 if ( ! empty( $client_ip ) && $client_ip !== 'n/a' ) {
174 $ip_key = self::get_login_rate_limit_key( 'ip', $client_ip );
175 $ip_attempts = absint( get_transient( $ip_key ) );
176 if ( $ip_attempts >= self::$max_login_attempts_per_ip ) {
177 OsDebugHelper::log( 'Too many login attempts from IP', 'login_rate_limit_ip', [ 'ip' => $client_ip ] );
178 return false;
179 }
180 }
181
182 return true;
183 }
184
185 private static function record_failed_login_attempt( string $contact_value, string $contact_type ) : void {
186 $lockout_duration = self::$login_lockout_minutes * MINUTE_IN_SECONDS;
187 $client_ip = OsUtilHelper::get_user_ip();
188
189 $contact_key = self::get_login_rate_limit_key( 'contact', $contact_value . '::' . $contact_type );
190 $attempts = absint( get_transient( $contact_key ) );
191 set_transient( $contact_key, $attempts + 1, $lockout_duration );
192
193 if ( ! empty( $client_ip ) && $client_ip !== 'n/a' ) {
194 $ip_key = self::get_login_rate_limit_key( 'ip', $client_ip );
195 $ip_attempts = absint( get_transient( $ip_key ) );
196 set_transient( $ip_key, $ip_attempts + 1, $lockout_duration );
197 }
198 }
199
200 private static function clear_login_rate_limits( string $contact_value, string $contact_type ) : void {
201 delete_transient( self::get_login_rate_limit_key( 'contact', $contact_value . '::' . $contact_type ) );
202
203 $client_ip = OsUtilHelper::get_user_ip();
204 if ( ! empty( $client_ip ) && $client_ip !== 'n/a' ) {
205 delete_transient( self::get_login_rate_limit_key( 'ip', $client_ip ) );
206 }
207 }
208
209 private static function get_login_rate_limit_key( string $type, string $identifier ) : string {
210 return 'latepoint_login_' . $type . '_' . substr( wp_hash( $identifier ), 0, 20 );
211 }
212
213 public static function can_wp_users_login_as_customers(): bool {
214 return OsSettingsHelper::is_on( 'wp_users_as_customers', false );
215 }
216
217
218 // CUSTOMERS
219 // ---------------
220
221 public static function logout_customer() {
222 if ( self::can_wp_users_login_as_customers() ) {
223 wp_logout();
224 } else {
225 OsSessionsHelper::destroy_customer_session_cookie();
226 }
227 }
228
229 public static function authorize_customer( $customer_id ): bool {
230 $customer = new OsCustomerModel();
231 $customer = $customer->where( [ 'id' => $customer_id ] )->set_limit( 1 )->get_results_as_models();
232 if ( empty( $customer ) ) {
233 OsDebugHelper::log( 'Tried to authorize customer with invalid ID', 'customer_authorization', [ 'customer_id' => $customer_id ] );
234
235 return false;
236 }
237
238 if ( self::can_wp_users_login_as_customers() ) {
239
240 if ( $customer->wordpress_user_id ) {
241 $wp_user = get_user_by( 'id', $customer->wordpress_user_id );
242 // check if WP User exists, if not - create new one and get ID, otherwise get ID from customer record, since its valid
243 $wordpress_user_id = ( $wp_user ) ? $customer->wordpress_user_id : OsCustomerHelper::create_wp_user_for_customer( $customer );
244 } else {
245 $wordpress_user_id = OsCustomerHelper::create_wp_user_for_customer( $customer );
246 }
247
248 if ( $wordpress_user_id ) {
249 $wp_user = get_user_by( 'id', $wordpress_user_id );
250 if ( $wp_user ) {
251 self::login_wp_user( $wp_user );
252 } else {
253 OsDebugHelper::log( 'WordPress user ID for customer is not found or can not be created.', 'customer_create_error', [
254 'customer_id' => $customer_id,
255 'wordpress_user_id' => $wordpress_user_id
256 ] );
257
258 return false;
259 }
260 } else {
261 OsDebugHelper::log( 'WordPress user ID for customer is not found or can not be created.', 'customer_create_error', [ 'customer_id' => $customer_id ] );
262
263 return false;
264 }
265 }
266 OsSessionsHelper::start_or_use_session_for_customer( $customer_id );
267 OsStepsHelper::$customer_object = $customer;
268
269 return true;
270 }
271
272 public static function get_logged_in_customer_uuid() {
273 $customer = self::get_logged_in_customer();
274 if ( $customer ) {
275 return $customer->get_uuid();
276 } else {
277 return false;
278 }
279 }
280
281 public static function get_logged_in_customer_id() {
282 if ( OsAuthHelper::is_customer_auth_disabled() ) {
283 return false;
284 }
285 if ( self::can_wp_users_login_as_customers() ) {
286 // using wp users as customers
287 if ( OsWpUserHelper::is_user_logged_in() ) {
288 $wp_user = wp_get_current_user();
289 // search connected latepoint customer
290 $customer = OsCustomerHelper::get_customer_for_wp_user( $wp_user );
291 if ( $customer->id ) {
292 return $customer->id;
293 } else {
294 OsDebugHelper::log( 'Can not create LatePoint Customer from WP User', 'customer_create_error', $customer->get_error_messages() );
295
296 return false;
297 }
298 } else {
299 return false;
300 }
301 } else {
302 if ( self::$logged_in_customer_id ) {
303 return self::$logged_in_customer_id;
304 }
305 $customer_id = OsSessionsHelper::get_customer_id_from_session();
306 // make sure customer with this ID exists in database
307 $customer = new OsCustomerModel( $customer_id );
308 if ( ! $customer->is_new_record() ) {
309 self::$logged_in_customer_id = $customer_id;
310
311 return self::$logged_in_customer_id;
312 } else {
313 // customer not found, destroy this invalid customer ID in session cookie
314 OsSessionsHelper::destroy_customer_session_cookie();
315
316 return false;
317 }
318 }
319 }
320
321 public static function is_customer_logged_in() {
322 return self::get_logged_in_customer_id();
323 }
324
325 public static function get_logged_in_customer() {
326 $customer = false;
327 if ( self::is_customer_logged_in() ) {
328 $customer = new OsCustomerModel( self::get_logged_in_customer_id() );
329 if ( $customer->is_new_record() ) {
330 $customer = false;
331 }
332 }
333
334 return $customer;
335 }
336
337
338 // AGENTS
339 // -------------
340
341 public static function get_logged_in_agent_id() {
342 $agent_id = false;
343 if ( self::is_agent_logged_in() ) {
344 if ( self::get_current_user()->agent && self::get_current_user()->agent->id ) {
345 $agent_id = self::get_current_user()->agent->id;
346 }
347 }
348
349 return $agent_id;
350 }
351
352 public static function is_agent_logged_in() {
353 return ( self::get_current_user()->backend_user_type == LATEPOINT_USER_TYPE_AGENT );
354 }
355
356 public static function get_logged_in_agent() {
357 $agent = false;
358 if ( self::is_agent_logged_in() ) {
359 $agent = new OsAgentModel();
360 $agent = $agent->where( [ 'wp_user_id' => self::get_logged_in_wp_user_id() ] )->set_limit( 1 )->get_results_as_models();
361 }
362
363 return $agent;
364 }
365
366
367 public static function is_custom_backend_user_logged_in() {
368 return ( self::get_current_user()->backend_user_type == LATEPOINT_USER_TYPE_CUSTOM );
369 }
370
371 public static function is_admin_logged_in() {
372 return ( self::get_current_user()->backend_user_type == LATEPOINT_USER_TYPE_ADMIN );
373 }
374
375 public static function get_logged_in_admin_user() {
376 $admin_user = false;
377 if ( self::is_admin_logged_in() ) {
378 $admin_user = self::get_logged_in_wp_user();
379 }
380
381 return $admin_user;
382 }
383
384 public static function get_logged_in_admin_user_id() {
385 $admin_id = false;
386 if ( self::is_admin_logged_in() ) {
387 $admin_id = self::get_logged_in_wp_user_id();
388 }
389
390 return $admin_id;
391 }
392
393 public static function get_logged_in_custom_user_id() {
394 $admin_id = false;
395 if ( self::is_custom_backend_user_logged_in() ) {
396 $admin_id = self::get_logged_in_wp_user_id();
397 }
398
399 return $admin_id;
400 }
401
402
403 public static function get_default_customer_authentication_method(): string {
404 $method = OsSettingsHelper::get_settings_value( 'default_customer_authentication_method', 'password' );
405
406 $enabled_auth_methods = self::get_enabled_customer_authentication_methods();
407 if ( empty( $enabled_auth_methods ) ) {
408 $method = '';
409 } elseif ( count( $enabled_auth_methods ) == 1 ) {
410 $method = $enabled_auth_methods[0];
411 } else {
412 $method = in_array( $method, $enabled_auth_methods ) ? $method : reset( $enabled_auth_methods );
413 }
414
415 /**
416 * Default auth method
417 *
418 * @param {string} $method default auth method value
419 * @returns {string} The filtered auth method value
420 *
421 * @since 5.2.0
422 * @hook latepoint_default_contact_type_for_customer_auth
423 *
424 */
425 return apply_filters( 'latepoint_default_contact_type_for_customer_auth', $method );
426 }
427
428 public static function get_available_customer_authentication_methods(): array {
429 $methods = [ 'password' => __( 'Password', 'latepoint' ), 'otp' => __( 'One-time code', 'latepoint' ) ];
430
431 /**
432 * Enabled auth method
433 *
434 * @param {array} $methods available auth methods
435 * @returns {array} The filtered array of available auth methods
436 *
437 * @since 5.2.0
438 * @hook latepoint_get_available_customer_authentication_methods
439 *
440 */
441 return apply_filters( 'latepoint_get_available_customer_authentication_methods', $methods );
442 }
443
444
445 public static function get_enabled_customer_authentication_methods(): array {
446 $selected_method = OsSettingsHelper::get_settings_value( 'selected_customer_authentication_method', 'password' );
447
448 switch ( $selected_method ) {
449 case 'password':
450 $auth_methods = [ 'password' ];
451 break;
452 case 'otp':
453 $auth_methods = [ 'otp' ];
454 break;
455 case 'password_or_otp':
456 $auth_methods = [ 'password', 'otp' ];
457 break;
458 default:
459 $auth_methods = [ 'password' ];
460 }
461
462 /**
463 * Enabled auth method
464 *
465 * @param {array} $auth_methods enabled auth methods
466 * @returns {array} The filtered array of enabled auth methods
467 *
468 * @since 5.2.0
469 * @hook latepoint_get_enabled_customer_authentication_methods
470 *
471 */
472 return apply_filters( 'latepoint_get_enabled_customer_authentication_methods', $auth_methods );
473 }
474
475
476 public static function get_selected_customer_authentication_method(): string {
477 $via = OsSettingsHelper::get_settings_value( 'selected_customer_authentication_method', 'password' );
478 if ( in_array( $via, self::get_enabled_customer_authentication_methods( true ) ) ) {
479 return $via;
480 } else {
481 OsSettingsHelper::save_setting_by_name( 'selected_customer_authentication_method', 'password' );
482
483 return 'password';
484 }
485 }
486
487 public static function get_customer_authentication_method_options( $keys_only = false ): array {
488 $options = [
489 'password' => __( 'Password', 'latepoint' ),
490 'otp' => __( 'One-time code', 'latepoint' )
491 ];
492
493 return $keys_only ? array_keys( $options ) : $options;
494 }
495
496
497 public static function get_default_contact_type_for_customer_auth(): string {
498 $method = OsSettingsHelper::get_settings_value( 'default_contact_type_for_customer_auth', 'email' );
499
500 $enabled_contact_types = self::get_enabled_contact_types_for_customer_auth();
501 if ( empty( $enabled_contact_types ) ) {
502 $method = '';
503 } elseif ( count( $enabled_contact_types ) == 1 ) {
504 $method = $enabled_contact_types[0];
505 } else {
506 $method = in_array( $method, $enabled_contact_types ) ? $method : reset( $enabled_contact_types );
507 }
508
509 /**
510 * Default auth method
511 *
512 * @param {string} $method default auth method value
513 * @returns {string} The filtered auth method value
514 *
515 * @since 5.2.0
516 * @hook latepoint_default_contact_type_for_customer_auth
517 *
518 */
519 return apply_filters( 'latepoint_default_contact_type_for_customer_auth', $method );
520 }
521
522 public static function get_available_contact_types_for_customer_auth(): array {
523 $contact_types = [ 'email' => __( 'Email Address', 'latepoint' ), 'phone' => __( 'Phone Number', 'latepoint' ) ];
524
525 /**
526 * Enabled auth method
527 *
528 * @param {array} $contact_types available contact types
529 * @returns {array} The filtered array of available contact types
530 *
531 * @since 5.2.0
532 * @hook latepoint_get_available_contact_types_for_customer_auth
533 *
534 */
535 return apply_filters( 'latepoint_get_available_contact_types_for_customer_auth', $contact_types );
536 }
537
538 public static function get_enabled_contact_types_for_customer_auth(): array {
539 $customer_authentication_field_type = OsSettingsHelper::get_settings_value( 'selected_customer_authentication_field_type', 'email' );
540
541 switch ( $customer_authentication_field_type ) {
542 case 'email':
543 $contact_types = [ 'email' ];
544 break;
545 case 'phone':
546 $contact_types = [ 'phone' ];
547 break;
548 case 'email_or_phone':
549 $contact_types = [ 'email', 'phone' ];
550 break;
551 case 'disabled':
552 $contact_types = [];
553 break;
554 default:
555 $contact_types = [ 'email' ];
556 }
557
558 /**
559 * Enabled auth method
560 *
561 * @param {array} $contact_types enabled contact types
562 * @returns {array} The filtered array of enabled contact types
563 *
564 * @since 5.2.0
565 * @hook latepoint_get_enabled_contact_types_for_customer_auth
566 *
567 */
568 return apply_filters( 'latepoint_get_enabled_contact_types_for_customer_auth', $contact_types );
569 }
570
571 public static function is_customer_auth_enabled(): bool {
572 return ( self::get_selected_customer_authentication_field_type() != 'disabled' );
573 }
574
575 public static function is_customer_auth_disabled(): bool {
576 return ! self::is_customer_auth_enabled();
577 }
578
579 public static function count_total_customers_violating_auth_rules() : array {
580
581 $violators = ['field' => '', 'values' => []];
582 $field = '';
583
584 if(OsAuthHelper::is_customer_auth_enabled()){
585 // auth enabled
586 $auth_field = OsAuthHelper::get_selected_customer_authentication_field_type();
587 if($auth_field == 'email'){
588 $field = 'email';
589 }
590 if($auth_field == 'phone'){
591 $field = 'phone';
592 }
593 }else{
594 // auth disabled
595 $merge_data = OsSettingsHelper::get_settings_value('default_contact_merge_behavior', 'email');
596 if($merge_data == 'email'){
597 $field = 'email';
598 }
599 if($merge_data == 'phone'){
600 $field = 'phone';
601 }
602 }
603
604 if($field){
605 $customers_model = new OsCustomerModel();
606 $result = $customers_model->select( $field )
607 ->where( [ $field.' !=' => '' ] )
608 ->group_by( $field )
609 ->having( 'COUNT(*) > 1' )
610 ->get_results( ARRAY_A );
611 $violators['values'] = (array_column($result, $field));
612 $violators['field'] = $field;
613 }
614
615 return $violators;
616 }
617
618 public static function get_selected_customer_authentication_field_type(): string {
619 $via = OsSettingsHelper::get_settings_value( 'selected_customer_authentication_field_type' );
620 if ( empty( $via ) ) {
621 // load from legacy setting
622 if ( OsSettingsHelper::is_on( 'steps_hide_login_register_tabs' ) ) {
623 OsSettingsHelper::save_setting_by_name( 'selected_customer_authentication_field_type', 'disabled' );
624
625 return 'disabled';
626 } else {
627 OsSettingsHelper::save_setting_by_name( 'selected_customer_authentication_field_type', 'email' );
628
629 return 'email';
630 }
631 }
632 if ( in_array( $via, self::get_customer_authentication_field_type_options( true ) ) ) {
633 return $via;
634 } else {
635 OsSettingsHelper::save_setting_by_name( 'selected_customer_authentication_field_type', 'email' );
636
637 return 'email';
638 }
639 }
640
641 public static function get_customer_authentication_field_type_options( $keys_only = false ): array {
642 $options = [
643 'email' => __( 'Email Address', 'latepoint' ),
644 'phone' => __( 'Phone Number', 'latepoint' ),
645 'disabled' => __( 'Disable ability to login', 'latepoint' )
646 ];
647
648 return $keys_only ? array_keys( $options ) : $options;
649 }
650
651
652 public static function is_classic_auth_flow(): bool {
653 return ( OsSettingsHelper::get_settings_value( 'modern_auth_flow_for_customers', LATEPOINT_VALUE_OFF ) == LATEPOINT_VALUE_OFF );
654 }
655
656 public static function is_otp_auth_enabled(): bool {
657 return in_array( 'otp', self::get_enabled_customer_authentication_methods() );
658 }
659
660
661 public static function get_default_delivery_method_for_customer_auth_contact_type( string $contact_type ) {
662 $delivery_method = 'email';
663 switch ( $contact_type ) {
664 case 'email':
665 $delivery_method = 'email';
666 break;
667 case 'phone':
668 $delivery_method = 'sms';
669 break;
670 }
671
672 /**
673 * Get default delivery method for auth contact type
674 *
675 * @param {string} $delivery_method delivery method (email, sms, whatsapp)
676 * @param {string} $contact_type contact type selected for auth (email, phone)
677 *
678 * @returns {string} Filtered delivery method
679 * @since 5.2.0
680 * @hook latepoint_get_default_delivery_method_for_customer_auth
681 *
682 */
683 return apply_filters( 'latepoint_get_default_delivery_method_for_customer_auth', $delivery_method, $contact_type );
684 }
685
686 public static function auth_form_html( $is_classic, OsCustomerModel $customer, string $selected_contact_type_for_auth = '', $selected_delivery_method = '' ): string {
687 if ( empty( $selected_contact_type_for_auth ) ) {
688 $selected_contact_type_for_auth = OsAuthHelper::get_default_contact_type_for_customer_auth();
689 }
690 if ( empty( $selected_delivery_method ) ) {
691 $selected_delivery_method = self::get_default_delivery_method_for_customer_auth_contact_type( $selected_contact_type_for_auth );
692 }
693 $enabled_contact_types_for_customer_auth = OsAuthHelper::get_enabled_contact_types_for_customer_auth();
694 $otp_allowed = self::is_otp_auth_enabled();
695 $multiple_auth_methods_enabled = ( count( self::get_enabled_customer_authentication_methods() ) > 1 );
696 $html = '';
697 if ( ! $is_classic ) {
698 $html .= '<div class="latepoint-customer-auth-wrapper">';
699 $html .= '<div class="latepoint-customer-otp-request-wrapper hide-when-entering-otp">';
700 // NEW STYLE SHOWING JUST THE AUTH OPTIONS FIRST
701 if ( in_array( 'email', $enabled_contact_types_for_customer_auth ) ) {
702 $html .= '<div data-login-method="email" class="customer-login-method-wrapper ' . ( $selected_contact_type_for_auth == 'email' ? '' : 'os-hidden' ) . '">';
703 $html .= OsFormHelper::text_field( 'auth[email]', __( 'Your Email Address', 'latepoint' ), $customer->email, array(
704 'validate' => $customer->get_validations_for_property( 'email' ),
705 'class' => 'required'
706 ) );
707 $html .= '</div>';
708 }
709 if ( in_array( 'phone', $enabled_contact_types_for_customer_auth ) ) {
710 $html .= '<div data-login-method="phone" class="customer-login-method-wrapper ' . ( $selected_contact_type_for_auth == 'phone' ? '' : 'os-hidden' ) . '">';
711 $html .= OsFormHelper::phone_number_field( 'auth[phone]', __( 'Your Phone Number', 'latepoint' ), $customer->phone, array(
712 'validate' => $customer->get_validations_for_property( 'phone' ),
713 'class' => 'required',
714 'theme' => 'simple'
715 ) );
716 $html .= '</div>';
717 }
718 $html .= '<a tabindex="0" class="latepoint-btn latepoint-btn-block latepoint-btn-primary latepoint-request-otp-button" data-otp-request-route="' . OsRouterHelper::build_route_name( 'auth', 'request_otp' ) . '"><span>' . __( 'Continue', 'latepoint' ) . '</span></a>';
719 $html .= '</div>';
720 $html .= '</div>';
721 } else {
722 ob_start();
723 ?>
724 <div class="os-customer-login-w os-customer-wrapped-box os-unwrapped">
725 <?php if ( count( $enabled_contact_types_for_customer_auth ) > 1 ) { ?>
726 <div class="login-options-wrapper">
727 <div class="latepoint-customer-box-title"><?php _e( 'Sign in', 'latepoint' ); ?></div>
728 <?php if ( in_array( 'email', $enabled_contact_types_for_customer_auth ) && in_array( 'phone', $enabled_contact_types_for_customer_auth ) ) { ?>
729 <div class="login-options-col login-options-via">
730 <div class="login-options-via-wrapper">
731 <div data-login-method="email" data-is-otp-enabled="<?php echo OsOTPHelper::is_otp_enabled_for_contact_type( 'email', 'email' ) ? 'yes' : 'no'; ?>"
732 data-otp-delivery-method="email"
733 class="login-option <?php echo $selected_contact_type_for_auth == 'email' ? 'os-selected os-default' : ''; ?>"><?php _e( 'Email', 'latepoint' ); ?></div>
734 <div data-login-method="phone" data-is-otp-enabled="<?php echo OsOTPHelper::is_otp_enabled_for_contact_type( 'phone', 'sms' ) ? 'yes' : 'no'; ?>"
735 data-otp-delivery-method="sms"
736 class="login-option <?php echo $selected_contact_type_for_auth == 'phone' ? 'os-selected os-default' : ''; ?>"><?php _e( 'Phone', 'latepoint' ); ?></div>
737 </div>
738 </div>
739 <?php } ?>
740 </div>
741 <?php } ?>
742 <?php
743 if ( in_array( 'email', $enabled_contact_types_for_customer_auth ) ) {
744 echo '<div data-login-method="email" class="customer-login-method-wrapper ' . ( $selected_contact_type_for_auth == 'email' ? '' : 'os-hidden' ) . '">';
745 echo OsFormHelper::text_field( 'auth[email]', __( 'Your Email Address', 'latepoint' ), '' );
746 echo '</div>';
747 }
748 ?>
749 <?php
750 if ( in_array( 'phone', $enabled_contact_types_for_customer_auth ) ) {
751 echo '<div data-login-method="phone" class="customer-login-method-wrapper ' . ( $selected_contact_type_for_auth == 'phone' ? '' : 'os-hidden' ) . '">';
752 echo OsFormHelper::phone_number_field( 'auth[phone]', __( 'Your Phone Number', 'latepoint' ), '' );
753 echo '</div>';
754 }
755 ?>
756 <div class="os-customer-login-password-fields-w" <?php echo ( OsAuthHelper::get_default_customer_authentication_method() == 'otp' ) ? 'style="display:none;"' : ''; ?>>
757 <?php echo OsFormHelper::password_field( 'auth[password]', __( 'Your Password', 'latepoint' ), '', array( 'class' => 'required' ) ); ?>
758 <a href="#" class="latepoint-btn latepoint-btn-primary latepoint-btn-link step-forgot-password-btn"
759 data-os-action="<?php echo esc_attr( OsRouterHelper::build_route_name( 'customer_cabinet', 'request_password_reset_token' ) ); ?>"
760 data-os-output-target=".os-password-reset-form-holder"
761 data-os-after-call="latepoint_reset_password_from_booking_init"
762 data-os-params="<?php echo esc_attr( OsUtilHelper::build_os_params( [ 'from_booking' => true ] ) ); ?>"><span><?php esc_html_e( 'Forgot?', 'latepoint' ); ?></span></a>
763 </div>
764
765 <?php if ( $otp_allowed ) { ?>
766 <div class="os-customer-otp-notice" <?php echo ( OsAuthHelper::get_default_customer_authentication_method() == 'otp' ) ? '' : 'style="display:none;"'; ?>>
767 <?php _e( 'You will receive a 6-digit code to log in.', 'latepoint' ); ?>
768 </div>
769 <?php } ?>
770 <div class="os-customer-login-buttons">
771 <?php if ( $multiple_auth_methods_enabled ) { ?>
772 <div class="login-options-col">
773 <div class="latepoint-customer-otp-option">
774 <?php if ( OsAuthHelper::get_default_customer_authentication_method() == 'otp' ) { ?>
775 <label><input type="checkbox" name="auth[via]" value="password"
776 class="login-with-password-toggle os-opposite"><span><?php _e( 'Use password instead', 'latepoint' ); ?></span></label>
777 <?php } else { ?>
778 <label><input type="checkbox" name="auth[via]" value="otp"
779 class="login-with-password-toggle"><span><?php _e( 'Send me a sign-in code', 'latepoint' ); ?></span></label>
780 <?php } ?>
781 </div>
782 </div>
783 <?php } else {
784 echo OsFormHelper::hidden_field( 'auth[via]', OsAuthHelper::get_default_customer_authentication_method() );
785 } ?>
786 <a data-otp-request-route="<?php echo esc_attr( OsRouterHelper::build_route_name( 'auth', 'request_otp' ) ); ?>"
787 data-password-login-route="<?php echo esc_attr( OsRouterHelper::build_route_name( 'auth', 'login_customer' ) ); ?>" href="#"
788 class="latepoint-btn latepoint-btn-primary step-login-existing-customer-btn <?php echo $multiple_auth_methods_enabled ? '' : 'latepoint-btn-block'; ?>"><span><?php esc_html_e( 'Continue', 'latepoint' ); ?></span></a>
789 </div>
790 </div>
791 <?php
792 $html = ob_get_clean();
793 }
794 $html .= OsFormHelper::hidden_field( 'auth[contact_type]', $selected_contact_type_for_auth );
795 $html .= OsFormHelper::hidden_field( 'auth[delivery_method]', $selected_delivery_method );
796 $html .= OsFormHelper::hidden_field( 'auth[action]', 'register' );
797 $html .= wp_nonce_field( 'auth_nonce', 'auth[nonce]', true, false );
798
799
800 return $html;
801 }
802
803
804 // WP USER
805 public static function get_logged_in_wp_user_id() {
806 return OsWpUserHelper::get_current_user_id();
807 }
808
809 public static function get_logged_in_wp_user() {
810 return OsWpUserHelper::get_current_user();
811 }
812
813
814 // UTILS
815
816 public static function hash_password( $password ) {
817 return wp_hash_password( $password, PASSWORD_DEFAULT );
818 }
819
820 public static function verify_password( $password, $hash ) {
821 return wp_check_password( $password, $hash );
822 }
823
824 }