Change Google Drive file from public to private - google-drive-api

I created a public File on my Google Drive, I used the v3 API from Google Drive on Python to get a list of all my files.
Now I want to change a file permissions so it would be private and can only be seen by me (owner)
from __future__ import print_function
from apiclient.discovery import build
from httplib2 import Http
from oauth2client import file, client, tools
# Setup the Drive v3 API
SCOPES = 'https://www.googleapis.com/auth/drive.metadata.readonly'
store = file.Storage('credentials.json')
creds = store.get()
if not creds or creds.invalid:
flow = client.flow_from_clientsecrets('client_id.json', SCOPES)
creds = tools.run_flow(flow, store)
service = build('drive', 'v3', http=creds.authorize(Http()))
# Call the Drive v3 API
results = service.files().list(
pageSize=10, fields="nextPageToken, files(id, name, modifiedTime, owners, permissions)").execute()
items = results.get('files', [])
if not items:
print('No files found.')
else:
print('Files:')
for item in items:
print('{0} ({1}) ({2})'.format(item['name'], item['id'], item["modifiedTime"])
Cosa = items[2]
print("--- Archivo Publico ---")
print(Cosa["permissions"])
print("---- Modifico los Permisos ----")
service.permissions().delete(fileId="ExampleID",permissionId="anyone").execute()
Now, when I execute the code I get:
googleapiclient.errors.HttpError: <HttpError 403 when requesting https://www.googleapis.com/drive/v3/files/1KHjbcJkN79cccgwywrwsBHlOuLUgtOqXZk4gvZKR1eE/permissions/anyone? returned "Insufficient Permission">
Why? I´m the owner of the File.
edit: The file has 2 permissions. The first is "anyone" which let´s everyone see and edit the file. The second is my permission which makes me the owner. I'm trying to delete the first to make the file private

I had to change de SCOPE from:
SCOPES = 'https://www.googleapis.com/auth/drive.metadata.readonly'
to
SCOPES = 'https://www.googleapis.com/auth/drive'
I also deleted my credentials.json and made the web authentication. It works as spected now

Related

How to get file information in google drive using google drive url in google drive api

Does anyone know if this is possible?
i think i can do it by extracting id from url.
then execute code like below.
service = build('drive', 'v3', credentials=creds)
# Call the Drive v3 API
results = service.files().list(
pageSize=10, fields="nextPageToken, files(id, name,parents,owners)",q="'drive id' in parents"
).execute()
https://developers.google.com/drive/api/guides/search-files
however parsing url might fail sometime.
so i would like to know how to get file information in drive by specify url.
To ensure the parsing URL will not fail, you can use the findall function in regex in extracting the folder ID from the folder URL. Since the structure of the folder URL is static except for the id part, this pattern will guarantee the extraction of folder Id
Regex Pattern
"/folders\/(.*)\?resourcekey"
Please see sample code below for getting the files in a specific folder in my google drive
Code:
from googleapiclient.discovery import build
from google.colab import auth
from google.auth import default
import re
auth.authenticate_user()
creds, _ = default()
# Build the service
service = build('drive', 'v3', credentials=creds)
# Google drive folder's URL
folder_url = 'https://drive.google.com/corp/drive/folders/1bBWIXbinmb-DQ1z_fspsvxlw3vt8v6Wa?resourcekey=0-3Q_nXWmlLp_eG79NzcRe5w'
# Get the folder's ID from the URL using regex
folder_id = re.findall("/folders\/(.*)\?resourcekey", folder_url)
#query
query = f"'{folder_id[0]}' in parents"
# List the files in the folder
results = service.files().list(pageSize=10, fields="nextPageToken, files(id, name,parents,owners)",q=query).execute()
items = results.get('files', [])
if not items:
print('No files found.')
else:
print('Files:')
for item in items:
print(u'{0} ({1})'.format(item['name'], item['id']))
Output:
Resources:
Search for files and folders
Regular Expression
https://regex101.com/

Get Google Drive file owner email address using Google Drive API V3 via python

I'm having trouble getting the owner of a file on Google Drive via the Google Drive API v3.
I could do this under v2, but things have changed.
According to the documentation I need to:
List the permissions on a file (no problem)
Find Id of the permission with the 'owner' role from that list of permissions (no problem)
Get that permission ... which should return a permissions resource which should include the email address (problem!)
Unfortunately, what I'm getting back includes some of the information, but not the email address.
I suspect that I need to change my "get" call to tell the API which fields I'm after, but I can't see how to do this.
This is what I've got (v3):
from oauth2client.service_account import ServiceAccountCredentials
from httplib2 import Http
from apiclient.discovery import build
def build_service(user):
keyfile = 'C:\Python27\Scripts\Certificates for Transfer owner script\Transfer Ownership on Drive-f240cff252af.json'
SCOPE = 'https://www.googleapis.com/auth/drive'
credentials = ServiceAccountCredentials.from_json_keyfile_name(keyfile, scopes=SCOPE).create_delegated(user)
http_auth = credentials.authorize(Http())
return build('drive', 'v2', http=http_auth)
service = build_service('lpglobaldrive#lonelyplanet.com.au')
f = service.files().get(fileId='1lASRBuAHRxEC-T0X5SdlF3w7X_168Q2QV9L0V6QaXUk').execute()
p = service.permissions().get(fileId='1lASRBuAHRxEC-T0X5SdlF3w7X_168Q2QV9L0V6QaXUk',permissionId='18137907375963748644').execute()
currentOwner = p['emailAddress']
Unfortunately I get a "KeyError: 'emailAddress'" (and if I look at the contents of "p", there's role, kind, type and id, but no email Address).
This works for me (using v2):
from oauth2client.service_account import ServiceAccountCredentials
from httplib2 import Http
from apiclient.discovery import build
def build_service(user):
keyfile = 'C:\Python27\Scripts\Certificates for Transfer owner script\Transfer Ownership on Drive-f240cff252af.json'
SCOPE = 'https://www.googleapis.com/auth/drive'
credentials = ServiceAccountCredentials.from_json_keyfile_name(keyfile, scopes=SCOPE).create_delegated(user)
http_auth = credentials.authorize(Http())
return build('drive', 'v2', http=http_auth)
service = build_service('lpglobaldrive#lonelyplanet.com.au')
f = service.files().get(fileId='1lASRBuAHRxEC-T0X5SdlF3w7X_168Q2QV9L0V6QaXUk').execute()
currentOwner = f['owners'][0]['emailAddress']
Too simple ... just needed to add the following to the get call:
,fields='emailAddress'
i.e.
currentOwner = service.permissions().get(fileId='1lASRBuAHRxEC-T0X5SdlF3w7X_168Q2QV9L0V6QaXUk',permissionId='18137907375963748644',fields='emailAddress').execute()['emailAddress']

Unable to update Google Drive files using Drive API v3 -- The resource body includes fields which are not directly writable

I am trying to use Google Drive API (v3) to make updates to documents
in Google Drive.
I have read this migration guide:
Google Drive API v3 Migration
And coded it to make a new empty File() with the details I want to update
and then calling execute() with that and the file ID.
But i am still getting an error. Can anyone point out where I am doing wrong?
thanks alot!!
Error:
{
"code" : 403,
"errors" : [{
"domain" : "global",
"message" : "The resource body includes fields which are not directly writable.",
"reason" : "fieldNotWritable"
}],
"message" : "The resource body includes fields which are not directly writable."
}
Code snippet below:
File newFileDetails = new File();
FileList result = service2.files().list()
.setPageSize(10)
.setFields("nextPageToken, files(id, name)")
.execute();
List<File> files = result.getFiles();
if (files == null || files.size() == 0) {
System.out.println("No files found.");
} else {
System.out.println("Files:");
for (File file : files) {
if (file.getName().equals("first_sheet")) {
System.out.printf("%s (%s)\n", file.getName(), file.getId());
newFileDetails.setShared(true);
service2.files().update(file.getId(), newFileDetails).execute();
}
}
}
I had the same issue and found a solution. The key point is: you must create a new File object without Id and use it in update() method. Here is a piece of my code:
val oldMetadata = service!!.files().get(fileId.id).execute()
val newMetadata = File()
newMetadata.name = oldMetadata.name
newMetadata.parents = oldMetadata.parents
newMetadata.description = idHashPair.toDriveString()
val content = ByteArrayContent("application/octet-stream", fileContent)
val result = service!!.files().update(fileId.id, newMetadata, content).execute()
It works. I hope it'll help you.
Referring to https://developers.google.com/drive/v3/reference/files#resource-representations, you can see that shared isn't a writable field. If you think about it, this makes perfect sense. You can share a file by adding a new permission, and you can check if a file has been shared by reading the shared property. But saying a file is shared, other than by actually sharing it, makes no sense.
in the code it looks like this
Drive service... // your own declared implementation of service
File file = new File(); //using the com.google.api.services.drive.model package
// part where you set your data to file like:
file.setName("new name for file");
String fileID = "id of file, which you want to change";
service.files().update(fileID,file).execute();
trying to change the fields from remote files, and rewriting to this file can throw the security exception like exception below.
but it is not a solution for your question.
If you want to share file to another google account by email, you can do it with reimplementing authorization to authorization with using service account of your app, and the add the needed email, as owner of the file.
I was doing the same thing. My goal was to share my file programmatically with my Python code.
And yes, I was getting the same error:
"The resource body includes fields which are not directly writable"
I solved this problem by adding the service's email address of my Virtual Machine (I created it on my Compute Engine dashboard) to Editors of the file.
Then I ran this Python code in my VM:
from googleapiclient.discovery import build
from oauth2client.service_account import ServiceAccountCredentials
# Took the json file from my Google Cloud Platform (GCP) → IAM & Admin → Service Accounts:
service_key_file = 'service_key.json'
scope = 'https://www.googleapis.com/auth/drive'
credentials = ServiceAccountCredentials.from_json_keyfile_name(service_key_file, scopes=scope)
driveV3 = build('drive', 'v3', credentials=credentials)
fileId = '1ZP1xZ0WaH8w2yaQTSx99gafNZWawQabcdVW5DSngavQ' # A spreadsheet file on my GDrive.
newGmailUser = 'testtest#gmail.com'
permNewBody = {
'role': 'reader',
'type': 'user',
'emailAddress': newGmailUser,
}
driveV3.permissions().create(fileId=fileId, body=permNewBody).execute()
print(f"""The file is now shared with this user:
{newGmailUser}\n
See the file here:
https://docs.google.com/spreadsheets/d/1ZP1xZ0WaH8w2yaQTSx99gafNZWawQabcdVW5DSngavQ""")

Automatically verifying gdrive app login in python program

I want to automatically verify my credentials without going to the link and pasting the verification code every time I run this program.
might storing credentials will work but I don't know how to store it and reuse it..
my code is given below
#!/usr/bin/python
import httplib2
import pprint
from apiclient.discovery import build
from apiclient.http import MediaFileUpload
from oauth2client.client import OAuth2WebServerFlow
from oauth2client.file import Storage
# Copy your credentials from the console
CLIENT_ID = 'my_id' #i have client id but dont wanna share
CLIENT_SECRET = 'my_secret' #i have client secret but dont wanna share
# Check https://developers.google.com/drive/scopes for all available scopes
OAUTH_SCOPE = 'https://www.googleapis.com/auth/drive'
# Redirect URI for installed apps
REDIRECT_URI = 'urn:ietf:wg:oauth:2.0:oob'
# Path to the file to upload
FILENAME = 'hello.txt'
# Run through the OAuth flow and retrieve credentials
flow = OAuth2WebServerFlow(CLIENT_ID, CLIENT_SECRET, OAUTH_SCOPE,
redirect_uri=REDIRECT_URI)
authorize_url = flow.step1_get_authorize_url()
print 'Go to the following link in your browser: ' + authorize_url
code = raw_input('Enter verification code: ').strip()
credentials = flow.step2_exchange(code)
# Create an httplib2.Http object and authorize it with our credentials
http = httplib2.Http()
http = credentials.authorize(http)
drive_service = build('drive', 'v2', http=http)
# Insert a file
media_body = MediaFileUpload(FILENAME, mimetype='text/plain', resumable=True)
body = {
'title': 'My document',
'description': 'A test document',
'mimeType': 'text/plain'
}
file = drive_service.files().insert(body=body, media_body=media_body).execute()
pprint.pprint(file)
any help is appreciated !
Here you can find the documentation on OAuth with python: https://developers.google.com/api-client-library/python/guide/aaa_oauth (edited url)
basically you will have to use self.redirect(authorize_url) to make that step automatically and then in the second step you will use flow.step2_exchange(self.request.params)
In the documentation will find a better explanation of the process.

Store access token from Google OAuth 2.0 to access drive data from application account

I am able to execute quickstart.py for Google Drive using python. But how do we store the token and use it again - again for the same user without prompting user. Is their some way i can map user with access token when sending request for file on Google drive.
There are many different Storage types offered by google-api-python-client, some of which are well documented.
Some examples:
oauth2client.file.Storage:
from oauth2client.file import Storage
...
storage = Storage('a_credentials_file')
storage.put(credentials)
...
credentials = storage.get()
oauth2client.keyring_storage.Storage:
from oauth2client.keyring_storage import Storage
...
storage = Storage('application name', 'user name')
storage.put(credentials)
...
credentials = storage.get()
oauth2client.appengine.StorageByKeyName:
from oauth2client.keyring_storage import StorageByKeyName
from oauth2client.keyring_storage import CredentialsNDBModel
...
storage = StorageByKeyName(CredentialsNDBModel, some_user_id, 'credentials')
storage.put(credentials)
...
credentials = storage.get()
oauth2client.django_orm.Storage:
from django.contrib.auth.models import User
from oauth2client.django_orm import Storage
from your_project.your_app.models import CredentialsModel
...
user = # A User object usually obtained from request.
storage = Storage(CredentialsModel, 'id', user, 'credential')
credential = storage.get()
...
storage.put(credential)
I think you should give credit to bossylobster for a more complete answer, but based on your comment, which is precisely my setup, I've augmented the quickstart.py using the Storage class:
#!/usr/bin/python
import httplib2
import pprint
from apiclient.discovery import build
from apiclient.http import MediaFileUpload
from oauth2client.client import OAuth2WebServerFlow
from oauth2client.file import Storage
# Copy your credentials from the console
CLIENT_ID = 'PASTE_YOUR_ID'
CLIENT_SECRET = 'PASTE_YOUR_SECRET'
# Check https://developers.google.com/drive/scopes for all available scopes
OAUTH_SCOPE = 'https://www.googleapis.com/auth/drive'
# Redirect URI for installed apps
REDIRECT_URI = 'urn:ietf:wg:oauth:2.0:oob'
# Create a credential storage object. You pick the filename.
storage = Storage('a_credentials_file')
# Attempt to load existing credentials. Null is returned if it fails.
credentials = storage.get()
# Only attempt to get new credentials if the load failed.
if not credentials:
# Run through the OAuth flow and retrieve credentials
flow = OAuth2WebServerFlow(CLIENT_ID, CLIENT_SECRET, OAUTH_SCOPE, REDIRECT_URI)
authorize_url = flow.step1_get_authorize_url()
print 'Go to the following link in your browser: ' + authorize_url
code = raw_input('Enter verification code: ').strip()
credentials = flow.step2_exchange(code)
storage.put(credentials)
# Create an httplib2.Http object and authorize it with our credentials
http = httplib2.Http()
http = credentials.authorize(http)
drive_service = build('drive', 'v2', http=http)
# Use 'drive_service' for all of the API calls