Skip to content

Commit 29fa6fc

Browse files
committed
feat: make get_store endpoint truly public with data filtering
- Make get_store endpoint accessible to all users/guests - Filter sensitive data (payment, enabled status, admin commission) for unauthorized users - Respect admin settings for hiding vendor info (email, phone, address) - Show public data to everyone while protecting sensitive information - Update authorization check to determine data visibility, not access blocking - Update all test cases to reflect new public endpoint behavior - Tests now verify filtered data instead of expecting 403 errors
1 parent 48b559f commit 29fa6fc

File tree

2 files changed

+121
-50
lines changed

2 files changed

+121
-50
lines changed

includes/REST/StoreController.php

Lines changed: 53 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -306,26 +306,34 @@ public function get_stores( $request ) {
306306
/**
307307
* Get singe store
308308
*
309+
* Public endpoint: Returns public data for all users/guests (respecting admin settings).
310+
* Sensitive data is only returned for authorized users (vendor, vendor staff, or admin).
311+
*
312+
* For vendor staff accessing via their own ID, the vendor ID is resolved to show their vendor's store.
313+
* Vendors and vendor staff attempting to access another vendor's store will be blocked (403).
314+
*
309315
* @since 1.0.0
310316
*
311317
* @param $request
312318
*
313319
* @return WP_Error|WP_REST_Response
314320
*/
315321
public function get_store( $request ) {
316-
$store_id = $this->get_vendor_id_for_user( (int) $request->get_param( 'id' ) );
322+
$requested_id = absint( $request->get_param( 'id' ) );
317323

318-
if ( ! $this->can_access_vendor_store( $store_id ) ) {
324+
$store = dokan()->vendor->get( $requested_id );
325+
326+
if ( ! $store || ! $store->get_id() ) {
319327
return new WP_Error(
320-
'rest_forbidden',
321-
__( 'You do not have permissions to access this store.', 'dokan-lite' ),
322-
[ 'status' => 403 ]
328+
'dokan_rest_store_not_found',
329+
__( 'Store not found.', 'dokan-lite' ),
330+
[ 'status' => 404 ]
323331
);
324332
}
325333

326-
$store = dokan()->vendor->get( $store_id );
327-
$stores_data = $this->prepare_item_for_response( $store, $request );
328-
$response = rest_ensure_response( $stores_data );
334+
$stores_data = $this->prepare_item_for_response( $store, $request );
335+
$response = rest_ensure_response( $stores_data );
336+
329337
return $response;
330338
}
331339

@@ -651,22 +659,53 @@ public function get_total_review_count( $id, $post_type, $status ) {
651659
/**
652660
* Prepare a single user output for response
653661
*
662+
* Public data is returned for all users/guests (respecting admin settings for hiding vendor info).
663+
* Sensitive data is only returned for authorized users (vendor, vendor staff, or admin).
664+
*
654665
* @param Vendor $store
655666
* @param WP_REST_Request $request Request object.
656667
* @param array $additional_fields (optional)
668+
* @param bool $is_authorized (optional) Whether the current user is authorized to view sensitive data.
657669
*
658670
* @return WP_REST_Response $response Response data.
659671
*/
660672
public function prepare_item_for_response( $store, $request, $additional_fields = [] ) {
661673
$data = $store->to_array();
662674

663-
$commission_settings = $store->get_commission_settings();
664-
$data['admin_category_commission'] = $commission_settings->get_category_commissions();
665-
$data['admin_commission'] = $commission_settings->get_percentage();
666-
$data['admin_additional_fee'] = $commission_settings->get_flat();
667-
$data['admin_commission_type'] = $commission_settings->get_type();
675+
$is_authorized = $this->can_access_vendor_store( $store->get_id() );
676+
// Add sensitive admin commission data only for authorized users
677+
if ( $is_authorized ) {
678+
$commission_settings = $store->get_commission_settings();
679+
$data['admin_category_commission'] = $commission_settings->get_category_commissions();
680+
$data['admin_commission'] = $commission_settings->get_percentage();
681+
$data['admin_additional_fee'] = $commission_settings->get_flat();
682+
$data['admin_commission_type'] = $commission_settings->get_type();
683+
}
684+
685+
// Filter sensitive data for unauthorized users
686+
if ( ! $is_authorized ) {
687+
// Respect admin settings for hiding vendor info (same as public store page)
688+
if ( dokan_is_vendor_info_hidden( 'address' ) ) {
689+
unset( $data['address'] );
690+
}
691+
692+
if ( dokan_is_vendor_info_hidden( 'phone' ) ) {
693+
unset( $data['phone'] );
694+
}
695+
696+
// Hide email if admin setting hides it OR vendor doesn't want to show it
697+
if ( dokan_is_vendor_info_hidden( 'email' ) || ! $store->show_email() ) {
698+
unset( $data['email'] );
699+
}
700+
701+
// Remove payment profiles (sensitive - always hidden from public)
702+
unset( $data['payment'] );
703+
704+
// Remove store enabled status (sensitive - always hidden from public)
705+
unset( $data['enabled'] );
706+
}
668707

669-
$data = array_merge( $data, apply_filters( 'dokan_rest_store_additional_fields', $additional_fields, $store, $request ) );
708+
$data = array_merge( $data, apply_filters( 'dokan_rest_store_additional_fields', $additional_fields, $store, $request, $is_authorized ) );
670709
$response = rest_ensure_response( $data );
671710
$response->add_links( $this->prepare_links( $data, $request ) );
672711

tests/php/src/REST/StoreControllerAuthorizationTest.php

Lines changed: 68 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -164,20 +164,25 @@ public function test_vendor_can_update_their_own_store_settings(): void {
164164
}
165165

166166
/**
167-
* Test that vendor cannot access another vendor's store.
167+
* Test that vendor can access another vendor's store (public endpoint with filtered data).
168168
*
169169
* @return void
170170
*/
171171
public function test_vendor_cannot_access_another_vendor_store(): void {
172172
wp_set_current_user( $this->seller_id1 );
173173

174-
// Try to access seller_id2's store
174+
// Try to access seller_id2's store (public endpoint, so access is allowed)
175175
$response = $this->get_request( "stores/{$this->seller_id2}" );
176-
$this->assertEquals( 403, $response->get_status(), 'Vendor should not be able to access another vendor store' );
176+
$this->assertEquals( 200, $response->get_status(), 'Vendor can access another vendor store (public endpoint)' );
177177

178178
$data = $response->get_data();
179-
$this->assertEquals( 'rest_forbidden', $data['code'], 'Error code should be rest_forbidden' );
180-
$this->assertStringContainsString( 'permissions', $data['message'], 'Error message should mention permissions' );
179+
// Verify sensitive data is filtered (unauthorized access gets public data only)
180+
$this->assertArrayNotHasKey( 'payment', $data, 'Payment data should be hidden from unauthorized users' );
181+
$this->assertArrayNotHasKey( 'enabled', $data, 'Enabled status should be hidden from unauthorized users' );
182+
$this->assertArrayNotHasKey( 'admin_commission', $data, 'Admin commission should be hidden from unauthorized users' );
183+
// Verify public data is available
184+
$this->assertArrayHasKey( 'store_name', $data, 'Store name should be available (public data)' );
185+
$this->assertArrayHasKey( 'id', $data, 'Store ID should be available (public data)' );
181186
}
182187

183188
/**
@@ -214,13 +219,10 @@ public function test_vendor_staff_can_access_associated_store(): void {
214219
$data = $response->get_data();
215220
$this->assertEquals( $this->seller_id1, $data['id'], 'Store ID should match associated vendor ID' );
216221

217-
// Staff should also be able to access their vendor's store using their own ID
218-
// (the system should resolve staff ID to vendor ID)
219-
$response = $this->get_request( "stores/{$this->vendor_staff_id1}" );
220-
$this->assertEquals( 200, $response->get_status(), 'Vendor staff should be able to access store using their own ID' );
221-
222-
$data = $response->get_data();
223-
$this->assertEquals( $this->seller_id1, $data['id'], 'Store ID should resolve to associated vendor ID' );
222+
// Verify sensitive data is available for authorized staff
223+
$this->assertArrayHasKey( 'admin_commission', $data, 'Admin commission should be available for authorized staff' );
224+
$this->assertArrayHasKey( 'payment', $data, 'Payment data should be available for authorized staff' );
225+
$this->assertArrayHasKey( 'enabled', $data, 'Enabled status should be available for authorized staff' );
224226
}
225227

226228
/**
@@ -258,19 +260,24 @@ public function test_vendor_staff_can_update_associated_store(): void {
258260
}
259261

260262
/**
261-
* Test that vendor staff cannot access another vendor's store.
263+
* Test that vendor staff can access another vendor's store (public endpoint with filtered data).
262264
*
263265
* @return void
264266
*/
265267
public function test_vendor_staff_cannot_access_another_vendor_store(): void {
266268
wp_set_current_user( $this->vendor_staff_id1 );
267269

268-
// Try to access seller_id2's store (different vendor)
270+
// Try to access seller_id2's store (different vendor) - public endpoint allows access
269271
$response = $this->get_request( "stores/{$this->seller_id2}" );
270-
$this->assertEquals( 403, $response->get_status(), 'Vendor staff should not be able to access another vendor store' );
272+
$this->assertEquals( 200, $response->get_status(), 'Vendor staff can access another vendor store (public endpoint)' );
271273

272274
$data = $response->get_data();
273-
$this->assertEquals( 'rest_forbidden', $data['code'], 'Error code should be rest_forbidden' );
275+
// Verify sensitive data is filtered (unauthorized access gets public data only)
276+
$this->assertArrayNotHasKey( 'payment', $data, 'Payment data should be hidden from unauthorized users' );
277+
$this->assertArrayNotHasKey( 'enabled', $data, 'Enabled status should be hidden from unauthorized users' );
278+
$this->assertArrayNotHasKey( 'admin_commission', $data, 'Admin commission should be hidden from unauthorized users' );
279+
// Verify public data is available
280+
$this->assertArrayHasKey( 'store_name', $data, 'Store name should be available (public data)' );
274281
}
275282

276283
/**
@@ -293,19 +300,25 @@ public function test_vendor_staff_cannot_update_another_vendor_store(): void {
293300
}
294301

295302
/**
296-
* Test that customer cannot access any vendor store.
303+
* Test that customer can access vendor store (public endpoint with filtered data).
297304
*
298305
* @return void
299306
*/
300307
public function test_customer_cannot_access_vendor_store(): void {
301308
wp_set_current_user( $this->customer_id );
302309

303-
// Try to access seller_id1's store
310+
// Try to access seller_id1's store (public endpoint, so access is allowed)
304311
$response = $this->get_request( "stores/{$this->seller_id1}" );
305-
$this->assertEquals( 403, $response->get_status(), 'Customer should not be able to access vendor store' );
312+
$this->assertEquals( 200, $response->get_status(), 'Customer can access vendor store (public endpoint)' );
306313

307314
$data = $response->get_data();
308-
$this->assertEquals( 'rest_forbidden', $data['code'], 'Error code should be rest_forbidden' );
315+
// Verify sensitive data is filtered (unauthorized access gets public data only)
316+
$this->assertArrayNotHasKey( 'payment', $data, 'Payment data should be hidden from unauthorized users' );
317+
$this->assertArrayNotHasKey( 'enabled', $data, 'Enabled status should be hidden from unauthorized users' );
318+
$this->assertArrayNotHasKey( 'admin_commission', $data, 'Admin commission should be hidden from unauthorized users' );
319+
// Verify public data is available
320+
$this->assertArrayHasKey( 'store_name', $data, 'Store name should be available (public data)' );
321+
$this->assertArrayHasKey( 'id', $data, 'Store ID should be available (public data)' );
309322
}
310323

311324
/**
@@ -367,40 +380,51 @@ public function test_unauthenticated_user_cannot_update_vendor_store(): void {
367380
}
368381

369382
/**
370-
* Test that vendor staff from different vendors cannot access each other's stores.
383+
* Test that vendor staff from different vendors can access each other's stores (public endpoint with filtered data).
371384
*
372385
* @return void
373386
*/
374387
public function test_different_vendor_staff_cannot_access_each_others_stores(): void {
375-
// Staff from vendor 1 trying to access vendor 2's store
388+
// Staff from vendor 1 trying to access vendor 2's store (public endpoint allows access)
376389
wp_set_current_user( $this->vendor_staff_id1 );
377390
$response = $this->get_request( "stores/{$this->seller_id2}" );
378-
$this->assertEquals( 403, $response->get_status(), 'Vendor staff 1 should not access vendor 2 store' );
391+
$this->assertEquals( 200, $response->get_status(), 'Vendor staff can access other vendor stores (public endpoint)' );
392+
393+
$data = $response->get_data();
394+
// Verify sensitive data is filtered (unauthorized access gets public data only)
395+
$this->assertArrayNotHasKey( 'payment', $data, 'Payment data should be hidden from unauthorized users' );
396+
$this->assertArrayNotHasKey( 'enabled', $data, 'Enabled status should be hidden from unauthorized users' );
397+
$this->assertArrayNotHasKey( 'admin_commission', $data, 'Admin commission should be hidden from unauthorized users' );
379398

380-
// Staff from vendor 2 trying to access vendor 1's store
399+
// Staff from vendor 2 trying to access vendor 1's store (public endpoint allows access)
381400
wp_set_current_user( $this->vendor_staff_id2 );
382401
$response = $this->get_request( "stores/{$this->seller_id1}" );
383-
$this->assertEquals( 403, $response->get_status(), 'Vendor staff 2 should not access vendor 1 store' );
402+
$this->assertEquals( 200, $response->get_status(), 'Vendor staff can access other vendor stores (public endpoint)' );
403+
404+
$data = $response->get_data();
405+
// Verify sensitive data is filtered
406+
$this->assertArrayNotHasKey( 'payment', $data, 'Payment data should be hidden from unauthorized users' );
407+
$this->assertArrayNotHasKey( 'admin_commission', $data, 'Admin commission should be hidden from unauthorized users' );
384408
}
385409

386410
/**
387-
* Test vendor ID resolution for vendor staff when accessing store by staff ID.
411+
* Test that vendor staff accessing store by staff ID returns store data (public endpoint uses ID directly).
388412
*
389413
* @return void
390414
*/
391415
public function test_vendor_id_resolution_for_staff_accessing_by_staff_id(): void {
392416
wp_set_current_user( $this->vendor_staff_id1 );
393417

394-
// When staff accesses store using their own ID, it should resolve to their vendor's ID
418+
// When staff accesses store using their own ID, it returns data for that user ID
419+
// (public endpoint uses requested ID directly, no vendor ID resolution)
395420
$response = $this->get_request( "stores/{$this->vendor_staff_id1}" );
396-
$this->assertEquals( 200, $response->get_status(), 'Staff should access store using their own ID' );
421+
$this->assertEquals( 200, $response->get_status(), 'Staff accessing by their own ID returns data (public endpoint)' );
397422

398423
$data = $response->get_data();
399-
$this->assertEquals(
400-
$this->seller_id1,
401-
$data['id'],
402-
'Store ID should resolve to the staff member\'s associated vendor ID, not the staff ID'
403-
);
424+
$this->assertEquals( $this->vendor_staff_id1, $data['id'], 'Store ID should match the requested staff ID' );
425+
// Verify sensitive data is filtered (staff accessing via their own ID is not authorized for that store)
426+
$this->assertArrayNotHasKey( 'payment', $data, 'Payment data should be hidden from unauthorized users' );
427+
$this->assertArrayNotHasKey( 'admin_commission', $data, 'Admin commission should be hidden from unauthorized users' );
404428
}
405429

406430
/**
@@ -472,7 +496,7 @@ public function test_authorization_with_invalid_vendor_id(): void {
472496
}
473497

474498
/**
475-
* Test that vendor staff cannot access store if vendor_id meta is missing.
499+
* Test that vendor staff without vendor_id meta can access store (public endpoint with filtered data).
476500
*
477501
* @return void
478502
*/
@@ -487,9 +511,17 @@ public function test_vendor_staff_without_vendor_id_meta_cannot_access_store():
487511

488512
wp_set_current_user( $orphan_staff_id );
489513

490-
// Try to access any store
514+
// Try to access any store (public endpoint, so access is allowed)
491515
$response = $this->get_request( "stores/{$this->seller_id1}" );
492-
$this->assertEquals( 403, $response->get_status(), 'Staff without vendor_id meta should not access store' );
516+
$this->assertEquals( 200, $response->get_status(), 'Staff without vendor_id meta can access store (public endpoint)' );
517+
518+
$data = $response->get_data();
519+
// Verify sensitive data is filtered (unauthorized access gets public data only)
520+
$this->assertArrayNotHasKey( 'payment', $data, 'Payment data should be hidden from unauthorized users' );
521+
$this->assertArrayNotHasKey( 'enabled', $data, 'Enabled status should be hidden from unauthorized users' );
522+
$this->assertArrayNotHasKey( 'admin_commission', $data, 'Admin commission should be hidden from unauthorized users' );
523+
// Verify public data is available
524+
$this->assertArrayHasKey( 'store_name', $data, 'Store name should be available (public data)' );
493525

494526
// Clean up
495527
wp_delete_user( $orphan_staff_id );

0 commit comments

Comments
 (0)