blocked_period.php
3 months ago
booked_period.php
3 months ago
booking_request.php
3 months ago
booking_resource.php
3 months ago
booking_slot.php
3 months ago
filter.php
3 months ago
process_action.php
1 month ago
process_event.php
1 month ago
role.php
2 weeks ago
router.php
3 months ago
step.php
3 months ago
stripe_connect_customer.php
3 months ago
time_period.php
3 months ago
user.php
3 months ago
work_period.php
3 months ago
user.php
402 lines
| 1 | <?php |
| 2 | /* |
| 3 | * Copyright (c) 2023 LatePoint LLC. All rights reserved. |
| 4 | */ |
| 5 | |
| 6 | namespace LatePoint\Misc; |
| 7 | |
| 8 | class User { |
| 9 | public ?string $backend_user_type = null; |
| 10 | public ?\WP_User $wp_user = null; |
| 11 | public array $roles = []; |
| 12 | |
| 13 | public ?\OsAgentModel $agent = null; |
| 14 | public ?\OsCustomerModel $customer = null; |
| 15 | |
| 16 | public ?string $wp_capability = null; |
| 17 | protected array $allowed_records = [ |
| 18 | 'agent' => [], |
| 19 | 'service' => [], |
| 20 | 'location' => [], |
| 21 | ]; |
| 22 | protected array $capabilities = []; |
| 23 | |
| 24 | |
| 25 | function __construct() { |
| 26 | } |
| 27 | |
| 28 | |
| 29 | public function get_wp_user_meta( $meta_key, $default = '' ) { |
| 30 | $meta_value = $default; |
| 31 | if ( $this->wp_user ) { |
| 32 | $meta_value = get_user_meta( $this->wp_user->ID, $meta_key, true ); |
| 33 | if ( empty( $meta_value ) ) { |
| 34 | $meta_value = $default; |
| 35 | } |
| 36 | } |
| 37 | return $meta_value; |
| 38 | } |
| 39 | |
| 40 | |
| 41 | public function update_wp_user_meta( $meta_key, $meta_value ) { |
| 42 | if ( $this->wp_user ) { |
| 43 | update_user_meta( $this->wp_user->ID, $meta_key, $meta_value ); |
| 44 | } |
| 45 | } |
| 46 | |
| 47 | /** |
| 48 | * |
| 49 | * Checks if user has a certain capability |
| 50 | * |
| 51 | * @param array|string $capability single capability or an array of capabilities to check if user has or not |
| 52 | * @return bool |
| 53 | */ |
| 54 | public function has_capability( $capability ): bool { |
| 55 | if ( $this->has_backend_access() ) { |
| 56 | // only backend user types have capabilities, check if it's a backend user type first |
| 57 | if ( is_array( $capability ) ) { |
| 58 | $can = empty( array_diff( $capability, $this->get_capabilities() ) ); |
| 59 | } else { |
| 60 | $can = in_array( $capability, $this->get_capabilities() ); |
| 61 | } |
| 62 | } else { |
| 63 | $can = false; |
| 64 | } |
| 65 | /** |
| 66 | * Checks if a user has certain capability |
| 67 | * |
| 68 | * @since 4.7.0 |
| 69 | * @hook latepoint_user_has_capability |
| 70 | * |
| 71 | * @param {bool} $can answer to a question if user has a capability |
| 72 | * @param {array|string} $capability array or a single capability that needs to be checked |
| 73 | * @returns {bool} answer to a question if user has a capability |
| 74 | */ |
| 75 | return apply_filters( 'latepoint_user_has_capability', $can, $capability ); |
| 76 | } |
| 77 | |
| 78 | public static function load_from_wp_user( \WP_User $wp_user ): User { |
| 79 | $user = new self(); |
| 80 | $user->wp_user = $wp_user; |
| 81 | |
| 82 | if ( in_array( 'administrator', $wp_user->roles ) ) { |
| 83 | // ADMIN |
| 84 | $user->backend_user_type = LATEPOINT_USER_TYPE_ADMIN; |
| 85 | $user->wp_capability = 'manage_options'; |
| 86 | } elseif ( in_array( LATEPOINT_WP_AGENT_ROLE, $wp_user->roles ) ) { |
| 87 | // AGENT |
| 88 | $user->backend_user_type = LATEPOINT_USER_TYPE_AGENT; |
| 89 | $user->wp_capability = 'edit_bookings'; |
| 90 | // get connected agent model |
| 91 | $agent = new \OsAgentModel(); |
| 92 | $agent = $agent->where( [ 'wp_user_id' => $wp_user->ID ] )->set_limit( 1 )->get_results_as_models(); |
| 93 | if ( $agent ) { |
| 94 | $user->agent = $agent; |
| 95 | } |
| 96 | } else { |
| 97 | // see if it's one of custom roles |
| 98 | $custom_roles = \OsRolesHelper::get_custom_roles(); |
| 99 | foreach ( $custom_roles as $custom_role ) { |
| 100 | if ( ! empty( $wp_user->roles ) && in_array( $custom_role['wp_role'], $wp_user->roles ) ) { |
| 101 | $user->backend_user_type = LATEPOINT_USER_TYPE_CUSTOM; |
| 102 | $user->wp_capability = 'manage_latepoint'; |
| 103 | break; |
| 104 | } |
| 105 | } |
| 106 | } |
| 107 | $user->set_roles(); |
| 108 | $user->set_capabilities(); |
| 109 | $user->set_allowed_records(); |
| 110 | return $user; |
| 111 | } |
| 112 | |
| 113 | public function set_roles() { |
| 114 | if ( empty( $this->wp_user ) ) { |
| 115 | return; |
| 116 | } |
| 117 | if ( $this->wp_user->roles ) { |
| 118 | foreach ( $this->wp_user->roles as $role ) { |
| 119 | $this->roles[] = Role::get_from_wp_role( $role ); |
| 120 | } |
| 121 | } |
| 122 | } |
| 123 | |
| 124 | /* |
| 125 | * Check if user has custom permissions set to access actions, instead of using default ones attached to the role |
| 126 | */ |
| 127 | public function is_custom_capabilities(): bool { |
| 128 | return( ! empty( $this->get_custom_capabilities() ) ); |
| 129 | } |
| 130 | |
| 131 | /* |
| 132 | * Check if user has custom access to model records, instead of using default ones attached to the role |
| 133 | */ |
| 134 | public function is_custom_allowed_records(): bool { |
| 135 | return( ! empty( $this->get_custom_allowed_records() ) ); |
| 136 | } |
| 137 | |
| 138 | |
| 139 | // PERMITTED ACTIONS |
| 140 | // ----------------- |
| 141 | |
| 142 | public function clear_custom_capabilities() { |
| 143 | return delete_user_meta( $this->wp_user->ID, 'latepoint_custom_capabilities' ); |
| 144 | } |
| 145 | |
| 146 | public function set_custom_capabilities( $capabilities ) { |
| 147 | return update_user_meta( $this->wp_user->ID, 'latepoint_custom_capabilities', $capabilities ); |
| 148 | } |
| 149 | |
| 150 | public function get_custom_capabilities() { |
| 151 | return get_user_meta( $this->wp_user->ID, 'latepoint_custom_capabilities', true ); |
| 152 | } |
| 153 | |
| 154 | public function get_capabilities() { |
| 155 | return $this->capabilities; |
| 156 | } |
| 157 | |
| 158 | protected function set_capabilities() { |
| 159 | switch ( $this->backend_user_type ) { |
| 160 | case LATEPOINT_USER_TYPE_ADMIN: |
| 161 | // admins always get all permissions |
| 162 | $this->capabilities = \OsRolesHelper::get_all_available_actions_list(); |
| 163 | break; |
| 164 | case LATEPOINT_USER_TYPE_AGENT: |
| 165 | case LATEPOINT_USER_TYPE_CUSTOM: |
| 166 | $custom = $this->get_custom_capabilities(); |
| 167 | if ( empty( $custom ) ) { |
| 168 | foreach ( $this->roles as $role ) { |
| 169 | $this->capabilities = array_merge( $this->capabilities, $role->get_capabilities() ); |
| 170 | } |
| 171 | } else { |
| 172 | $this->capabilities = maybe_unserialize( $custom ); |
| 173 | } |
| 174 | break; |
| 175 | } |
| 176 | } |
| 177 | |
| 178 | |
| 179 | // ALLOWED RECORDS |
| 180 | // ----------------- |
| 181 | |
| 182 | public function clear_custom_allowed_records() { |
| 183 | return delete_user_meta( $this->wp_user->ID, 'latepoint_custom_allowed_records' ); |
| 184 | } |
| 185 | |
| 186 | public function set_custom_allowed_records( $allowed_records ) { |
| 187 | if ( empty( $allowed_records ) ) { |
| 188 | return $this->clear_custom_allowed_records(); |
| 189 | } else { |
| 190 | return update_user_meta( $this->wp_user->ID, 'latepoint_custom_allowed_records', $allowed_records ); |
| 191 | } |
| 192 | } |
| 193 | |
| 194 | public function get_custom_allowed_records() { |
| 195 | return get_user_meta( $this->wp_user->ID, 'latepoint_custom_allowed_records', true ); |
| 196 | } |
| 197 | |
| 198 | public function get_allowed_records( string $model_type, $load_from_db = false ) { |
| 199 | if ( $load_from_db ) { |
| 200 | // do not calculate allowed records based on what connections are available, just load from database whatever is set |
| 201 | $custom = $this->get_custom_allowed_records(); |
| 202 | if ( $custom ) { |
| 203 | $custom_records = maybe_unserialize( $custom ); |
| 204 | return ! empty( $custom_records[ $model_type ] ) ? $custom_records[ $model_type ] : []; |
| 205 | } else { |
| 206 | return LATEPOINT_ALL; |
| 207 | } |
| 208 | } else { |
| 209 | return ! empty( $this->allowed_records[ $model_type ] ) ? $this->allowed_records[ $model_type ] : []; |
| 210 | } |
| 211 | } |
| 212 | |
| 213 | public function is_single_record_allowed( string $model_type ): bool { |
| 214 | return $this->are_all_records_allowed( $model_type ) ? false : ( count( $this->get_allowed_records( $model_type ) ) == 1 ); |
| 215 | } |
| 216 | |
| 217 | public function are_all_records_allowed( string $model_type = '', $load_from_db = false ): bool { |
| 218 | if ( $load_from_db && $model_type ) { |
| 219 | $allowed_records = $this->get_allowed_records( $model_type, true ); |
| 220 | return ( $allowed_records == LATEPOINT_ALL ); |
| 221 | } else { |
| 222 | if ( $model_type ) { |
| 223 | return ( $this->allowed_records[ $model_type ] == LATEPOINT_ALL ); |
| 224 | } else { |
| 225 | return ( ( $this->allowed_records['agent'] == LATEPOINT_ALL ) && ( $this->allowed_records['location'] == LATEPOINT_ALL ) && ( $this->allowed_records['service'] == LATEPOINT_ALL ) ); |
| 226 | } |
| 227 | } |
| 228 | } |
| 229 | |
| 230 | public function check_if_allowed_record_id( $id, string $model_type ) { |
| 231 | if ( empty( $id ) ) { |
| 232 | return false; |
| 233 | } |
| 234 | if ( $this->are_all_records_allowed( $model_type ) ) { |
| 235 | return $id; |
| 236 | } |
| 237 | if ( array_intersect( [ $id ], $this->get_allowed_records( $model_type ) ) ) { |
| 238 | return $id; |
| 239 | } |
| 240 | return false; |
| 241 | } |
| 242 | |
| 243 | public function clean_query_args( $args ) { |
| 244 | $model_types = [ 'agent', 'service', 'location' ]; |
| 245 | foreach ( $model_types as $model_type ) { |
| 246 | if ( empty( $args[ $model_type . '_id' ] ) && ! $this->are_all_records_allowed( $model_type ) ) { |
| 247 | $args[ $model_type . '_id' ] = $this->get_allowed_records( $model_type ); |
| 248 | } |
| 249 | } |
| 250 | return $args; |
| 251 | } |
| 252 | |
| 253 | protected function set_allowed_records() { |
| 254 | switch ( $this->backend_user_type ) { |
| 255 | case LATEPOINT_USER_TYPE_ADMIN: |
| 256 | $this->allowed_records['agent'] = LATEPOINT_ALL; |
| 257 | $this->allowed_records['service'] = LATEPOINT_ALL; |
| 258 | $this->allowed_records['location'] = LATEPOINT_ALL; |
| 259 | break; |
| 260 | case LATEPOINT_USER_TYPE_AGENT: |
| 261 | if ( $this->agent ) { |
| 262 | $this->allowed_records['agent'] = [ $this->agent->id ] ?? []; |
| 263 | $connection = new \OsConnectorModel(); |
| 264 | $connections = $connection->where( [ 'agent_id' => $this->agent->id ] )->get_results_as_models(); |
| 265 | |
| 266 | if ( $connections ) { |
| 267 | foreach ( $connections as $connection ) { |
| 268 | if ( ! in_array( $connection->service_id, $this->allowed_records['service'] ) ) { |
| 269 | $this->allowed_records['service'][] = $connection->service_id; |
| 270 | } |
| 271 | if ( ! in_array( $connection->location_id, $this->allowed_records['location'] ) ) { |
| 272 | $this->allowed_records['location'][] = $connection->location_id; |
| 273 | } |
| 274 | } |
| 275 | } |
| 276 | } |
| 277 | break; |
| 278 | case LATEPOINT_USER_TYPE_CUSTOM: |
| 279 | // each user has their own settings, by default they allowed to access ALL, query DB to find custom settings |
| 280 | $custom = $this->get_custom_allowed_records(); |
| 281 | if ( empty( $custom ) ) { |
| 282 | $this->allowed_records['agent'] = LATEPOINT_ALL; |
| 283 | $this->allowed_records['service'] = LATEPOINT_ALL; |
| 284 | $this->allowed_records['location'] = LATEPOINT_ALL; |
| 285 | } else { |
| 286 | $custom_records = maybe_unserialize( $custom ); |
| 287 | $model_types = [ 'agent', 'service', 'location' ]; |
| 288 | $connection = new \OsConnectorModel(); |
| 289 | // (e.g. if specific locations are selected - make sure agents and services are filtered to only have those that are connected to that location) |
| 290 | foreach ( $model_types as $model_type ) { |
| 291 | if ( $custom_records[ $model_type ] != LATEPOINT_ALL ) { |
| 292 | $connection->where( [ $model_type . '_id' => $custom_records[ $model_type ] ] ); |
| 293 | } |
| 294 | } |
| 295 | $allowed_connections = $connection->get_results_as_models(); |
| 296 | foreach ( $allowed_connections as $allowed_connection ) { |
| 297 | if ( ! in_array( $allowed_connection->agent_id, $this->allowed_records['agent'] ) ) { |
| 298 | $this->allowed_records['agent'][] = $allowed_connection->agent_id; |
| 299 | } |
| 300 | if ( ! in_array( $allowed_connection->service_id, $this->allowed_records['service'] ) ) { |
| 301 | $this->allowed_records['service'][] = $allowed_connection->service_id; |
| 302 | } |
| 303 | if ( ! in_array( $allowed_connection->location_id, $this->allowed_records['location'] ) ) { |
| 304 | $this->allowed_records['location'][] = $allowed_connection->location_id; |
| 305 | } |
| 306 | } |
| 307 | } |
| 308 | break; |
| 309 | } |
| 310 | } |
| 311 | |
| 312 | |
| 313 | public function get_link_to_settings(): string { |
| 314 | switch ( $this->backend_user_type ) { |
| 315 | case LATEPOINT_USER_TYPE_ADMIN: |
| 316 | return \OsRouterHelper::build_link( [ 'settings', 'general' ] ); |
| 317 | case LATEPOINT_USER_TYPE_AGENT: |
| 318 | return \OsRouterHelper::build_link( [ 'agents', 'edit_form' ], [ 'id' => $this->agent->id ] ); |
| 319 | } |
| 320 | return ''; |
| 321 | } |
| 322 | |
| 323 | public function get_avatar_url(): string { |
| 324 | // if backend user logged in - try to get their avatar first, before trying to get customer url |
| 325 | if ( $this->backend_user_type ) { |
| 326 | if ( $this->agent ) { |
| 327 | return $this->agent->get_avatar_url(); |
| 328 | } |
| 329 | if ( $this->wp_user ) { |
| 330 | return get_avatar_url( $this->wp_user->user_email ); |
| 331 | } |
| 332 | } |
| 333 | if ( $this->customer ) { |
| 334 | return $this->customer->get_avatar_url(); |
| 335 | } |
| 336 | if ( $this->wp_user ) { |
| 337 | return get_avatar_url( $this->wp_user->user_email ); |
| 338 | } |
| 339 | return ''; |
| 340 | } |
| 341 | |
| 342 | public function get_display_name() { |
| 343 | if ( $this->backend_user_type ) { |
| 344 | if ( $this->agent ) { |
| 345 | return $this->agent->full_name; |
| 346 | } |
| 347 | if ( $this->wp_user ) { |
| 348 | return $this->wp_user->display_name; |
| 349 | } |
| 350 | } |
| 351 | if ( $this->customer ) { |
| 352 | return $this->customer->full_name; |
| 353 | } |
| 354 | if ( $this->wp_user ) { |
| 355 | return $this->wp_user->display_name; |
| 356 | } |
| 357 | } |
| 358 | |
| 359 | public function get_user_type_label() { |
| 360 | $labels = [ |
| 361 | LATEPOINT_USER_TYPE_ADMIN => __( 'Administrator', 'latepoint' ), |
| 362 | LATEPOINT_USER_TYPE_AGENT => __( 'Agent', 'latepoint' ), |
| 363 | LATEPOINT_USER_TYPE_CUSTOM => __( 'Custom', 'latepoint' ), |
| 364 | ]; |
| 365 | if ( $this->backend_user_type ) { |
| 366 | if ( $this->backend_user_type == LATEPOINT_USER_TYPE_CUSTOM ) { |
| 367 | if ( $this->roles && ( $this->roles[0] instanceof Role ) ) { |
| 368 | return $this->roles[0]->name; |
| 369 | } else { |
| 370 | return $labels[ $this->backend_user_type ]; |
| 371 | } |
| 372 | } else { |
| 373 | return $labels[ $this->backend_user_type ]; |
| 374 | } |
| 375 | } elseif ( $this->customer ) { |
| 376 | return __( 'Customer', 'latepoint' ); |
| 377 | } |
| 378 | } |
| 379 | |
| 380 | public static function get_backend_user_types() { |
| 381 | $backend_user_types = [ LATEPOINT_USER_TYPE_ADMIN, LATEPOINT_USER_TYPE_AGENT, LATEPOINT_USER_TYPE_CUSTOM ]; |
| 382 | /** |
| 383 | * Get array of user levels that can access backend |
| 384 | * |
| 385 | * @since 4.7.0 |
| 386 | * @hook latepoint_get_backend_user_types |
| 387 | * |
| 388 | * @param {array} $backend_user_types array of user levels (strings) that can access backend |
| 389 | * @returns {array} The filtered array of user types |
| 390 | */ |
| 391 | return apply_filters( 'latepoint_get_backend_user_types', $backend_user_types ); |
| 392 | } |
| 393 | |
| 394 | public function has_backend_access(): bool { |
| 395 | return in_array( $this->backend_user_type, self::get_backend_user_types() ); |
| 396 | } |
| 397 | |
| 398 | public static function allowed_props(): array { |
| 399 | return []; |
| 400 | } |
| 401 | } |
| 402 |