@@ -184,7 +184,11 @@ def test_api_documents_link_configuration_update_role_restricted_forbidden():
184184 document = document , user = user , role = models .RoleChoices .OWNER
185185 )
186186
187- new_data = {"link_role" : models .LinkRoleChoices .EDITOR }
187+ # Try to set a meaningful role on a restricted document
188+ new_data = {
189+ "link_reach" : models .LinkReachChoices .RESTRICTED ,
190+ "link_role" : models .LinkRoleChoices .EDITOR ,
191+ }
188192
189193 response = client .put (
190194 f"/api/v1.0/documents/{ document .id !s} /link-configuration/" ,
@@ -198,3 +202,196 @@ def test_api_documents_link_configuration_update_role_restricted_forbidden():
198202 "Cannot set link_role when link_reach is 'restricted'"
199203 in response .json ()["link_role" ][0 ]
200204 )
205+
206+
207+ def test_api_documents_link_configuration_update_link_reach_required ():
208+ """
209+ Test that link_reach is required when updating link configuration.
210+ """
211+ user = factories .UserFactory ()
212+ client = APIClient ()
213+ client .force_login (user )
214+
215+ document = factories .DocumentFactory (
216+ link_reach = models .LinkReachChoices .PUBLIC ,
217+ link_role = models .LinkRoleChoices .READER ,
218+ )
219+
220+ factories .UserDocumentAccessFactory (
221+ document = document , user = user , role = models .RoleChoices .OWNER
222+ )
223+
224+ # Try to update without providing link_reach
225+ new_data = {"link_role" : models .LinkRoleChoices .EDITOR }
226+
227+ response = client .put (
228+ f"/api/v1.0/documents/{ document .id !s} /link-configuration/" ,
229+ new_data ,
230+ format = "json" ,
231+ )
232+
233+ assert response .status_code == 400
234+ assert "link_reach" in response .json ()
235+ assert "This field is required" in response .json ()["link_reach" ][0 ]
236+
237+
238+ def test_api_documents_link_configuration_update_restricted_without_role_success ():
239+ """
240+ Test that setting link_reach to restricted without specifying link_role succeeds.
241+ """
242+ user = factories .UserFactory ()
243+ client = APIClient ()
244+ client .force_login (user )
245+
246+ document = factories .DocumentFactory (
247+ link_reach = models .LinkReachChoices .PUBLIC ,
248+ link_role = models .LinkRoleChoices .READER ,
249+ )
250+
251+ factories .UserDocumentAccessFactory (
252+ document = document , user = user , role = models .RoleChoices .OWNER
253+ )
254+
255+ # Only specify link_reach, not link_role
256+ new_data = {
257+ "link_reach" : models .LinkReachChoices .RESTRICTED ,
258+ }
259+
260+ response = client .put (
261+ f"/api/v1.0/documents/{ document .id !s} /link-configuration/" ,
262+ new_data ,
263+ format = "json" ,
264+ )
265+
266+ assert response .status_code == 200
267+ document .refresh_from_db ()
268+ assert document .link_reach == models .LinkReachChoices .RESTRICTED
269+
270+
271+ @pytest .mark .parametrize (
272+ "reach" , [models .LinkReachChoices .PUBLIC , models .LinkReachChoices .AUTHENTICATED ]
273+ )
274+ @pytest .mark .parametrize ("role" , models .LinkRoleChoices .values )
275+ def test_api_documents_link_configuration_update_non_restricted_with_valid_role_success (
276+ reach , role
277+ ):
278+ """
279+ Test that setting non-restricted link_reach with valid link_role succeeds.
280+ """
281+ user = factories .UserFactory ()
282+ client = APIClient ()
283+ client .force_login (user )
284+
285+ document = factories .DocumentFactory (
286+ link_reach = models .LinkReachChoices .RESTRICTED ,
287+ link_role = models .LinkRoleChoices .READER ,
288+ )
289+
290+ factories .UserDocumentAccessFactory (
291+ document = document , user = user , role = models .RoleChoices .OWNER
292+ )
293+
294+ new_data = {
295+ "link_reach" : reach ,
296+ "link_role" : role ,
297+ }
298+
299+ response = client .put (
300+ f"/api/v1.0/documents/{ document .id !s} /link-configuration/" ,
301+ new_data ,
302+ format = "json" ,
303+ )
304+
305+ assert response .status_code == 200
306+ document .refresh_from_db ()
307+ assert document .link_reach == reach
308+ assert document .link_role == role
309+
310+
311+ def test_api_documents_link_configuration_update_with_ancestor_constraints ():
312+ """
313+ Test that link configuration respects ancestor constraints using get_select_options.
314+ This test may need adjustment based on the actual get_select_options implementation.
315+ """
316+ user = factories .UserFactory ()
317+ client = APIClient ()
318+ client .force_login (user )
319+
320+ parent_document = factories .DocumentFactory (
321+ link_reach = models .LinkReachChoices .PUBLIC ,
322+ link_role = models .LinkRoleChoices .READER ,
323+ )
324+
325+ child_document = factories .DocumentFactory (
326+ parent = parent_document ,
327+ link_reach = models .LinkReachChoices .PUBLIC ,
328+ link_role = models .LinkRoleChoices .READER ,
329+ )
330+
331+ factories .UserDocumentAccessFactory (
332+ document = child_document , user = user , role = models .RoleChoices .OWNER
333+ )
334+
335+ # Try to set child to PUBLIC when parent is RESTRICTED
336+ new_data = {
337+ "link_reach" : models .LinkReachChoices .RESTRICTED ,
338+ "link_role" : models .LinkRoleChoices .READER ,
339+ }
340+
341+ response = client .put (
342+ f"/api/v1.0/documents/{ child_document .id !s} /link-configuration/" ,
343+ new_data ,
344+ format = "json" ,
345+ )
346+
347+ assert response .status_code == 400
348+ assert "link_reach" in response .json ()
349+ assert (
350+ "Link reach 'restricted' is not allowed based on parent"
351+ in response .json ()["link_reach" ][0 ]
352+ )
353+
354+
355+ def test_api_documents_link_configuration_update_invalid_role_for_reach_validation ():
356+ """
357+ Test the specific validation logic that checks if link_role is allowed for link_reach.
358+ This tests the code section that validates allowed_roles from get_select_options.
359+ """
360+ user = factories .UserFactory ()
361+ client = APIClient ()
362+ client .force_login (user )
363+
364+ parent_document = factories .DocumentFactory (
365+ link_reach = models .LinkReachChoices .AUTHENTICATED ,
366+ link_role = models .LinkRoleChoices .EDITOR ,
367+ )
368+
369+ child_document = factories .DocumentFactory (
370+ parent = parent_document ,
371+ link_reach = models .LinkReachChoices .RESTRICTED ,
372+ link_role = models .LinkRoleChoices .READER ,
373+ )
374+
375+ factories .UserDocumentAccessFactory (
376+ document = child_document , user = user , role = models .RoleChoices .OWNER
377+ )
378+
379+ new_data = {
380+ "link_reach" : models .LinkReachChoices .AUTHENTICATED ,
381+ "link_role" : models .LinkRoleChoices .READER , # This should be rejected
382+ }
383+
384+ response = client .put (
385+ f"/api/v1.0/documents/{ child_document .id !s} /link-configuration/" ,
386+ new_data ,
387+ format = "json" ,
388+ )
389+
390+ assert response .status_code == 400
391+ assert "link_role" in response .json ()
392+ error_message = response .json ()["link_role" ][0 ]
393+ assert (
394+ "Link role 'reader' is not allowed for link reach 'authenticated'"
395+ in error_message
396+ )
397+ assert "Allowed roles: editor" in error_message
0 commit comments