tidyverse/googledrive

Unclear how to access "shared folders" from "shared drives" vs. shared

jmobrien opened this issue · 2 comments

Encountering issues where googledrive is unable to usefully access anything inside a shared FOLDER that comes from a shared drive. Permissions as Content Manager. Limited to these specific shared folders--full shared drives work fine using the usual techniques, as do shared folders that do not come from a shared drive.

This appears similar to #402, but the ultimate guidance there does not seem to work. Example below:

require(googledrive)
#> Loading required package: googledrive

drive_find(type = "folders")  
# (not run for brevity)
#    drive_find() output doesn't include any of several folders shared from shared drive(s)
#    (Does list other shared folders from non-shared-drive accounts, as well as usual folders):


# ID of a shared folder from a shared drive (obtained from webpage, masked here and below):
folder_id <- 
  "[[folderID]]"

# Get dribble for folder using ID (this DOES work fine):
folder_dribble <- 
  as_id(folder_id) |> 
  drive_get()

# Dribble seems to contain the ID of a Shared Drive (masked again)
(drive_id <- 
  folder_dribble$drive_resource[[1]]$driveId)
#> [1] "[[driveID]]"

# But, trying to search using the dribble, per guidance in #402, doesn't work:
drive_ls(folder_dribble)
#> Error in `map()`:
#> ℹ In index: 1.
#> Caused by error in `.f()`:
#> ! Client error: (404) Not Found
#> Shared drive not found: [[driveID]]
#> • message: Shared drive not found: [[driveID]]
#> • domain: global
#> • reason: notFound
#> • location: driveId
#> • locationType: parameter
#> Backtrace:
#>      ▆
#>   1. └─googledrive::drive_ls(folder_dribble)
#>   2.   ├─rlang::exec(drive_find, !!!params)
#>   3.   └─googledrive (local) `<fn>`(shared_drive = `<drv_id>`, q = "('[[folderID]]' in parents)")
#>   4.     ├─base::append(params, handle_shared_drives(shared_drive, corpus))
#>   5.     └─googledrive:::handle_shared_drives(shared_drive, corpus)
#>   6.       ├─googledrive::as_shared_drive(shared_drive)
#>   7.       └─googledrive:::as_shared_drive.drive_id(shared_drive)
#>   8.         └─googledrive::shared_drive_get(id = x)
#>   9.           ├─googledrive::as_dribble(map(as_id(id), get_one_shared_drive_id))
#>  10.           └─purrr::map(as_id(id), get_one_shared_drive_id)
#>  11.             └─purrr:::map_("list", .x, .f, ..., .progress = .progress)
#>  12.               ├─purrr:::with_indexed_errors(...)
#>  13.               │ └─base::withCallingHandlers(...)
#>  14.               ├─purrr:::call_with_cleanup(...)
#>  15.               └─googledrive (local) .f(.x[[i]], ...)
#>  16.                 └─gargle::response_process(response)
#>  17.                   └─gargle:::gargle_abort_request_failed(...)
#>  18.                     └─gargle:::gargle_abort(...)
#>  19.                       └─cli::cli_abort(...)
#>  20.                         └─rlang::abort(...)

# Permissions on the shared folder in question, in case it's relevant:
folder_dribble$drive_resource[[1]]$capabilities |> 
  unlist() |> tibble::enframe() |> print(n = Inf)
#> # A tibble: 35 × 2
#>    name                                  value
#>    <chr>                                 <lgl>
#>  1 canAddChildren                        TRUE 
#>  2 canAddFolderFromAnotherDrive          FALSE
#>  3 canChangeCopyRequiresWriterPermission FALSE
#>  4 canChangeSecurityUpdateEnabled        FALSE
#>  5 canChangeViewersCanCopyContent        FALSE
#>  6 canComment                            TRUE 
#>  7 canCopy                               TRUE 
#>  8 canDelete                             FALSE
#>  9 canDeleteChildren                     FALSE
#> 10 canDownload                           TRUE 
#> 11 canEdit                               TRUE 
#> 12 canListChildren                       TRUE 
#> 13 canModifyContent                      TRUE 
#> 14 canModifyContentRestriction           FALSE
#> 15 canModifyLabels                       FALSE
#> 16 canMoveChildrenOutOfTeamDrive         FALSE
#> 17 canMoveChildrenOutOfDrive             FALSE
#> 18 canMoveChildrenWithinTeamDrive        TRUE 
#> 19 canMoveChildrenWithinDrive            TRUE 
#> 20 canMoveItemIntoTeamDrive              FALSE
#> 21 canMoveItemOutOfTeamDrive             FALSE
#> 22 canMoveItemOutOfDrive                 FALSE
#> 23 canMoveItemWithinTeamDrive            TRUE 
#> 24 canMoveItemWithinDrive                TRUE 
#> 25 canMoveTeamDriveItem                  FALSE
#> 26 canReadLabels                         FALSE
#> 27 canReadRevisions                      TRUE 
#> 28 canReadTeamDrive                      FALSE
#> 29 canReadDrive                          FALSE
#> 30 canRemoveChildren                     FALSE
#> 31 canRename                             TRUE 
#> 32 canShare                              FALSE
#> 33 canTrash                              TRUE 
#> 34 canTrashChildren                      TRUE 
#> 35 canUntrash                            FALSE

Created on 2023-07-18 with reprex v2.0.2

Tunneling down, the failed API request looks like this:

$method
[1] "GET"

$url
[1] "https://www.googleapis.com/drive/v3/drives/[[driveID]]?fields=%2A"

$body
named list()

$token
<request>
Auth token: Gargle2.0

(above was passed to request_make() from within get_one_shared_drive_id())

Likely relatedly, it's not possible to directly reference anything about the shared drive the shared folders come from:

# Not run--this will include full shared drives, but not individual folders from shared drives:
  # shared_drive_find() 

# Using the drive_id gets a not found:
shared_drive_get(
  id = drive_id
)
#> Error in `map()`:
#> ℹ In index: 1.
#> Caused by error in `.f()`:
#> ! Client error: (404) Not Found
#> Shared drive not found: [[driveID]]
#> • message: Shared drive not found: [[driveID]]
#> • domain: global
#> • reason: notFound
#> • location: driveId
#> • locationType: parameter
#> Backtrace:
#>      ▆
#>   1. └─googledrive::shared_drive_get(id = "[[driveID]]")
#>   2.   ├─googledrive::as_dribble(map(as_id(id), get_one_shared_drive_id))
#>   3.   └─purrr::map(as_id(id), get_one_shared_drive_id)
#>   4.     └─purrr:::map_("list", .x, .f, ..., .progress = .progress)
#>   5.       ├─purrr:::with_indexed_errors(...)
#>   6.       │ └─base::withCallingHandlers(...)
#>   7.       ├─purrr:::call_with_cleanup(...)
#>   8.       └─googledrive (local) .f(.x[[i]], ...)
#>   9.         └─gargle::response_process(response)
#>  10.           └─gargle:::gargle_abort_request_failed(...)
#>  11.             └─gargle:::gargle_abort(...)
#>  12.               └─cli::cli_abort(...)
#>  13.                 └─rlang::abort(...)

# Trying to search anything within it does the same:
drive_find(
  shared_drive = drive_id
)
#> Error in `handle_shared_drives()`:
#> ! Can't find the requested `shared_drive`.
#> Backtrace:
#>     ▆
#>  1. └─googledrive::drive_find(shared_drive = "[[driveID]]")
#>  2.   ├─base::append(params, handle_shared_drives(shared_drive, corpus))
#>  3.   └─googledrive:::handle_shared_drives(shared_drive, corpus)
#>  4.     └─googledrive:::drive_abort("Can't find the requested {.arg shared_drive}.")
#>  5.       └─cli::cli_abort(message = message, ..., .envir = .envir)
#>  6.         └─rlang::abort(...)

Created on 2023-07-18 with reprex v2.0.2

Ideas? I can't tell whether this is an API limitation, a sharing configuration issue, me missing something, or what.

I haven't fully processed all of the above, but in the name of giving you some ideas, I would look very hard at the corpus argument of drive_find() and other functions that ultimately call drive_find(). If you haven't already, I would also read the docs on shared drives:

https://googledrive.tidyverse.org/reference/shared_drives.html

Just want to chime in here that I am having similar problems that I cannot get to the bottom of.

In my case, I have access to a shared folder that is not part of a shared drive, i.e. the folder's parent is not shared, and this folder appears under "Shared with me" but cannot be accessed via "Shared drives" on the browser GUI.

Now

dd <- googledrive::drive_get(path = "https://drive.google.com/drive/folders/<ID>")

returns a valid dribble with one row. But

googledrive::drive_ls(path = dd, corpus = "allDrives")

and

googledrive::drive_ls(path = dd, corpus = "domain")

both error with:

> rlang::last_trace()
<error/purrr_error_indexed>
Error in `map()`:
ℹ In index: 1.
Caused by error in `.f()`:
! Client error: (404) Not Found
Shared drive not found: 0AEmDcn0Ku6o9Uk9PVA
• message: Shared drive not found: 0AEmDcn0Ku6o9Uk9PVA
• domain: global
• reason: notFound
• location: driveId
• locationType: parameter
---
Backtrace:
     ▆
  1. └─googledrive::drive_ls(path = dd, corpus = "allDrives")
  2.   ├─rlang::exec(drive_find, !!!params)
  3.   └─googledrive (local) `<fn>`(corpus = "allDrives", shared_drive = `<drv_id>`, q = "('1BFePA5dltXqdwY1X7Ng_Xal4e7zaZLUM' in parents)")
  4.     ├─base::append(params, handle_shared_drives(shared_drive, corpus))
  5.     └─googledrive:::handle_shared_drives(shared_drive, corpus)
  6.       ├─googledrive::as_shared_drive(shared_drive)
  7.       └─googledrive:::as_shared_drive.drive_id(shared_drive)
  8.         └─googledrive::shared_drive_get(id = x)
  9.           ├─googledrive::as_dribble(map(as_id(id), get_one_shared_drive_id))
 10.           └─purrr::map(as_id(id), get_one_shared_drive_id)
 11.             └─purrr:::map_("list", .x, .f, ..., .progress = .progress)
 12.               ├─purrr:::with_indexed_errors(...)
 13.               │ └─base::withCallingHandlers(...)
 14.               ├─purrr:::call_with_cleanup(...)
 15.               └─googledrive (local) .f(.x[[i]], ...)

The ID 0AEmDcn0Ku6o9Uk9PVA is not the same as the folder that I am passing to drive_get. If I'm understanding correctly, I think it's the ID of the drive in which the shared folder sits, but to which I do not have access.