@@ -133,7 +133,10 @@ def test_api_documents_link_configuration_update_authenticated_related_success(
133133 client = APIClient ()
134134 client .force_login (user )
135135
136- document = factories .DocumentFactory ()
136+ document = factories .DocumentFactory (
137+ link_reach = models .LinkReachChoices .AUTHENTICATED ,
138+ link_role = models .LinkRoleChoices .READER ,
139+ )
137140 if via == USER :
138141 factories .UserDocumentAccessFactory (document = document , user = user , role = role )
139142 elif via == TEAM :
@@ -143,7 +146,10 @@ def test_api_documents_link_configuration_update_authenticated_related_success(
143146 )
144147
145148 new_document_values = serializers .LinkDocumentSerializer (
146- instance = factories .DocumentFactory ()
149+ instance = factories .DocumentFactory (
150+ link_reach = models .LinkReachChoices .PUBLIC ,
151+ link_role = models .LinkRoleChoices .EDITOR ,
152+ )
147153 ).data
148154
149155 with mock_reset_connections (document .id ):
@@ -158,3 +164,240 @@ def test_api_documents_link_configuration_update_authenticated_related_success(
158164 document_values = serializers .LinkDocumentSerializer (instance = document ).data
159165 for key , value in document_values .items ():
160166 assert value == new_document_values [key ]
167+
168+
169+ def test_api_documents_link_configuration_update_role_restricted_forbidden ():
170+ """
171+ Test that trying to set link_role on a document with restricted link_reach
172+ returns a validation error.
173+ """
174+ user = factories .UserFactory ()
175+ client = APIClient ()
176+ client .force_login (user )
177+
178+ document = factories .DocumentFactory (
179+ link_reach = models .LinkReachChoices .RESTRICTED ,
180+ link_role = models .LinkRoleChoices .READER ,
181+ )
182+
183+ factories .UserDocumentAccessFactory (
184+ document = document , user = user , role = models .RoleChoices .OWNER
185+ )
186+
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+ }
192+
193+ response = client .put (
194+ f"/api/v1.0/documents/{ document .id !s} /link-configuration/" ,
195+ new_data ,
196+ format = "json" ,
197+ )
198+
199+ assert response .status_code == 400
200+ assert "link_role" in response .json ()
201+ assert (
202+ "Cannot set link_role when link_reach is 'restricted'"
203+ in response .json ()["link_role" ][0 ]
204+ )
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+ mock_reset_connections , # pylint: disable=redefined-outer-name
240+ ):
241+ """
242+ Test that setting link_reach to restricted without specifying link_role succeeds.
243+ """
244+ user = factories .UserFactory ()
245+ client = APIClient ()
246+ client .force_login (user )
247+
248+ document = factories .DocumentFactory (
249+ link_reach = models .LinkReachChoices .PUBLIC ,
250+ link_role = models .LinkRoleChoices .READER ,
251+ )
252+
253+ factories .UserDocumentAccessFactory (
254+ document = document , user = user , role = models .RoleChoices .OWNER
255+ )
256+
257+ # Only specify link_reach, not link_role
258+ new_data = {
259+ "link_reach" : models .LinkReachChoices .RESTRICTED ,
260+ }
261+
262+ with mock_reset_connections (document .id ):
263+ response = client .put (
264+ f"/api/v1.0/documents/{ document .id !s} /link-configuration/" ,
265+ new_data ,
266+ format = "json" ,
267+ )
268+
269+ assert response .status_code == 200
270+ document .refresh_from_db ()
271+ assert document .link_reach == models .LinkReachChoices .RESTRICTED
272+
273+
274+ @pytest .mark .parametrize (
275+ "reach" , [models .LinkReachChoices .PUBLIC , models .LinkReachChoices .AUTHENTICATED ]
276+ )
277+ @pytest .mark .parametrize ("role" , models .LinkRoleChoices .values )
278+ def test_api_documents_link_configuration_update_non_restricted_with_valid_role_success (
279+ reach ,
280+ role ,
281+ mock_reset_connections , # pylint: disable=redefined-outer-name
282+ ):
283+ """
284+ Test that setting non-restricted link_reach with valid link_role succeeds.
285+ """
286+ user = factories .UserFactory ()
287+ client = APIClient ()
288+ client .force_login (user )
289+
290+ document = factories .DocumentFactory (
291+ link_reach = models .LinkReachChoices .RESTRICTED ,
292+ link_role = models .LinkRoleChoices .READER ,
293+ )
294+
295+ factories .UserDocumentAccessFactory (
296+ document = document , user = user , role = models .RoleChoices .OWNER
297+ )
298+
299+ new_data = {
300+ "link_reach" : reach ,
301+ "link_role" : role ,
302+ }
303+
304+ with mock_reset_connections (document .id ):
305+ response = client .put (
306+ f"/api/v1.0/documents/{ document .id !s} /link-configuration/" ,
307+ new_data ,
308+ format = "json" ,
309+ )
310+
311+ assert response .status_code == 200
312+ document .refresh_from_db ()
313+ assert document .link_reach == reach
314+ assert document .link_role == role
315+
316+
317+ def test_api_documents_link_configuration_update_with_ancestor_constraints ():
318+ """
319+ Test that link configuration respects ancestor constraints using get_select_options.
320+ This test may need adjustment based on the actual get_select_options implementation.
321+ """
322+ user = factories .UserFactory ()
323+ client = APIClient ()
324+ client .force_login (user )
325+
326+ parent_document = factories .DocumentFactory (
327+ link_reach = models .LinkReachChoices .PUBLIC ,
328+ link_role = models .LinkRoleChoices .READER ,
329+ )
330+
331+ child_document = factories .DocumentFactory (
332+ parent = parent_document ,
333+ link_reach = models .LinkReachChoices .PUBLIC ,
334+ link_role = models .LinkRoleChoices .READER ,
335+ )
336+
337+ factories .UserDocumentAccessFactory (
338+ document = child_document , user = user , role = models .RoleChoices .OWNER
339+ )
340+
341+ # Try to set child to PUBLIC when parent is RESTRICTED
342+ new_data = {
343+ "link_reach" : models .LinkReachChoices .RESTRICTED ,
344+ "link_role" : models .LinkRoleChoices .READER ,
345+ }
346+
347+ response = client .put (
348+ f"/api/v1.0/documents/{ child_document .id !s} /link-configuration/" ,
349+ new_data ,
350+ format = "json" ,
351+ )
352+
353+ assert response .status_code == 400
354+ assert "link_reach" in response .json ()
355+ assert (
356+ "Link reach 'restricted' is not allowed based on parent"
357+ in response .json ()["link_reach" ][0 ]
358+ )
359+
360+
361+ def test_api_documents_link_configuration_update_invalid_role_for_reach_validation ():
362+ """
363+ Test the specific validation logic that checks if link_role is allowed for link_reach.
364+ This tests the code section that validates allowed_roles from get_select_options.
365+ """
366+ user = factories .UserFactory ()
367+ client = APIClient ()
368+ client .force_login (user )
369+
370+ parent_document = factories .DocumentFactory (
371+ link_reach = models .LinkReachChoices .AUTHENTICATED ,
372+ link_role = models .LinkRoleChoices .EDITOR ,
373+ )
374+
375+ child_document = factories .DocumentFactory (
376+ parent = parent_document ,
377+ link_reach = models .LinkReachChoices .RESTRICTED ,
378+ link_role = models .LinkRoleChoices .READER ,
379+ )
380+
381+ factories .UserDocumentAccessFactory (
382+ document = child_document , user = user , role = models .RoleChoices .OWNER
383+ )
384+
385+ new_data = {
386+ "link_reach" : models .LinkReachChoices .AUTHENTICATED ,
387+ "link_role" : models .LinkRoleChoices .READER , # This should be rejected
388+ }
389+
390+ response = client .put (
391+ f"/api/v1.0/documents/{ child_document .id !s} /link-configuration/" ,
392+ new_data ,
393+ format = "json" ,
394+ )
395+
396+ assert response .status_code == 400
397+ assert "link_role" in response .json ()
398+ error_message = response .json ()["link_role" ][0 ]
399+ assert (
400+ "Link role 'reader' is not allowed for link reach 'authenticated'"
401+ in error_message
402+ )
403+ assert "Allowed roles: editor" in error_message
0 commit comments