@@ -586,6 +586,70 @@ def test_api_product_endpoint_cyclonedx_sbom_action(self):
586586 self .assertEqual (status .HTTP_400_BAD_REQUEST , response .status_code )
587587 self .assertEqual ("Spec version 10.10 not supported" , response .data )
588588
589+ def test_api_product_endpoint_manage_permissions_action (self ):
590+ url = reverse ("api_v2:product-manage-permissions" , args = [self .product1 .uuid ])
591+
592+ # User without view_product gets 404 (object not in secured queryset)
593+ self .client .login (username = self .base_user .username , password = "secret" )
594+ response = self .client .get (url )
595+ self .assertEqual (status .HTTP_404_NOT_FOUND , response .status_code )
596+
597+ # User with view_product but not owner gets 403
598+ assign_perm ("view_product" , self .base_user , self .product1 )
599+ response = self .client .get (url )
600+ self .assertEqual (status .HTTP_403_FORBIDDEN , response .status_code )
601+
602+ # Superuser can GET the permissions list
603+ self .client .login (username = self .super_user .username , password = "secret" )
604+ response = self .client .get (url )
605+ self .assertEqual (status .HTTP_200_OK , response .status_code )
606+ # base_user has view_product at this point
607+ self .assertEqual (1 , len (response .data ))
608+ self .assertEqual (self .base_user .username , response .data [0 ]["username" ])
609+ self .assertIn ("view_product" , response .data [0 ]["object_permissions" ])
610+
611+ # Superuser can POST to assign permissions
612+ data = {"user" : self .admin_user .username , "permissions" : ["view_product" ]}
613+ response = self .client .post (url , data , format = "json" )
614+ self .assertEqual (status .HTTP_200_OK , response .status_code )
615+ self .assertEqual ({"status" : "permissions assigned" }, response .data )
616+ self .assertIn ("view_product" , get_perms (self .admin_user , self .product1 ))
617+
618+ # Superuser can DELETE to remove permissions
619+ data = {"user" : self .admin_user .username , "permissions" : ["view_product" ]}
620+ response = self .client .delete (url , data , content_type = "application/json" )
621+ self .assertEqual (status .HTTP_200_OK , response .status_code )
622+ self .assertEqual ({"status" : "permissions removed" }, response .data )
623+ self .assertNotIn ("view_product" , get_perms (self .admin_user , self .product1 ))
624+
625+ # Product creator (created_by) can manage permissions
626+ self .product1 .created_by = self .admin_user
627+ self .product1 .save ()
628+ assign_perm ("view_product" , self .admin_user , self .product1 )
629+ self .client .login (username = self .admin_user .username , password = "secret" )
630+ data = {"user" : self .base_user .username , "permissions" : ["change_product" ]}
631+ response = self .client .post (url , data , format = "json" )
632+ self .assertEqual (status .HTTP_200_OK , response .status_code )
633+ self .assertIn ("change_product" , get_perms (self .base_user , self .product1 ))
634+
635+ # Invalid permission codename returns 400
636+ self .client .login (username = self .super_user .username , password = "secret" )
637+ data = {"user" : self .base_user .username , "permissions" : ["nonexistent_perm" ]}
638+ response = self .client .post (url , data , format = "json" )
639+ self .assertEqual (status .HTTP_400_BAD_REQUEST , response .status_code )
640+ self .assertIn ("errors" , response .data )
641+
642+ # Missing required fields returns 400
643+ response = self .client .post (url , {}, format = "json" )
644+ self .assertEqual (status .HTTP_400_BAD_REQUEST , response .status_code )
645+ self .assertIn ("errors" , response .data )
646+
647+ # Empty permissions list returns 400
648+ data = {"user" : self .base_user .username , "permissions" : []}
649+ response = self .client .post (url , data , format = "json" )
650+ self .assertEqual (status .HTTP_400_BAD_REQUEST , response .status_code )
651+ self .assertIn ("errors" , response .data )
652+
589653
590654class ProductRelatedAPITestCase (TestCase ):
591655 def setUp (self ):
0 commit comments