Why a collaborator cannot delete a document I uploaded onto RStudio Connect

Server:

function(input,output,session){
  
  observeEvent(input$upload, {
    
    require(input$file)
    
    file <- file.copy(from = input$file$datapath, 
                      to = paste0(tempdir(),input$pubname,
                                  " - ",
                                  input$pubmonth,
                                  " ",
                                  input$pubyear,
                                  ".pdf"))
    
    
    if(!is.null(input$file)){
      
      readRenviron("~/rstudio/connectapi/.Renviron.alt")
      
      client <- connect(host = "server",
                        api_key = "api key")
      
      bnd <- bundle_static(input$file$datapath)
      
      content_1 <- deploy(client,bnd,title = paste0(input$pubname, " - ", input$pubmonth, " ", input$pubyear),access_type = "logged_in")
      
      all_users <- get_users(client,limit = 200)
      
      one_user <- all_users %>% filter(username == input$username)
      
      one_user_guid <- one_user %>% pull(guid)
      
      content_1 %>%
        
        acl_add_collaborator(
          one_user_guid
        )
      
      myapp <- set_content_tag_tree(content_1,"tag_tree",input$unitname, input$pubname, input$pubyear, input$pubmonth)
      
      #myapp <- deploy(client, bnd, name = tempdir(),input$pubname," - ",input$pubdate,title = paste0(input$pubname, " - ", input$pubdate))
      
      
      #acl_add_viewer(myapp,"Anyone")
      
      
      poll_task(myapp)
      
      browse_dashboard(myapp)
      
      
      
      
      
    }
  }
  )
  
}

This is an add that I built that allows my team members to upload there documents to RStudio Connect, and they they are added as collaborators of the document that they upload.

My question is around the type of functions these collaborators have access to on RStudio Connect.

Why are they not able to delete a document that they uploaded? But they are a collaborator of the document.

Hi @zuki! We are glad to hear this API process is working for you! Any feedback you have on the process or on what privileges it would be ideal to pass along to your users would be great for us to have as we continue to improve the product!

This is a great example - the ability to "delete" the content is reserved for the owner of the content (you) and administrators on the server. This is a safeguard, so that a collaborator cannot "go rogue" and delete content that they are not the owner of.

However, I can also see how this would be a confusing delineation! The collaborator and owner are very similar for most privilege (access to change parameters on reports, set tags, look at logs, deploy new versions, etc.). However, there are exceptions (like deleting content), and at one point there were limitations on whether collaborators could receive email updates (on failure) or view the usage data for an application. Those may or may not still exist... I know there has been discussion on removing those restrictions for collaborators.

On the "delete" topic, one option would be to have a "to_delete" tag that users could mark content with. I realize that is much less than ideal, but it would make it easier for you to follow up (either manually or programmatically) to delete content that needs to be cleaned up.

I hope that helps!! We will definitely share this feedback with our team!

Actually, one other option that just shipped in the latest version of RStudio Connect (1.8.6) - you can change the owner of content if you are an administrator on the server!! This might be a good solution for your case.

This is not exposed directly in the connectapi package (yet), but you would basically do something like:

content_1$update(owner_guid = "new_owner_guid")

(where new_owner_guid is the user's actual guid).

Do I have to type in the actual user's guid?

When I do this, I get an error:

content_1$update(owner_guid  = one_user_guid)

where the one_user_guid comes from:

all_users <- get_users(client,page_size = 20,prefix = NULL,limit = 200)
      
      one_user <- all_users %>% filter(username == input$username)
      
      one_user_guid <- one_user %>% pull(guid)

Is it possible to share the error message that you're getting?

Thank you I managed to fix the error.

But the problem is still there, users are still not able to delete the content that they have upload. Here is my code:

server <- function(input, output){
    
    observeEvent(input$upload, {
      
      require(input$file)
      
      file <- file.copy(from = input$file$datapath, 
                to = paste0(tempdir(),input$pubname,
                           " - ",
                           input$pubmonth,
                           " ",
                           input$pubyear,
                           ".pdf"))
      
      
      if(!is.null(input$file)){
      
      #readRenviron("~/rstudio/connectapi/.Renviron.alt")

      client <- connect(host = "server",
                        api_key = "Key"
                        )
      
      bnd <- bundle_static(path = input$file$datapath)
      
      content_1 <- deploy(client,bnd,title = paste0(input$pubname, " - ", input$pubmonth, " ", input$pubyear), access_type = "logged_in")
      
      all_users <- get_users(client,page_size = 20,prefix = NULL,limit = 200)
      
      one_user <- all_users %>% filter(username == input$username)
      
      one_user_guid <- one_user %>% pull(guid)
      
      content_1$update(owner_guid  = one_user_guid)
      
      content_1 %>%
        
        acl_add_collaborator(
          one_user_guid
        )
      
      
      myapp <- set_content_tag_tree(content_1,"Tags",input$unitname, input$pubname, input$pubyear, input$pubmonth)
      
      #myapp <- deploy(client, bnd, name = tempdir(),input$pubname," - ",input$pubdate,title = paste0(input$pubname, " - ", input$pubdate))
      
      
      
      poll_task(myapp)
      
      browse_dashboard(myapp)
      
      
      
     
      }
    }
    )
  
}
shinyApp(ui = ui, server = server)

So sorry for the delay getting back to you here!!

In sum, you are right! The $update(owner_guid = ...) function needed to be ported to the newer version of the API. It also requires RStudio Connect 1.8.6. If you update to the newest version of the connectapi package (0.1.0.9018 at the time of writing) and ensure you are running RStudio Connect version 1.8.6 (latest patch release is 1.8.6.2), then this function should work now!

Please let us know if you run into any more trouble!! Hopefully this will fix your issue!

Thanks for the response @cole the current version we are using is 1.7.6. I think for now I'll just use your suggestion and create a "delete" tag that will allow the collaborators to mark the reports that they want deleted.

I'm not sure if you can advise on another issue I have, some of the users are complaining that sometimes when they upload reports to Rstudio Connect they overwrite reports that had already been uploaded. Is there a way I can prevent this from happening? The reports have different names so I don't understand why the overwriting happens. I ran the app using Rstudio to see if maybe it produces an error that could explain why the overwriting is happening, but there wasn't an error just a message that says:

Not sure why this happens because the reports have different names.

Hi Zuki,

Are you sure that the "name"s are different? It is worth noting that the "name" and the "title" are two distinct arguments, and two distinct things. Titles can be the same with no consequence, but names not being unique will cause deployment to the same location.

At present, it looks like the default name argument (connectapi:::create_random_name()) is being used. In any case, a 25 character random-name is very unlikely to have a duplicate, but it is possible, and would be more likely if set.seed() or some other code is being used to make your code's randomness deterministic. Do you mind sharing the code that is generating this error / output?

One way to test the result is to look at content with that name:

client <- connect()

# or whichever name is of interest
get_content(client, filter = list(name = "tfoykjedzwblzvacjrdorqngn"))

Another way would be to provide the name argument directly to deploy() ensure it is unique!

This is the code :

function(input, output){
  
  observeEvent(input$upload, {
    
    require(input$file)
    
    
    
    if(!is.null(input$file)){
      
      #readRenviron("~/rstudio/connectapi/.Renviron.alt")
      
      client <- connect(host = "server",
                        api_key = "key"
      )
      
      
      bnd <- bundle_static(path = input$file$datapath)
      
      content_1 <- deploy(client,bnd,title = paste0(input$pubname, " - ", input$pubmonth, " ", input$pubyear), access_type = "logged_in")
      
      all_users <- get_users(client,page_size = 20,prefix = NULL,limit = 200)
      
      one_user <- all_users %>% filter(username == input$username)
      
      one_user_guid <- one_user %>% pull(guid)
      
      content_1 %>%
        
        acl_add_collaborator(
          one_user_guid
        )
      
      
      myapp <- set_content_tag_tree(content_1,"Reports",input$unitname, input$pubname, input$pubyear, input$pubmonth)
      
      #myapp <- deploy(client, bnd, name = tempdir(),input$pubname," - ",input$pubdate,title = paste0(input$pubname, " - ", input$pubdate))
      
      content_1$update(owner_guid  = one_user_guid)
      
      poll_task(myapp)
      
      browse_dashboard(myapp)
      
      
      
      
    }
  }
  )
  
}



Apologies for the delay getting back to this @Zuki. Your app looks normal to me, so I am very surprised this is happening. The odds of a duplicate (the default length of our "random name" is 25 characters) is vanishingly small.

Something I thought you might try is creating your own name = argument that you ensure is unique, somehow? Alternatively, you could dig into your app to see if there is a reason that duplication is happening. For example, set.seed() will make things deterministic, so you could always set seed to a new value?

See below, which should always return the same values:

set.seed(4)

connectapi:::create_random_name()
#> [1] "xkscglsvuzsxfbxatkcmppebo"

connectapi:::create_random_name()
#> [1] "leovepqvkpnutapxvmtleirjt"

set.seed(4)

connectapi:::create_random_name()
#> [1] "xkscglsvuzsxfbxatkcmppebo"

connectapi:::create_random_name()
#> [1] "leovepqvkpnutapxvmtleirjt"

Created on 2021-03-17 by the reprex package (v0.3.0)

So instead, maybe you could do something like this? Setting NULL reinitializes as if set.seed has not been set, so perhaps that can resolve your issue

set.seed(NULL)

connectapi:::create_random_name()
#> [1] "lrskhmuafsaumsgbkohyeleql"

connectapi:::create_random_name()
#> [1] "cwczbfvlvdgvothoxylghkmjk"

set.seed(NULL)

connectapi:::create_random_name()
#> [1] "jjzoblcwnohgpglfgrjasgyhi"

connectapi:::create_random_name()
#> [1] "kabhssnuoerqbyzkpryqdkrli"

Created on 2021-03-17 by the reprex package (v0.3.0)

Thanks @cole .

Could this warning message have anything todo with the overwrite issue:

I'm asking because the overwrite issue only happens when the app is being run on Rstudio Connect, when I run the app Rstudio Server the app works perfectly and there is no overwrite problem.

Hey @Zuki ! No that should not be a problem.

That error mostly would result in functionality not working / etc. (i.e. if you try to access an API that was not in version 1.7.6 of Connect).

Thanks for the detail on things not working when deployed to RStudio Connect! I will take a look at that and see if I can reproduce in that environment!