Transfer Ownership of Google Sheets from Service Account to General Account - google-apps-script

I created a Google sheet using Google Sheets API which copied the content of spreadsheet present in one of my folder in Google Drive. Even the copied file did contain the code of App Script in it. So the file which was created using service account didn't allowed me to use the code of App Script. It throws the following error as shown in image below:
When I created the copy of this file from front end as shown in image below:
In this case owner was not service account so I was able to use the App Script.
Can any one help me with this?

You can programmatically make a Permissions.List using the service account credentials to make another user the owner of the file (the Spreadsheet in this case, you need its ID), you need to set the transferOwnership attribute to true and use a request body like this:
{
"role": "owner",
"type": "user",
"emailAddress": "new-owner#email.com"
}

Related

Share the Drive file with extra permissions

I have a drive file where I need to restrict the users from these (I mean ticks for both needs to be removed and shared using apps script/drive api)
I need to accomplish using Google Apps Script Advanced Drive service or regular apps script. I am unsure what is the exact method. I have tried with
function shareit() {
DriveApp.getFileById(id).setSharing(DriveApp.Access.ANYONE_WITH_LINK, DriveApp.Permission.EDIT);
}
Drive Sharing Permissions with App Script
I manage to make both changes by using Advance Services from App Script. I was able to use part of your code to first remove the "Editors can change permissions and share" by using the:
setShareableByEditors(false)
Code Sample:
function shareit() {
DriveApp.getFileById(id).setSharing(DriveApp.Access.ANYONE_WITH_LINK, DriveApp.Permission.EDIT).setShareableByEditors(false);
// Add advance service to be able to run a files patch and update the permissions of the ID to require writters permisions to copy, print and download.
Drive.Files.patch({copyRequiresWriterPermission:true}, id);
}
As presented in the comments you would need run a patch update to the File ID to change the permissions.
References:
https://developers.google.com/apps-script/advanced/drive
https://developers.google.com/drive/api/v2/reference/files/patch
https://developers.google.com/apps-script/reference/drive/file#setShareableByEditors(Boolean)

Creating a Google App Script web app to upload files to google drive with minimum scope

I want to create a Google App Script web app to allow users to upload files to a folder of my google drive.
The problem is that I've checked the drive scope list here,
in order to perform the upload action , this scope must be reviewed by the users
https://www.googleapis.com/auth/drive
and it comes with a scary description See, edit, create and delete all of your Google Drive files which is way too strong.
Is there any way to perform the upload action with a less stronger scope?
Thank you so much.
In your situation, for example, how about the following scope?
https://www.googleapis.com/auth/drive.file
The official document says as follows. Ref
Per-file access to files created or opened by the app. File authorization is granted on a per-user basis and is revoked when the user deauthorizes the app.
In this scope, only the files and folders created by this application can be accessed.
Reference:
Authenticate your users
Added:
From your following replying,
Thank you for replying too, I have an update. When I run the code in the editor , it throws an error : ' { [Exception: You do not have permission to call DriveApp.Folder.createFile. Required permissions: googleapis.com/auth/drive] name: 'Exception' }' So I guess there is no solution to my problem T.T
I understood that you are using createFile with the Drive service (DriveApp). In this case, the scope of https://www.googleapis.com/auth/drive is requierd to be used. It seems that this is the current specification. In order to use the scope of https://www.googleapis.com/auth/drive.file, how about using Drive API at Advanced Google services? By this, you can use the scope by setting to appsscript.json which is the manifest file.
At first, please add https://www.googleapis.com/auth/drive.file as "oauthScopes": ["https://www.googleapis.com/auth/drive.file"] to the manifest file of appsscript.json. Ref
Although I'm not sure about your actual script, the sample script for creating a Spreadsheet is as follows.
Sample script:
Before you use this script, please enable Drive API at Advanced Google services.
function myFunction() {
const obj = Drive.Files.insert({title: "sampleSpreadsheet", mimeType: MimeType.GOOGLE_SHEETS, parents: [{id: "###folderId###"}]});
console.log(obj.id)
}
When you run this script, new Spreadsheet is created to folderId by the scope of https://www.googleapis.com/auth/drive.file.
Note:
If you are required to use other scopes, please add them to oauthScopes.
References:
Manifests
Manifest structure
Related thread.
Can I use DocumentApp.openById() with read only permission?

This is the code written according to the official documentation, I do not know which side went wrong [duplicate]

I want to retrieve list of files from a Google drive folder. Authentication happens through Service account. Here is my code to do the same:
final _credentials = new ServiceAccountCredentials.fromJson(r'''
{
"private_key_id": "b5-xxxx-17",
"private_key": "-----BEGIN PRIVATE KEY-----\nMI-xxxxk=\n-----END PRIVATE KEY-----\n",
"client_email": "drive-access#xxxx.iam.gserviceaccount.com",
"client_id": "100000000000",
"type": "service_account"
}
''');
final _SCOPES = [SheetsApi.DriveFileScope, SheetsApi.SpreadsheetsScope];
clientViaServiceAccount(_credentials, _SCOPES).then((http_client) {
DriveApi driveApi = DriveApi(http_client);
driveApi.files.list().then((files) {
print('kind: ' + files.kind);
print('list: ' + files.files.length.toString());
});
My log looks like this:
just: drive#fileList
list: 0
In Google Developers console, Google Drive API is enabled and service account it linked properly (as far as I can check).
But I also got another piece of code which writes some data to a spreadsheet, with hardcoded sheetID and that code is working fine.
Any help on what I am doing wrong here?
Retrieving files using Service account:
The service account is different from your Google account. This means that the Google Drive is also different between Service account and your account. So when the file is retrieved using Service account, please share the files in your Google Drive with the Service account. By this, the files in your Google Drive can be retrieved by the Service account.
Scopes:
In your script, DriveFileScope and SpreadsheetsScope are used as the scopes. DriveFileScope is https://www.googleapis.com/auth/drive.file. The official document says this scope as follows.
View and manage Google Drive files and folders that you have opened or created with this app
By this, in your script, how about modifying DriveFileScope as follows?
DriveReadonlyScope (https://www.googleapis.com/auth/drive.readonly)
DriveScope (https://www.googleapis.com/auth/drive)
Note:
I think that this scope can be also used for your situation.
DriveApi.driveMetadataReadOnlyScope (https://www.googleapis.com/auth/drive.metadata.readonly)
References:
Scopes for Google Sheets API, v4
Scopes for Drive API, v3

How can I check that my GoogleSpreadsheet is in my drive or in a teamdrive?

Like I said on the title, I would like to run a Google apps script linked to a google spreadsheet only if the Spreadsheet is located on the user's drive because I work with Spreadsheet template located on teamdrive and the rule is that the user must make a copy on their local Drive to run the script. So I would like to know if it's possible with the file id for exemple to check if I am in a teamdrive or not ?
Thanks for your answers
With the fileId itself, you cannot know whether it is part of a shared drive or not.
However, you can use DriveApp to obtain the file itself, and most importantly, its permission. In order to check that the file is in a personal drive (and owned by the user issuing the request), you have to make sure the permission is in fact OWNER. You can do this with GAS as follows:
function isInPersonalDrive(fileId) {
var file = DriveApp.getFileById(fileId);
return file.getAccess(Session.getActiveUser()) === DriveApp.Permission.OWNER;
}

Share Google Drive Folder via Zapier with Mailchimp trigger

I can't figure out how to format the "Custom Value for Sharing Preference" on this Zap I'm trying to create that will share a Google Drive folder with my new Mailchimp subscribers.
I've been able to get the File ID using the Drive API, but I'm not sure how to provide the Custom Value that should come from the New Mailchimp Subscriber Email.
If I simply choose the Email address from the Mailchimp dropdown provided by Zapier and test it, I get an error:
We had trouble sending your test through. The app returned "The
permission type field is required.". This usually happens when your
Zap is missing a required field or a field value isn't in a recognized
format.
EDIT: Success via the Google Drive API test.
Using the sandbox available here, I know that I need to:
POST https://www.googleapis.com/drive/v3/files/fileId/permissions
the following Request Body
{
"role": "reader",
"type": "user",
"emailAddress": "email#example.com"
}
I've been able to run that test a few times with Google's sandbox, so I know I can do it. I just don't know how to pull this into Zapier.