@@ -1009,6 +1009,10 @@ def test_sort_resources(self):
10091009 reversed_resource_titles = sorted (resource_titles .copy ())
10101010 self .assertNotEqual (resource_titles , reversed_resource_titles )
10111011
1012+ @override_settings (
1013+ EDITORS_CAN_MANAGE_ANONYMOUS_PERMISSIONS = True ,
1014+ EDITORS_CAN_MANAGE_REGISTERED_MEMBERS_PERMISSIONS = True ,
1015+ )
10121016 def test_perms_resources (self ):
10131017 """
10141018 Ensure we can Get & Set Permissions across the Resource Base list.
@@ -1164,7 +1168,9 @@ def test_perms_resources(self):
11641168 resource_perm_spec ,
11651169 )
11661170
1167- # Remove perms to Norman
1171+ # Remove perms to Norman by explicitly setting permissions to "none".
1172+ # Note: Omitting a user from the request preserves their existing permissions.
1173+ # To actually remove permissions, you must explicitly set them to "none".
11681174 resource_perm_spec = {
11691175 "uuid" : resource .uuid ,
11701176 "users" : [
@@ -1178,6 +1184,16 @@ def test_perms_resources(self):
11781184 "is_staff" : False ,
11791185 "is_superuser" : False ,
11801186 },
1187+ {
1188+ "id" : norman .id ,
1189+ "username" : norman .username ,
1190+ "first_name" : norman .first_name ,
1191+ "last_name" : norman .last_name ,
1192+ "avatar" : build_absolute_uri (avatar_url (bobby )),
1193+ "permissions" : "none" ,
1194+ "is_staff" : False ,
1195+ "is_superuser" : False ,
1196+ },
11811197 {
11821198 "avatar" : build_absolute_uri (avatar_url (bobby )),
11831199 "first_name" : "admin" ,
@@ -2341,6 +2357,248 @@ def test_manager_can_edit_map(self):
23412357 resource_perm_spec ,
23422358 )
23432359
2360+ @override_settings (
2361+ EDITORS_CAN_MANAGE_ANONYMOUS_PERMISSIONS = False ,
2362+ EDITORS_CAN_MANAGE_REGISTERED_MEMBERS_PERMISSIONS = False ,
2363+ )
2364+ def test_resource_service_permissions_with_restricted_settings (self ):
2365+ """
2366+ Test that when EDITORS_CAN_MANAGE_ANONYMOUS_PERMISSIONS and
2367+ EDITORS_CAN_MANAGE_REGISTERED_MEMBERS_PERMISSIONS are set to False,
2368+ only staff/admin users can modify anonymous and registered members permissions.
2369+ Non-staff editors should not be able to modify these groups' permissions.
2370+ """
2371+ resource = Dataset .objects .filter (owner__username = "admin" ).first ()
2372+ bobby = get_user_model ().objects .get (username = "bobby" )
2373+
2374+ # Give bobby edit permissions on the resource including permission to manage permissions
2375+ resource .set_permissions (
2376+ {
2377+ "users" : {
2378+ bobby : [
2379+ "base.change_resourcebase" ,
2380+ "base.change_resourcebase_metadata" ,
2381+ "base.change_resourcebase_permissions" ,
2382+ ]
2383+ }
2384+ }
2385+ )
2386+
2387+ # Login as bobby (non-staff editor)
2388+ self .assertTrue (self .client .login (username = "bobby" , password = "bob" ))
2389+
2390+ anonymous_group = Group .objects .get (name = "anonymous" )
2391+ registered_group = Group .objects .get (name = "registered-members" )
2392+
2393+ # Try to update permissions including anonymous and registered members groups
2394+ set_perms_url = urljoin (f"{ reverse ('base-resources-detail' , kwargs = {'pk' : resource .pk })} /" , "permissions" )
2395+ perm_spec = {
2396+ "uuid" : resource .uuid ,
2397+ "groups" : [
2398+ {
2399+ "id" : anonymous_group .id ,
2400+ "name" : "anonymous" ,
2401+ "permissions" : "view" ,
2402+ },
2403+ {
2404+ "id" : registered_group .id ,
2405+ "name" : "registered-members" ,
2406+ "permissions" : "download" ,
2407+ },
2408+ ],
2409+ }
2410+
2411+ response = self .client .put (set_perms_url , data = perm_spec , format = "json" )
2412+ self .assertEqual (response .status_code , 200 )
2413+
2414+ resp_js = json .loads (response .content .decode ("utf-8" ))
2415+ execution_id = resp_js .get ("execution_id" , "" )
2416+ status_url = resp_js .get ("status_url" , None )
2417+ self .assertIsNotNone (status_url )
2418+ self .assertIsNotNone (execution_id )
2419+
2420+ for _cnt in range (0 , 10 ):
2421+ response = self .client .get (f"{ status_url } " )
2422+ self .assertEqual (response .status_code , 200 )
2423+ resp_js = json .loads (response .content .decode ("utf-8" ))
2424+ if resp_js .get ("status" , "" ) == "finished" :
2425+ break
2426+ else :
2427+ resouce_service_dispatcher .apply ((execution_id ,))
2428+ sleep (3.0 )
2429+
2430+ # Get the current permissions to verify anonymous and registered groups were excluded
2431+ get_perms_url = urljoin (f"{ reverse ('base-resources-detail' , kwargs = {'pk' : resource .pk })} /" , "permissions" )
2432+ response = self .client .get (get_perms_url , format = "json" )
2433+ self .assertEqual (response .status_code , 200 )
2434+ resource_perm_spec = response .data
2435+
2436+ groups_in_response = {g ["name" ]: g ["permissions" ] for g in resource_perm_spec .get ("groups" , [])}
2437+
2438+ # The groups should still have their original permissions (not the ones bobby tried to set)
2439+ # Bobby tried to set anonymous to "view" and registered-members to "download"
2440+ # But since he lacks permissions, these changes should NOT have been applied
2441+ # Verify the permissions remain unchanged from their original state
2442+ self .assertIn ("anonymous" , groups_in_response )
2443+ self .assertIn ("registered-members" , groups_in_response )
2444+ # The permissions should NOT be what bobby tried to set
2445+ self .assertNotEqual (
2446+ groups_in_response .get ("anonymous" ), "view" , "Bobby should not have been able to set anonymous to view"
2447+ )
2448+ self .assertNotEqual (
2449+ groups_in_response .get ("registered-members" ),
2450+ "download" ,
2451+ "Bobby should not have been able to set registered-members to download" ,
2452+ )
2453+
2454+ # login as admin (staff user) and verify admin can modify these permissions
2455+ self .assertTrue (self .client .login (username = "admin" , password = "admin" ))
2456+
2457+ perm_spec_admin = {
2458+ "uuid" : resource .uuid ,
2459+ "groups" : [
2460+ {
2461+ "id" : anonymous_group .id ,
2462+ "name" : "anonymous" ,
2463+ "permissions" : "view" ,
2464+ },
2465+ {
2466+ "id" : registered_group .id ,
2467+ "name" : "registered-members" ,
2468+ "permissions" : "view" ,
2469+ },
2470+ ],
2471+ }
2472+
2473+ response = self .client .put (set_perms_url , data = perm_spec_admin , format = "json" )
2474+ self .assertEqual (response .status_code , 200 )
2475+
2476+ # Wait for async task to complete
2477+ resp_js = json .loads (response .content .decode ("utf-8" ))
2478+ execution_id = resp_js .get ("execution_id" , "" )
2479+ status_url = resp_js .get ("status_url" , None )
2480+
2481+ for _cnt in range (0 , 10 ):
2482+ response = self .client .get (f"{ status_url } " )
2483+ self .assertEqual (response .status_code , 200 )
2484+ resp_js = json .loads (response .content .decode ("utf-8" ))
2485+ if resp_js .get ("status" , "" ) == "finished" :
2486+ break
2487+ else :
2488+ resouce_service_dispatcher .apply ((execution_id ,))
2489+ sleep (3.0 )
2490+
2491+ # Verify admin successfully modified the permissions
2492+ response = self .client .get (get_perms_url , format = "json" )
2493+ self .assertEqual (response .status_code , 200 )
2494+ resource_perm_spec = response .data
2495+
2496+ # Admin should have been able to set permissions for these groups
2497+ groups_in_response = {g ["name" ]: g ["permissions" ] for g in resource_perm_spec .get ("groups" , [])}
2498+ self .assertIn ("anonymous" , groups_in_response )
2499+ self .assertIn ("registered-members" , groups_in_response )
2500+ # Verify admin successfully changed the permissions to what was requested
2501+ self .assertEqual (
2502+ groups_in_response .get ("anonymous" ), "view" , "Admin should have been able to set anonymous to view"
2503+ )
2504+ self .assertEqual (
2505+ groups_in_response .get ("registered-members" ),
2506+ "view" ,
2507+ "Admin should have been able to set registered-members to view" ,
2508+ )
2509+
2510+ @override_settings (
2511+ EDITORS_CAN_MANAGE_ANONYMOUS_PERMISSIONS = True ,
2512+ EDITORS_CAN_MANAGE_REGISTERED_MEMBERS_PERMISSIONS = False ,
2513+ )
2514+ def test_resource_service_permissions_with_partial_restriction (self ):
2515+ """
2516+ Test that when only EDITORS_CAN_MANAGE_REGISTERED_MEMBERS_PERMISSIONS is False,
2517+ editors can modify anonymous permissions but not registered members permissions.
2518+ """
2519+ resource = Dataset .objects .filter (owner__username = "admin" ).first ()
2520+ bobby = get_user_model ().objects .get (username = "bobby" )
2521+
2522+ # Give bobby edit permissions including permission to manage permissions
2523+ resource .set_permissions (
2524+ {
2525+ "users" : {
2526+ bobby : [
2527+ "base.change_resourcebase" ,
2528+ "base.change_resourcebase_metadata" ,
2529+ "base.change_resourcebase_permissions" ,
2530+ ]
2531+ }
2532+ }
2533+ )
2534+
2535+ # Login as bobby
2536+ self .assertTrue (self .client .login (username = "bobby" , password = "bob" ))
2537+
2538+ anonymous_group = Group .objects .get (name = "anonymous" )
2539+ registered_group = Group .objects .get (name = "registered-members" )
2540+
2541+ set_perms_url = urljoin (f"{ reverse ('base-resources-detail' , kwargs = {'pk' : resource .pk })} /" , "permissions" )
2542+ perm_spec = {
2543+ "uuid" : resource .uuid ,
2544+ "groups" : [
2545+ {
2546+ "id" : anonymous_group .id ,
2547+ "name" : "anonymous" ,
2548+ "permissions" : "view" ,
2549+ },
2550+ {
2551+ "id" : registered_group .id ,
2552+ "name" : "registered-members" ,
2553+ "permissions" : "download" ,
2554+ },
2555+ ],
2556+ }
2557+
2558+ response = self .client .put (set_perms_url , data = perm_spec , format = "json" )
2559+ self .assertEqual (response .status_code , 200 )
2560+
2561+ resp_js = json .loads (response .content .decode ("utf-8" ))
2562+ execution_id = resp_js .get ("execution_id" , "" )
2563+ status_url = resp_js .get ("status_url" , None )
2564+
2565+ for _cnt in range (0 , 10 ):
2566+ response = self .client .get (f"{ status_url } " )
2567+ self .assertEqual (response .status_code , 200 )
2568+ resp_js = json .loads (response .content .decode ("utf-8" ))
2569+ if resp_js .get ("status" , "" ) == "finished" :
2570+ break
2571+ else :
2572+ resouce_service_dispatcher .apply ((execution_id ,))
2573+ sleep (3.0 )
2574+
2575+ # Verify bobby could modify anonymous but not registered members
2576+ # The registered-members group should have been filtered out from bobby's request
2577+ get_perms_url = urljoin (f"{ reverse ('base-resources-detail' , kwargs = {'pk' : resource .pk })} /" , "permissions" )
2578+ response = self .client .get (get_perms_url , format = "json" )
2579+ self .assertEqual (response .status_code , 200 )
2580+ resource_perm_spec = response .data
2581+
2582+ groups_in_response = {g ["name" ]: g ["permissions" ] for g in resource_perm_spec .get ("groups" , [])}
2583+
2584+ # Bobby tried to set anonymous to "view" and registered-members to "download"
2585+ # Since EDITORS_CAN_MANAGE_ANONYMOUS_PERMISSIONS=True, anonymous should be changed
2586+ # Since EDITORS_CAN_MANAGE_REGISTERED_MEMBERS_PERMISSIONS=False, registered-members should NOT be changed
2587+ self .assertIn ("anonymous" , groups_in_response )
2588+ self .assertIn ("registered-members" , groups_in_response )
2589+
2590+ # Verify anonymous was successfully changed by bobby
2591+ self .assertEqual (
2592+ groups_in_response .get ("anonymous" ), "view" , "Bobby should have been able to set anonymous to view"
2593+ )
2594+
2595+ # Verify registered-members was NOT changed by bobby
2596+ self .assertNotEqual (
2597+ groups_in_response .get ("registered-members" ),
2598+ "download" ,
2599+ "Bobby should not have been able to set registered-members to download" ,
2600+ )
2601+
23442602 def test_resource_service_copy (self ):
23452603 files = os .path .join (gisdata .GOOD_DATA , "vector/single_point.shp" )
23462604 files_as_dict , _ = get_files (files )
0 commit comments