diff --git a/dt-assets/js/shared-functions.js b/dt-assets/js/shared-functions.js index 52f80aff2..60c6b0e3a 100644 --- a/dt-assets/js/shared-functions.js +++ b/dt-assets/js/shared-functions.js @@ -662,6 +662,14 @@ window.SHAREDFUNCTIONS = { window.localStorage.setItem(key, JSON.stringify(json)); } }, + remove_json_from_local_storage(key, path) { + if (path) { + key = path + '_' + key; + } + if (localStorage) { + window.localStorage.removeItem(key); + } + }, createCustomFilter(field, value) { return { fields: [ diff --git a/dt-mapping/mapping-queries.php b/dt-mapping/mapping-queries.php index 9b02bd4f0..cc6ec0310 100644 --- a/dt-mapping/mapping-queries.php +++ b/dt-mapping/mapping-queries.php @@ -1301,34 +1301,66 @@ public static function post_type_geojson( $post_type, $args = [], $offset = 0, $ global $wpdb; //phpcs:disable + // Determine if post id filtering should take place. + $post_id_filter_sql = ''; + $shared_user_join_sql = ''; + $shared_user_condition_sql = ''; + if ( isset( $args['slug'], $args['user_id'] ) && $args['slug'] === 'personal' ) { + $post_id_filter_sql = $wpdb->prepare( " + SELECT api_p.ID + FROM $wpdb->posts api_p + WHERE (api_p.post_status = 'publish') + AND api_p.post_type = %s + GROUP BY api_p.ID + ", ( ( $post_type === 'system-users' ) ? 'contacts' : $post_type ) ); + + if ( isset( $args['field_type'] ) && $args['field_type'] == 'user_select' ) { + $shared_user_join_sql = "LEFT JOIN $wpdb->dt_share as field_shared_with ON ( field_shared_with.post_id = um.meta_value )"; + $post_id_filter_sql = 'AND (um.meta_value IN ('. $post_id_filter_sql .'))'; + } else { + $shared_user_join_sql = "LEFT JOIN $wpdb->dt_share as field_shared_with ON ( field_shared_with.post_id = p.ID )"; + $post_id_filter_sql = 'AND (p.ID IN ('. $post_id_filter_sql .'))'; + } + $shared_user_condition_sql = "AND (field_shared_with.user_id = ". $args['user_id'] .")"; + } + if ( isset( $args['field_key'], $args['field_type'] ) && in_array( $args['field_type'], [ 'key_select', 'multi_select' ] ) ){ $prepared_query = $wpdb->prepare( " - SELECT p.post_title AS name, lgm.post_id, lgm.lng, lgm.lat + SELECT DISTINCT p.post_title AS name, lgm.post_id, lgm.lng, lgm.lat FROM $wpdb->dt_location_grid_meta AS lgm JOIN $wpdb->posts AS p ON ( p.ID = lgm.post_id ) LEFT JOIN $wpdb->postmeta AS pm ON ( p.ID = pm.post_id ) + ". $shared_user_join_sql ." WHERE lgm.post_type = %s + ". $shared_user_condition_sql ." AND (pm.meta_key = %s)" . ( !empty( $args['field_values'] ) ? " AND (pm.meta_value IN (" . dt_array_to_sql( $args['field_values'] ) . "))" : '' ) ." + ". $post_id_filter_sql ." LIMIT %d, %d; ", $post_type, $args['field_key'], $offset, $limit ); } elseif ( isset( $args['field_type'] ) && $args['field_type'] == 'user_select' ){ $prepared_query = $wpdb->prepare(" - SELECT u.display_name AS name, um.meta_value AS post_id, lgm.lng, lgm.lat + SELECT DISTINCT u.display_name AS name, um.meta_value AS post_id, lgm.lng, lgm.lat FROM $wpdb->dt_location_grid_meta AS lgm JOIN $wpdb->users AS u ON ( u.ID = lgm.post_id ) LEFT JOIN $wpdb->usermeta AS um ON ( u.ID = um.user_id AND um.meta_key = %s ) INNER JOIN $wpdb->usermeta AS um_cap ON ( u.ID = um_cap.user_id AND um_cap.meta_key = %s ) + ". $shared_user_join_sql ." WHERE lgm.post_type = %s + ". $shared_user_condition_sql ." + ". $post_id_filter_sql ." LIMIT %d, %d; ", ( $wpdb->prefix . 'corresponds_to_contact' ), ( $wpdb->prefix . 'capabilities' ), 'users', $offset, $limit ); } else { $prepared_query = $wpdb->prepare( " - SELECT p.post_title AS name, lgm.post_id, lgm.lng, lgm.lat + SELECT DISTINCT p.post_title AS name, lgm.post_id, lgm.lng, lgm.lat FROM $wpdb->dt_location_grid_meta AS lgm JOIN $wpdb->posts AS p ON ( p.ID = lgm.post_id ) + ". $shared_user_join_sql ." WHERE lgm.post_type = %s + ". $shared_user_condition_sql ." + ". $post_id_filter_sql ." LIMIT %d, %d; ", $post_type, $offset, $limit ); } diff --git a/dt-metrics/metrics.php b/dt-metrics/metrics.php index e9e60a11d..55e373ccd 100644 --- a/dt-metrics/metrics.php +++ b/dt-metrics/metrics.php @@ -39,6 +39,8 @@ public function __construct(){ // Personal require_once( get_template_directory() . '/dt-metrics/records/genmap.php' ); new DT_Metrics_Groups_Genmap( 'personal', __( 'Personal', 'disciple_tools' ) ); + require_once( get_template_directory() . '/dt-metrics/records/dynamic-records-map.php' ); + new DT_Metrics_Dynamic_Records_Map( 'personal', __( 'Personal', 'disciple_tools' ) ); require_once( get_template_directory() . '/dt-metrics/personal/coaching-tree.php' ); require_once( get_template_directory() . '/dt-metrics/personal/baptism-tree.php' ); require_once( get_template_directory() . '/dt-metrics/personal/group-tree.php' ); @@ -80,7 +82,7 @@ public function __construct(){ /* Record Types */ new DT_Metrics_Groups_Genmap( 'records', __( 'Genmap', 'disciple_tools' ) ); - require_once( get_template_directory() . '/dt-metrics/records/dynamic-records-map.php' ); + new DT_Metrics_Dynamic_Records_Map( 'records', __( 'Records Map', 'disciple_tools' ) ); } if ( !empty( $modules['access_module']['enabled'] ) ){ require_once( get_template_directory() . '/dt-metrics/combined/critical-path.php' ); diff --git a/dt-metrics/records/dynamic-records-map.js b/dt-metrics/records/dynamic-records-map.js index 44660f6c7..611771f6f 100644 --- a/dt-metrics/records/dynamic-records-map.js +++ b/dt-metrics/records/dynamic-records-map.js @@ -1,6 +1,8 @@ jQuery(document).ready(function ($) { let spinner_html = ''; + const loading_spinner = jQuery('#loading-spinner'); + const loading_legend = jQuery('#loading-legend'); let mapbox_library_api = { container_set_up: false, current_map_type: 'points', @@ -11,13 +13,14 @@ jQuery(document).ready(function ($) { spinner: null, map_query_layer_payloads: {}, dt_maps_layers_cookie_id: 'dt-maps-layers-cookie', + dt_maps_layers_cookie_id_by_slug: `dt-maps-layers-cookie-${window.dt_mapbox_metrics.settings.menu_slug}`, recursive_load: async function ( body, data = {}, offset = 0, limit = 50000, ) { - jQuery('#loading-spinner').show(); + jQuery(loading_spinner).show(); if (data.response === undefined) { data = { request: {}, @@ -30,18 +33,20 @@ jQuery(document).ready(function ($) { body.offset = offset; body.limit = limit; + body.slug = mapbox_library_api.obj.settings.menu_slug; let query = await window.makeRequest( 'POST', mapbox_library_api.obj.settings.post_type_rest_url, body, mapbox_library_api.obj.settings.rest_base_url, ); + jQuery(loading_spinner).hide(); data.request = query.request; data.response.features = data.response.features.concat( query.response.features, ); - jQuery('#loading-legend').html( + jQuery(loading_legend).html( `(${data.response.features.length.toLocaleString()})`, ); @@ -60,8 +65,7 @@ jQuery(document).ready(function ($) { limit, ); } - jQuery('#loading-legend').html(''); - jQuery('#loading-spinner').hide(); + jQuery(loading_legend).html(''); return data; }, setup_container: function () { @@ -438,15 +442,25 @@ jQuery(document).ready(function ($) { mapbox_library_api.dt_maps_layers_cookie_id, {}, ); + if (!dt_maps_layers_cookie) { + dt_maps_layers_cookie = + window.SHAREDFUNCTIONS.get_json_from_local_storage( + mapbox_library_api.dt_maps_layers_cookie_id_by_slug, + {}, + ); + } if (!dt_maps_layers_cookie) { dt_maps_layers_cookie = {}; } dt_maps_layers_cookie['' + response.request.id] = cookie; window.SHAREDFUNCTIONS.save_json_to_local_storage( - mapbox_library_api.dt_maps_layers_cookie_id, + mapbox_library_api.dt_maps_layers_cookie_id_by_slug, dt_maps_layers_cookie, null, ); + window.SHAREDFUNCTIONS.remove_json_from_local_storage( + mapbox_library_api.dt_maps_layers_cookie_id, + ); // Adjust all map layer points. mapbox_library_api.adjust_layer_point_sizes(); @@ -501,16 +515,26 @@ jQuery(document).ready(function ($) { mapbox_library_api.dt_maps_layers_cookie_id, {}, ); + if (!dt_maps_layers_cookie) { + dt_maps_layers_cookie = + window.SHAREDFUNCTIONS.get_json_from_local_storage( + mapbox_library_api.dt_maps_layers_cookie_id_by_slug, + {}, + ); + } if (!dt_maps_layers_cookie) { dt_maps_layers_cookie = {}; } dt_maps_layers_cookie['' + layer_id] = map_query_layer_payload; window.SHAREDFUNCTIONS.save_json_to_local_storage( - mapbox_library_api.dt_maps_layers_cookie_id, + mapbox_library_api.dt_maps_layers_cookie_id_by_slug, dt_maps_layers_cookie, null, ); + window.SHAREDFUNCTIONS.remove_json_from_local_storage( + mapbox_library_api.dt_maps_layers_cookie_id, + ); // Close layer records edit modal. $('#add_records_div').fadeOut('fast'); @@ -544,14 +568,24 @@ jQuery(document).ready(function ($) { window.SHAREDFUNCTIONS.get_json_from_local_storage( mapbox_library_api.dt_maps_layers_cookie_id, ); + if (!dt_maps_layers_cookie) { + dt_maps_layers_cookie = + window.SHAREDFUNCTIONS.get_json_from_local_storage( + mapbox_library_api.dt_maps_layers_cookie_id_by_slug, + {}, + ); + } if (dt_maps_layers_cookie['' + map_query_layer_payload.id]) { delete dt_maps_layers_cookie['' + map_query_layer_payload.id]; window.SHAREDFUNCTIONS.save_json_to_local_storage( - mapbox_library_api.dt_maps_layers_cookie_id, + mapbox_library_api.dt_maps_layers_cookie_id_by_slug, dt_maps_layers_cookie, null, ); + window.SHAREDFUNCTIONS.remove_json_from_local_storage( + mapbox_library_api.dt_maps_layers_cookie_id, + ); } // Remove from map memory. @@ -634,12 +668,22 @@ jQuery(document).ready(function ($) { window.SHAREDFUNCTIONS.get_json_from_local_storage( mapbox_library_api.dt_maps_layers_cookie_id, ); + if (!dt_maps_layers_cookie) { + dt_maps_layers_cookie = + window.SHAREDFUNCTIONS.get_json_from_local_storage( + mapbox_library_api.dt_maps_layers_cookie_id_by_slug, + {}, + ); + } dt_maps_layers_cookie['' + div_layer_id] = layer_settings; window.SHAREDFUNCTIONS.save_json_to_local_storage( - mapbox_library_api.dt_maps_layers_cookie_id, + mapbox_library_api.dt_maps_layers_cookie_id_by_slug, dt_maps_layers_cookie, null, ); + window.SHAREDFUNCTIONS.remove_json_from_local_storage( + mapbox_library_api.dt_maps_layers_cookie_id, + ); } break; } @@ -699,6 +743,13 @@ jQuery(document).ready(function ($) { mapbox_library_api.dt_maps_layers_cookie_id, false, ); + if (!dt_maps_layers_cookie) { + dt_maps_layers_cookie = + window.SHAREDFUNCTIONS.get_json_from_local_storage( + mapbox_library_api.dt_maps_layers_cookie_id_by_slug, + false, + ); + } // Convert parent object to array of layer objects. let layer_cookies = []; @@ -729,10 +780,13 @@ jQuery(document).ready(function ($) { dt_maps_layers_cookie = {}; dt_maps_layers_cookie['' + default_cookie['id']] = default_cookie; window.SHAREDFUNCTIONS.save_json_to_local_storage( - mapbox_library_api.dt_maps_layers_cookie_id, + mapbox_library_api.dt_maps_layers_cookie_id_by_slug, dt_maps_layers_cookie, null, ); + window.SHAREDFUNCTIONS.remove_json_from_local_storage( + mapbox_library_api.dt_maps_layers_cookie_id, + ); // Force a reload. reload_data = true; @@ -1502,13 +1556,14 @@ jQuery(document).ready(function ($) { points_map: { setup: async function () { + let payload = { + post_type: mapbox_library_api.post_type, + query: mapbox_library_api.query_args || {}, + }; let points = await window.makeRequest( 'POST', mapbox_library_api.obj.settings.points_rest_url, - { - post_type: mapbox_library_api.post_type, - query: mapbox_library_api.query_args || {}, - }, + payload, mapbox_library_api.obj.settings.rest_base_url, ); this.load_layer(points); @@ -1645,13 +1700,14 @@ jQuery(document).ready(function ($) { let cluster_map = { default_setup: async function () { + let payload = { + post_type: mapbox_library_api.post_type, + query: mapbox_library_api.query_args || {}, + }; let geojson = await window.makeRequest( 'POST', mapbox_library_api.obj.settings.rest_url, - { - post_type: mapbox_library_api.post_type, - query: mapbox_library_api.query_args || {}, - }, + payload, mapbox_library_api.obj.settings.rest_base_url, ); cluster_map.load_layer(geojson); @@ -1792,13 +1848,14 @@ jQuery(document).ready(function ($) { behind_layer: null, setup: async function (behind_layer = null) { area_map.behind_layer = behind_layer; + let payload = { + post_type: mapbox_library_api.obj.settings.post_type, + query: mapbox_library_api.query_args || {}, + }; area_map.grid_data = await window.makeRequest( 'POST', mapbox_library_api.obj.settings.totals_rest_url, - { - post_type: mapbox_library_api.obj.settings.post_type, - query: mapbox_library_api.query_args || {}, - }, + payload, mapbox_library_api.obj.settings.rest_base_url, ); await area_map.load_layer(); @@ -2051,15 +2108,16 @@ jQuery(document).ready(function ($) { if (details.admin2_grid_id !== null) { jQuery('#admin2_list').html(spinner_html); + let payload = { + grid_id: details.admin2_grid_id, + post_type: mapbox_library_api.post_type, + query: mapbox_library_api.query_args || {}, + }; window .makeRequest( 'POST', mapbox_library_api.obj.settings.list_by_grid_rest_url, - { - grid_id: details.admin2_grid_id, - post_type: mapbox_library_api.post_type, - query: mapbox_library_api.query_args || {}, - }, + payload, mapbox_library_api.obj.settings.rest_base_url, ) .done((list_by_grid) => { @@ -2071,15 +2129,16 @@ jQuery(document).ready(function ($) { }); } else if (details.admin1_grid_id !== null) { jQuery('#admin1_list').html(spinner_html); + let payload = { + grid_id: details.admin1_grid_id, + post_type: mapbox_library_api.post_type, + query: mapbox_library_api.query_args || {}, + }; window .makeRequest( 'POST', mapbox_library_api.obj.settings.list_by_grid_rest_url, - { - grid_id: details.admin1_grid_id, - post_type: mapbox_library_api.post_type, - query: mapbox_library_api.query_args || {}, - }, + payload, mapbox_library_api.obj.settings.rest_base_url, ) .done((list_by_grid) => { @@ -2091,15 +2150,16 @@ jQuery(document).ready(function ($) { }); } else if (details.admin0_grid_id !== null) { jQuery('#admin0_list').html(spinner_html); + let payload = { + grid_id: details.admin0_grid_id, + post_type: mapbox_library_api.post_type, + query: mapbox_library_api.query_args || {}, + }; window .makeRequest( 'POST', mapbox_library_api.obj.settings.list_by_grid_rest_url, - { - grid_id: details.admin0_grid_id, - post_type: mapbox_library_api.post_type, - query: mapbox_library_api.query_args || {}, - }, + payload, mapbox_library_api.obj.settings.rest_base_url, ) .done((list_by_grid) => { diff --git a/dt-metrics/records/dynamic-records-map.php b/dt-metrics/records/dynamic-records-map.php index cdc6eb0b4..0f5339046 100644 --- a/dt-metrics/records/dynamic-records-map.php +++ b/dt-metrics/records/dynamic-records-map.php @@ -7,7 +7,7 @@ class DT_Metrics_Dynamic_Records_Map extends DT_Metrics_Chart_Base { //slug and title of the top menu folder - public $base_slug = 'records'; // lowercase + public $base_slug; // lowercase public $base_title; public $post_type = 'contacts'; public $post_types = []; @@ -18,17 +18,17 @@ class DT_Metrics_Dynamic_Records_Map extends DT_Metrics_Chart_Base public $slug = 'dynamic_records_map'; // lowercase public $js_object_name = 'wp_js_object'; // This object will be loaded into the metrics.js file by the wp_localize_script. public $js_file_name = '/dt-metrics/records/dynamic-records-map.js'; // should be full file name plus extension - public $permissions = [ 'dt_all_access_contacts', 'view_project_metrics' ]; + public $permissions = []; public $namespace = 'dt-metrics/records'; public $base_filter = []; - public function __construct() { + public function __construct( $base_slug, $base_title ) { + $this->base_slug = $base_slug; + $this->base_title = $base_title; + parent::__construct(); - if ( !$this->has_permission() ){ - return; - } + $this->title = __( 'Records Map', 'disciple_tools' ); - $this->base_title = __( 'Contacts', 'disciple_tools' ); // Build post types array, ignoring some for now. // TODO: Only select post types with valid location field types! @@ -69,6 +69,8 @@ public function __construct() { if ( "metrics/$this->base_slug/$this->slug" === $url_path ) { add_action( 'wp_enqueue_scripts', [ $this, 'scripts' ], 99 ); } + + $this->namespace = "dt-metrics/$this->base_slug/$this->slug"; add_action( 'rest_api_init', [ $this, 'add_api_routes' ] ); } @@ -172,7 +174,10 @@ public function post_type_geojson( WP_REST_Request $request ){ $params = $request->get_json_params() ?? $request->get_body_params(); $offset = !empty( $params['offset'] ) ? $params['offset'] : 0; $limit = !empty( $params['limit'] ) ? $params['limit'] : 500000; - if ( !empty( $params['post_type'] ) ){ + + // Ensure to prevent any backdoor entries for non-slug related requests. + if ( !empty( $params['post_type'] ) && !empty( $params['slug'] ) ) { + $slug = $params['slug']; // Ensure params shape is altered accordingly, for system based post types. switch ( $params['post_type'] ){ @@ -183,8 +188,28 @@ public function post_type_geojson( WP_REST_Request $request ){ break; } - // Execute request query. - $response = Disciple_Tools_Mapping_Queries::post_type_geojson( $params['post_type'], $params, $offset, $limit ); + // Ensure user has required permissions, based on specified slug request. + $has_permission = false; + if ( ( $slug === 'personal' ) && current_user_can( 'access_contacts' ) ) { + $has_permission = true; + } + if ( ( $slug === 'records' ) && ( current_user_can( 'dt_all_access_contacts' ) || current_user_can( 'view_project_metrics' ) ) ) { + $has_permission = true; + } + + if ( $has_permission ) { + + // Determine type of query to be executed, based on incoming slug. + if ( $slug === 'personal' ) { + $params['user_id'] = get_current_user_id(); + } + + // Execute request query. + $response = Disciple_Tools_Mapping_Queries::post_type_geojson( $params['post_type'], $params, $offset, $limit ); + + // Ensure to unset user_id for security reasons. + unset( $params['user_id'] ); + } } return [ @@ -254,7 +279,4 @@ public function points_geojson( WP_REST_Request $request ) { return Disciple_Tools_Mapping_Queries::points_geojson( $post_type, $query ); } - - } -new DT_Metrics_Dynamic_Records_Map(); diff --git a/dt-metrics/records/genmap.php b/dt-metrics/records/genmap.php index 32a608dcf..1867a6a45 100644 --- a/dt-metrics/records/genmap.php +++ b/dt-metrics/records/genmap.php @@ -11,14 +11,10 @@ class DT_Metrics_Groups_Genmap extends DT_Metrics_Chart_Base public $base_title; public $title; public $js_object_name = 'wp_js_object'; // This object will be loaded into the metrics.js file by the wp_localize_script. - public $permissions = [ 'dt_all_access_contacts', 'view_project_metrics', 'multiplier' ]; + public $permissions = []; public $namespace = null; public function __construct( $base_slug, $base_title ) { - if ( !$this->has_permission() ){ - return; - } - $this->base_slug = $base_slug; $this->base_title = $base_title; @@ -52,53 +48,66 @@ public function add_api_routes() { } public function tree( WP_REST_Request $request ) { - if ( !$this->has_permission() ){ - return new WP_Error( __METHOD__, 'Missing Permissions', [ 'status' => 400 ] ); - } $params = dt_recursive_sanitize_array( $request->get_params() ); - if ( ! isset( $params['p2p_type'], $params['p2p_direction'], $params['post_type'] ) ) { - return new WP_Error( __METHOD__, 'Missing parameters! [Required: p2p_type, p2p_direction, post_type ]', [ 'status' => 400 ] ); + if ( ! isset( $params['p2p_type'], $params['p2p_direction'], $params['post_type'], $params['slug'] ) ) { + return new WP_Error( __METHOD__, 'Missing parameters! [Required: p2p_type, p2p_direction, post_type, slug ]', [ 'status' => 400 ] ); } - $user = wp_get_current_user(); - $post_type = $params['post_type']; - $post_settings = DT_Posts::get_post_settings( $post_type ); - - // Determine scope of query focus, based on specified slug. - $slug = $params['slug'] ?? 'personal'; - $focus_id = $params['focus_id'] ?? 0; - if ( ( $post_type === 'contacts' ) && ( $slug === 'personal' ) ) { - $user_contact_id = Disciple_Tools_Users::get_contact_for_user( $user->ID ); - if ( intval( $user_contact_id ) ){ - $focus_id = $user_contact_id; - } + $slug = $params['slug']; + + // Ensure user has required permissions, based on specified slug request. + $has_permission = false; + if ( ( $slug === 'personal' ) && current_user_can( 'access_contacts' ) ) { + $has_permission = true; + } + if ( ( $slug === 'records' ) && ( current_user_can( 'dt_all_access_contacts' ) || current_user_can( 'view_project_metrics' ) ) ) { + $has_permission = true; } - $filters = [ - 'slug' => $slug, - 'post_type' => $post_type, - 'show_archived' => $params['show_archived'] ?? false, - 'status_key' => $post_settings['status_field']['status_key'] ?? '', - 'archived_key' => $post_settings['status_field']['archived_key'] ?? '' - ]; - $query = $this->get_query( $post_type, $params['p2p_type'], $params['p2p_direction'], $filters ); + if ( $has_permission ) { + $user = wp_get_current_user(); + $post_type = $params['post_type']; + $post_settings = DT_Posts::get_post_settings( $post_type ); - $can_list_all = current_user_can( 'list_all_' . $post_type ); - if ( $post_type === 'contacts' && current_user_can( 'dt_all_access_contacts' ) ){ - $can_list_all = true; - } - $generated_genmap = $this->get_genmap( $query, $params['gen_depth_limit'] ?? 100, $focus_id, $filters, $can_list_all ); + // Determine scope of query focus, based on specified slug. + $focus_id = $params['focus_id'] ?? 0; + if ( ( $post_type === 'contacts' ) && ( $slug === 'personal' ) ) { + $focus_id = Disciple_Tools_Users::get_contact_for_user( $user->ID ); + } - // Ensure empty hits on personal based slugs, still ensure user node is accessible. - if ( ( $focus_id !== 0 ) && empty( $generated_genmap['children'] ) ) { - $generated_genmap['shared'] = 1; - $generated_genmap['name'] = $user->display_name; - } + // Ensure sourced focus_id is not a wp exception. + if ( is_wp_error( $focus_id ) ) { + return new WP_Error( __METHOD__, 'Missing Permissions', [ 'status' => 400 ] ); + } - return [ - 'data_layers' => $this->package_data_layer_post_fields( $query, $post_type, $post_settings, $params['data_layers'] ?? [] ), - 'genmap' => $generated_genmap - ]; + $filters = [ + 'slug' => $slug, + 'post_type' => $post_type, + 'show_archived' => $params['show_archived'] ?? false, + 'status_key' => $post_settings['status_field']['status_key'] ?? '', + 'archived_key' => $post_settings['status_field']['archived_key'] ?? '' + ]; + $query = $this->get_query( $post_type, $params['p2p_type'], $params['p2p_direction'], $filters ); + + $can_list_all = current_user_can( 'list_all_' . $post_type ); + if ( $post_type === 'contacts' && current_user_can( 'dt_all_access_contacts' ) ){ + $can_list_all = true; + } + $generated_genmap = $this->get_genmap( $query, $params['gen_depth_limit'] ?? 100, $focus_id, $filters, $can_list_all ); + + // Ensure empty hits on personal based slugs, still ensure user node is accessible. + if ( ( $focus_id !== 0 ) && empty( $generated_genmap['children'] ) ) { + $generated_genmap['shared'] = 1; + $generated_genmap['name'] = $user->display_name; + } + + return [ + 'data_layers' => $this->package_data_layer_post_fields( $query, $post_type, $post_settings, $params['data_layers'] ?? [] ), + 'genmap' => $generated_genmap + ]; + } else { + return new WP_Error( __METHOD__, 'Missing Permissions', [ 'status' => 400 ] ); + } } public function scripts() {