[Back] <?php
/*
* Copyright (c) 2023 LatePoint LLC. All rights reserved.
*/
namespace LatePoint\Misc;
class User{
public ?string $backend_user_type = null;
public ?\WP_User $wp_user = null;
public array $roles = [];
public ?\OsAgentModel $agent = null;
public ?\OsCustomerModel $customer = null;
public ?string $wp_capability = null;
protected array $allowed_records = ['agent' => [], 'service' => [], 'location' => []];
protected array $capabilities = [];
function __construct(){
}
public function get_wp_user_meta($meta_key, $default = ''){
$meta_value = $default;
if($this->wp_user){
$meta_value = get_user_meta($this->wp_user->ID, $meta_key, true);
if(empty($meta_value)) $meta_value = $default;
}
return $meta_value;
}
public function update_wp_user_meta($meta_key, $meta_value){
if($this->wp_user){
update_user_meta($this->wp_user->ID, $meta_key, $meta_value);
}
}
/**
*
* Checks if user has a certain capability
*
* @param array|string $capability single capability or an array of capabilities to check if user has or not
* @return bool
*/
public function has_capability($capability): bool{
if($this->has_backend_access()){
// only backend user types have capabilities, check if it's a backend user type first
if(is_array($capability)){
$can = empty(array_diff($capability, $this->get_capabilities()));
}else{
$can = in_array($capability, $this->get_capabilities());
}
}else{
$can = false;
}
/**
* Checks if a user has certain capability
*
* @since 4.7.0
* @hook latepoint_user_has_capability
*
* @param {bool} $can answer to a question if user has a capability
* @param {array|string} $capability array or a single capability that needs to be checked
* @returns {bool} answer to a question if user has a capability
*/
return apply_filters('latepoint_user_has_capability', $can, $capability);
}
public static function load_from_wp_user(\WP_User $wp_user): User{
$user = new self();
$user->wp_user = $wp_user;
if(in_array('administrator', $wp_user->roles)){
// ADMIN
$user->backend_user_type = LATEPOINT_USER_TYPE_ADMIN;
$user->wp_capability = 'manage_options';
}elseif(in_array(LATEPOINT_WP_AGENT_ROLE, $wp_user->roles)){
// AGENT
$user->backend_user_type = LATEPOINT_USER_TYPE_AGENT;
$user->wp_capability = 'edit_bookings';
// get connected agent model
$agent = new \OsAgentModel();
$agent = $agent->where(['wp_user_id' => $wp_user->ID])->set_limit(1)->get_results_as_models();
if($agent) $user->agent = $agent;
}else{
// see if it's one of custom roles
$custom_roles = \OsRolesHelper::get_custom_roles();
foreach($custom_roles as $custom_role){
if(!empty($wp_user->roles) && in_array($custom_role['wp_role'], $wp_user->roles)){
$user->backend_user_type = LATEPOINT_USER_TYPE_CUSTOM;
$user->wp_capability = 'manage_latepoint';
break;
}
}
}
$user->set_roles();
$user->set_capabilities();
$user->set_allowed_records();
return $user;
}
public function set_roles(){
if(empty($this->wp_user)) return;
if($this->wp_user->roles){
foreach($this->wp_user->roles as $role){
$this->roles[] = Role::get_from_wp_role($role);
}
}
}
/*
* Check if user has custom permissions set to access actions, instead of using default ones attached to the role
*/
public function is_custom_capabilities(): bool{
return(!empty($this->get_custom_capabilities()));
}
/*
* Check if user has custom access to model records, instead of using default ones attached to the role
*/
public function is_custom_allowed_records(): bool{
return(!empty($this->get_custom_allowed_records()));
}
// PERMITTED ACTIONS
// -----------------
public function clear_custom_capabilities(){
return delete_user_meta($this->wp_user->ID, 'latepoint_custom_capabilities');
}
public function set_custom_capabilities($capabilities){
return update_user_meta($this->wp_user->ID, 'latepoint_custom_capabilities', $capabilities);
}
public function get_custom_capabilities(){
return get_user_meta($this->wp_user->ID, 'latepoint_custom_capabilities', true);
}
public function get_capabilities(){
return $this->capabilities;
}
protected function set_capabilities(){
switch($this->backend_user_type){
case LATEPOINT_USER_TYPE_ADMIN:
// admins always get all permissions
$this->capabilities = \OsRolesHelper::get_all_available_actions_list();
break;
case LATEPOINT_USER_TYPE_AGENT:
case LATEPOINT_USER_TYPE_CUSTOM:
$custom = $this->get_custom_capabilities();
if(empty($custom)){
foreach($this->roles as $role){
$this->capabilities = array_merge($this->capabilities, $role->get_capabilities());
}
}else{
$this->capabilities = maybe_unserialize($custom);
}
break;
}
}
// ALLOWED RECORDS
// -----------------
public function clear_custom_allowed_records(){
return delete_user_meta($this->wp_user->ID, 'latepoint_custom_allowed_records');
}
public function set_custom_allowed_records($allowed_records){
if(empty($allowed_records)){
return $this->clear_custom_allowed_records();
}else{
return update_user_meta($this->wp_user->ID, 'latepoint_custom_allowed_records', $allowed_records);
}
}
public function get_custom_allowed_records(){
return get_user_meta($this->wp_user->ID, 'latepoint_custom_allowed_records', true);
}
public function get_allowed_records(string $model_type, $load_from_db = false){
if($load_from_db){
// do not calculate allowed records based on what connections are available, just load from database whatever is set
$custom = $this->get_custom_allowed_records();
if($custom){
$custom_records = maybe_unserialize($custom);
return !empty($custom_records[$model_type]) ? $custom_records[$model_type] : [];
}else{
return LATEPOINT_ALL;
}
}else{
return !empty($this->allowed_records[$model_type]) ? $this->allowed_records[$model_type] : [];
}
}
public function is_single_record_allowed(string $model_type): bool{
return $this->are_all_records_allowed($model_type) ? false : (count($this->get_allowed_records($model_type)) == 1);
}
public function are_all_records_allowed(string $model_type = '', $load_from_db = false): bool{
if($load_from_db && $model_type){
$allowed_records = $this->get_allowed_records($model_type, true);
return ($allowed_records == LATEPOINT_ALL);
}else{
if($model_type){
return ($this->allowed_records[$model_type] == LATEPOINT_ALL);
}else{
return (($this->allowed_records['agent'] == LATEPOINT_ALL) && ($this->allowed_records['location'] == LATEPOINT_ALL) && ($this->allowed_records['service'] == LATEPOINT_ALL));
}
}
}
public function check_if_allowed_record_id($id, string $model_type){
if(empty($id)) return false;
if($this->are_all_records_allowed($model_type)) return $id;
if(array_intersect([$id], $this->get_allowed_records($model_type))) return $id;
return false;
}
public function clean_query_args($args){
$model_types = ['agent', 'service', 'location'];
foreach($model_types as $model_type){
if(empty($args[$model_type.'_id']) && !$this->are_all_records_allowed($model_type)){
$args[$model_type.'_id'] = $this->get_allowed_records($model_type);
}
}
return $args;
}
protected function set_allowed_records(){
switch($this->backend_user_type){
case LATEPOINT_USER_TYPE_ADMIN:
$this->allowed_records['agent'] = LATEPOINT_ALL;
$this->allowed_records['service'] = LATEPOINT_ALL;
$this->allowed_records['location'] = LATEPOINT_ALL;
break;
case LATEPOINT_USER_TYPE_AGENT:
if($this->agent){
$this->allowed_records['agent'] = [$this->agent->id] ?? [];
$connection = new \OsConnectorModel();
$connections = $connection->where(['agent_id' => $this->agent->id])->get_results_as_models();
if($connections){
foreach($connections as $connection){
if(!in_array($connection->service_id, $this->allowed_records['service'])) $this->allowed_records['service'][] = $connection->service_id;
if(!in_array($connection->location_id, $this->allowed_records['location'])) $this->allowed_records['location'][] = $connection->location_id;
}
}
}
break;
case LATEPOINT_USER_TYPE_CUSTOM:
// each user has their own settings, by default they allowed to access ALL, query DB to find custom settings
$custom = $this->get_custom_allowed_records();
if(empty($custom)){
$this->allowed_records['agent'] = LATEPOINT_ALL;
$this->allowed_records['service'] = LATEPOINT_ALL;
$this->allowed_records['location'] = LATEPOINT_ALL;
}else{
$custom_records = maybe_unserialize($custom);
$model_types = ['agent', 'service', 'location'];
$connection = new \OsConnectorModel();
// (e.g. if specific locations are selected - make sure agents and services are filtered to only have those that are connected to that location)
foreach($model_types as $model_type){
if($custom_records[$model_type] != LATEPOINT_ALL){
$connection->where([$model_type.'_id' => $custom_records[$model_type]]);
}
}
$allowed_connections = $connection->get_results_as_models();
foreach($allowed_connections as $allowed_connection){
if(!in_array($allowed_connection->agent_id, $this->allowed_records['agent'])) $this->allowed_records['agent'][] = $allowed_connection->agent_id;
if(!in_array($allowed_connection->service_id, $this->allowed_records['service'])) $this->allowed_records['service'][] = $allowed_connection->service_id;
if(!in_array($allowed_connection->location_id, $this->allowed_records['location'])) $this->allowed_records['location'][] = $allowed_connection->location_id;
}
}
break;
}
}
public function get_link_to_settings(): string{
switch($this->backend_user_type){
case LATEPOINT_USER_TYPE_ADMIN:
return \OsRouterHelper::build_link(['settings', 'general']);
case LATEPOINT_USER_TYPE_AGENT:
return \OsRouterHelper::build_link(['agents', 'edit_form'], ['id' => $this->agent->id]);
}
return '';
}
public function get_avatar_url(): string{
// if backend user logged in - try to get their avatar first, before trying to get customer url
if($this->backend_user_type){
if($this->agent) return $this->agent->get_avatar_url();
if($this->wp_user) return get_avatar_url($this->wp_user->user_email);
}
if($this->customer) return $this->customer->get_avatar_url();
if($this->wp_user) return get_avatar_url($this->wp_user->user_email);
return '';
}
public function get_display_name(){
if($this->backend_user_type){
if($this->agent) return $this->agent->full_name;
if($this->wp_user) return $this->wp_user->display_name;
}
if($this->customer) return $this->customer->full_name;
if($this->wp_user) return $this->wp_user->display_name;
}
public function get_user_type_label(){
$labels = [
LATEPOINT_USER_TYPE_ADMIN => __('Administrator', 'latepoint'),
LATEPOINT_USER_TYPE_AGENT => __('Agent', 'latepoint'),
LATEPOINT_USER_TYPE_CUSTOM => __('Custom', 'latepoint')
];
if($this->backend_user_type){
if($this->backend_user_type == LATEPOINT_USER_TYPE_CUSTOM){
if($this->roles && ($this->roles[0] instanceof Role)){
return $this->roles[0]->name;
}else{
return $labels[$this->backend_user_type];
}
}else{
return $labels[$this->backend_user_type];
}
}elseif($this->customer){
return __('Customer', 'latepoint');
}
}
public static function get_backend_user_types(){
$backend_user_types = [LATEPOINT_USER_TYPE_ADMIN, LATEPOINT_USER_TYPE_AGENT, LATEPOINT_USER_TYPE_CUSTOM];
/**
* Get array of user levels that can access backend
*
* @since 4.7.0
* @hook latepoint_get_backend_user_types
*
* @param {array} $backend_user_types array of user levels (strings) that can access backend
* @returns {array} The filtered array of user types
*/
return apply_filters('latepoint_get_backend_user_types', $backend_user_types);
}
public function has_backend_access(): bool{
return in_array($this->backend_user_type, self::get_backend_user_types());
}
public static function allowed_props(): array{
return [];
}
}