Skip to content

Commit 6faffa8

Browse files
jr-rkclaude
andcommitted
fix: add_member posts the canonical /eperson/epersons/ href (review)
Code review caught that add_member built the eperson uri-list body as `{API}/epersons/{uuid}`, dropping the `/eperson` path segment - the canonical href (used elsewhere in this file, e.g. get_user_by_email) is `/eperson/epersons/{uuid}`. The bare path does not resolve, so DSpace rejects the membership POST with 422 and add_member returns False. The new test asserted the malformed URI, pinning the bug. Corrected the URI in add_member and the assertion, and marked the test dtq_only: the fix lands on dtq while main still emits the old path, so it is deselected on the main leg of the differential-contract job. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent f49d0ee commit 6faffa8

2 files changed

Lines changed: 10 additions & 2 deletions

File tree

dspace_rest_client/client.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1290,7 +1290,9 @@ def add_member(self, group, eperson):
12901290
return False
12911291

12921292
url = f'{self.API_ENDPOINT}/eperson/groups/{group.uuid}/epersons'
1293-
eperson_uri = f'{self.API_ENDPOINT}/epersons/{eperson.uuid}'
1293+
# canonical eperson href is /eperson/epersons/{uuid}; a bare /epersons/
1294+
# path does not resolve and DSpace rejects the uri-list with a 422
1295+
eperson_uri = f'{self.API_ENDPOINT}/eperson/epersons/{eperson.uuid}'
12941296
r = self.api_post_uri(url, params=None, uri_list=eperson_uri)
12951297
if r.status_code == 204:
12961298
return True

tests/test_clarin_write.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,14 +165,20 @@ def _group(self):
165165
def _user(self):
166166
return User({"uuid": EPERSON_UUID, "email": "a@b.c"})
167167

168+
@pytest.mark.dtq_only
168169
def test_posts_eperson_uri_and_returns_true_on_204(self):
170+
"""The eperson uri-list body must be the canonical /eperson/epersons/
171+
href. dtq_only: the fix (dropping the bare /epersons/ path) lands on
172+
dtq; main still emits the malformed URI, so this is deselected on the
173+
main leg of the differential-contract job."""
169174
c = make_client()
170175
url = f"{API}/eperson/groups/{GROUP_UUID}/epersons"
171176
with requests_mock.Mocker() as m:
172177
m.post(url, status_code=204)
173178
self.assertTrue(c.add_member(self._group(), self._user()))
179+
# canonical eperson href - /eperson/epersons/, not a bare /epersons/
174180
self.assertEqual(m.last_request.text,
175-
f"{API}/epersons/{EPERSON_UUID}")
181+
f"{API}/eperson/epersons/{EPERSON_UUID}")
176182

177183
def test_non_204_returns_false(self):
178184
c = make_client()

0 commit comments

Comments
 (0)