Skip to content

Commit 3c2f606

Browse files
authored
Merge pull request #120 from rstudio/fix-rsc-pin-write
fix(rsconnect): raise error if attempting to create content for other user
2 parents f494dff + 9cca758 commit 3c2f606

File tree

2 files changed

+38
-12
lines changed

2 files changed

+38
-12
lines changed

pins/boards.py

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -276,10 +276,12 @@ def pin_write(
276276
dst_pin_path = self.construct_path([pin_name])
277277
dst_version_path = self.path_to_deploy_version(name, meta.version.version)
278278

279-
try:
280-
self.fs.mkdir(dst_pin_path)
281-
except FileExistsError:
282-
pass
279+
if not self.fs.exists(dst_pin_path):
280+
# equivalent to mkdirp, want to fail quietly in case of race conditions
281+
try:
282+
self.fs.mkdir(dst_pin_path)
283+
except FileExistsError:
284+
pass
283285

284286
# put tmp pin dir onto backend filesystem
285287
# TODO: if we allow the rsc backend to fs.exists("<user>/<content>/latest")
@@ -747,25 +749,34 @@ def pin_write(self, *args, access_type=None, **kwargs):
747749
* Adds access_type argument to specify who can see content. Defaults to "acl".
748750
"""
749751

750-
# run parent function ---
751-
752752
f_super = super().pin_write
753-
meta = f_super(*args, **kwargs)
754753

755-
# update content title to reflect what's in metadata ----
756-
757-
# TODO(question): R pins updates this info before writing the pin..?
758754
# bind the original signature to get pin name
759755
sig = inspect.signature(f_super)
760756
bind = sig.bind(*args, **kwargs)
761-
762757
pin_name = self.path_to_pin(bind.arguments["name"])
758+
759+
if pin_name.split("/")[0] != self.user_name and not self.fs.exists(pin_name):
760+
# TODO: fs.mkdir here would erroneously create content for the user calling the API
761+
# even if they were trying to create a content item for another user. we catch it here,
762+
# but should also fix things downstream.
763+
raise PinsError(
764+
f"You are connected as {self.user_name}, but you are trying to create a new piece"
765+
f" of content for another user ({pin_name}). They must create the content before you"
766+
" can write to it."
767+
)
768+
769+
# run parent function ---
770+
meta = f_super(*args, **kwargs)
771+
772+
# update content title to reflect what's in metadata ----
773+
# TODO(question): R pins updates this info before writing the pin..?
763774
content = self.fs.info(pin_name)
764775
self.fs.api.patch_content_item(
765776
content["guid"],
766777
title=meta.title,
767778
description=meta.description or "",
768-
# access_type = content.access_type
779+
access_type=access_type or content["access_type"],
769780
)
770781

771782
return meta

pins/tests/test_boards.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,21 @@ def test_board_rsc_require_full_pin_name(board_short):
416416
assert "Invalid pin name" in exc_info.value.args[0]
417417

418418

419+
@pytest.mark.fs_rsc
420+
def test_board_rsc_pin_write_other_user_fails(df, board_short):
421+
with pytest.raises(PinsError) as exc_info:
422+
board_short.pin_write(df, "derek/mtcarszzzzz")
423+
424+
assert "a new piece of content for another user" in exc_info.value.args[0]
425+
426+
427+
@pytest.mark.fs_rsc
428+
def test_board_rsc_pin_write_acl(df, board_short):
429+
board_short.pin_write(df, "susan/mtcars", type="csv", access_type="all")
430+
content = board_short.fs.info("susan/mtcars")
431+
assert content["access_type"] == "all"
432+
433+
419434
# Manual Board Specific =======================================================
420435

421436
from pins.boards import BoardManual # noqa

0 commit comments

Comments
 (0)