Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 18 additions & 14 deletions gspread/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -327,26 +327,30 @@ def copy(

permissions = original.list_permissions()
for p in permissions:
if p.get("deleted"):
# Share the new spreadsheet with the same permissions as the original
# but don't share it with the owner of the original spreadsheet as
# Google API rejects that with the error response:
# APIError: [403]: The transferOwnership parameter must be enabled when the permission role is 'owner'.
if p.get("deleted") or p.get("role") == "owner":
continue

# .list_permissions() returns a list of permissions,
# even the folder permissions if the file is in a shared folder.
# We only want the permissions that are directly applied to the
# spreadsheet file, i.e. 'writer', 'commenter' and 'reader'.
perm_details = {
p_details.get("permissionType"): p_details.get("inherited")
for p_details in p.get("permissionDetails")
}
if p.get("role") in ("organizer", "fileOrganizer") and (
perm_details.get("file") or perm_details.get("member")
):
continue
# .list_permissions() when used in shared drive returns a list
# of permissions, even the folder permissions if the file is in
# a shared folder. We only want the permissions that are directly
# applied to the spreadsheet file, i.e. 'writer', 'commenter' and 'reader'.
if p.get("permissionDetails"):
perm_details = {
p_details.get("permissionType"): p_details.get("inherited")
for p_details in p.get("permissionDetails")
}
if p.get("role") in ("organizer", "fileOrganizer") and (
perm_details.get("file") or perm_details.get("member")
):
continue

# In case of domain type the domain extract the domain
# In case of user/group extract the emailAddress
# Otherwise use None for type 'Anyone'

email_or_domain = ""
if str(p["type"]) == "domain":
email_or_domain = str(p["domain"])
Expand Down
2 changes: 1 addition & 1 deletion gspread/spreadsheet.py
Original file line number Diff line number Diff line change
Expand Up @@ -543,7 +543,7 @@ def export(self, format: ExportFormat = ExportFormat.PDF) -> bytes:
"""
return self.client.export(self.id, format)

def list_permissions(self) -> List[Dict[str, Union[str, bool]]]:
def list_permissions(self) -> List[Dict[str, Union[str, bool, List[Dict[str, Union[str, bool]]]]]]:
"""Lists the spreadsheet's permissions."""
return self.client.list_permissions(self.id)

Expand Down
10 changes: 10 additions & 0 deletions tests/client_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,16 @@ def test_copy(self):
copy_metadata = spreadsheet_copy.fetch_sheet_metadata()
self.assertEqual(original_metadata["sheets"], copy_metadata["sheets"])

@pytest.mark.vcr()
def test_copy_in_shared_drive(self):
original_spreadsheet = self.spreadsheet
spreadsheet_copy = self.gc.copy(original_spreadsheet.id, copy_permissions=True)
self.assertIsInstance(spreadsheet_copy, gspread.Spreadsheet)

original_metadata = original_spreadsheet.fetch_sheet_metadata()
copy_metadata = spreadsheet_copy.fetch_sheet_metadata()
self.assertEqual(original_metadata["sheets"], copy_metadata["sheets"])

@pytest.mark.vcr()
def test_import_csv(self):
spreadsheet = self.spreadsheet
Expand Down