Upload a file to google drive

Hello everyone!

I have a code that works for me in vs code, but the request and json doesn't work directly in ignition:

#that code works for me on vs code
import json
import requests
headers = {
    "Authorization":"Bearer xxxx-xxxxx"
}

para = {
    "name":"ejemplo3.jpg",
    "parents":["xxxxxx"]
}

files = {
    'data':('metadata',json.dumps(para),'application/json;charset=UTF-8'),
    'file':open('Screenshot_2.png','rb')
}

r = requests.post("https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart",
    headers=headers,
    files=files
)

I am looking for a way to select a file with file explorer, and upload to google drive, that is why I have the first part of the code where I select the file and get the name:

import os

#paso 1
selectedFile = event.source.parent.getComponent('file_explorer').selectedPath
print "archivo seleccionado:"
print selectedFile
flag_src_path_IsFile = event.source.parent.getComponent('file_explorer').selectedPathIsFile
print "flag_src_path_IsFile:"
print flag_src_path_IsFile

nameFile = os.path.basename(selectedFile)
print "nombre el archivo seleccionado en file explorer:"
print nameFile

and the step 2 that I have to use the google playground api is this, although it doesn't work for me :frowning:

it could be something like this:

import os
import urllib2
import json

# Token de acceso generado en Google Cloud Console
access_token = "xxxxxxxxxxxxxx"

# URL de la API de Google Drive para subir archivos
url = "https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart"

# Encabezados de la solicitud, incluyendo el token de acceso
headers = {
    "Authorization": "Bearer " + access_token,
    "Content-Type": "multipart/related; boundary=foo"
}

# Metadatos del archivo, incluyendo el nombre y la ubicaciĂłn
metadata = {
    "name": "energia-solar.jpg",
    "parents": ["xxxxxx"]
}

# Contenido del archivo, codificado en base64
file_path = r"C:\Users\BJ_IT\Downloads\aimage.png"
with open(file_path, "rb") as f:
    file_content = f.read()
file_content_base64 = file_content.encode("base64").replace("\n", "")

# Cuerpo de la solicitud
body = (
    "--foo\r\n" +
    "Content-Type: application/json; charset=UTF-8\r\n\r\n" +
    json.dumps(metadata) + "\r\n" +
    "--foo\r\n" +
    "Content-Type: image/jpeg\r\n" +
    "Content-Transfer-Encoding: base64\r\n" +
    "Content-Disposition: attachment; filename=\"energia-solar.jpg\"\r\n\r\n" +
    file_content_base64 + "\r\n" +
    "--foo--"
)

# Crear y enviar la solicitud
request = urllib2.Request(url, data=body, headers=headers)
response = urllib2.urlopen(request,timeout=10)

# Leer la respuesta y obtener el ID del archivo subido
response_data = json.loads(response.read())
file_id = response_data["id"]

print("Archivo subido con Ă©xito. ID del archivo: " + file_id)

could i get help? I have read:

I appreciate your answers...

If this end point works to upload a file in general using Postman or similar testing, I would suspect the issues lay in the jython libraries. Don't use requests/urllib, use system.net.httpClient. Try re-writing your script using the functions here - system.net.httpClient - Ignition User Manual 8.1 - Ignition Documentation

on my side, I am not sure I understand this:

file_content.encode("base64").replace("\n", "")

Is it really working to encode base64? also why the replace? base64 should not contains new line

I would do the following

from com.inductiveautomation.ignition.common import Base64
file_content_base64 = Base64.encode(file_content)

With this code it seems I'm very close...

import json
import system.net as net

url = "https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart"
headers = {"Authorization": "Bearer xxxxxxxxxxx"}

params = {"name": "energia-solar.jpg", "parents": ["xxxxxxxxxxxxxxx"]}
metadata = json.dumps(params)

files = {
    "data": ("metadata", metadata, "application/json;charset=UTF-8"),
    "file": ("energia-solar.jpg", system.file.readFileAsBytes("C:\\Users\\BJ_IT\\Downloads\\energia-solar.jpg"), "image/jpeg"),
}

client = net.httpClient()
response = client.post(url, headers=headers, data=files)

if response.good:
    print(response.json)
else:
	print "error"
	print (response.json)

and the console give me:

{'kind': u'drive#file', 'mimeType': u'application/json', 'name': u'Untitled', 'id': u'12DPzTFb-fA9UIAMG9p2CW7pcAonBUIbw'}

So I understand that you are not receiving a file, it is empty. so I should read as bytes, probably with something similar to this...

# Abre el archivo y léelo en una variable como un objeto de bytes
with open('C:\Users\BJ_IT\Downloads\energia-solar.jpg', 'rb') as f:
    file_data = f.read()

I'll keep trying and comment..

type object 'com.inductiveautomation.ignition.common.Base64' has no attribute 'encode'

I'll keep trying something similar to the last code posted here!
I appreciate your answer

have you tried simple upload instead of multipart: Fazer upload dos dados do arquivo  |  Google Drive  |  Google Developers

sorry it's encodeBytes (Base64)

file_content_base64 = Base64.encodeBytes(file_content)

I tried the first code on vs code and works fine

Although I still can't find the solution, which apparently is reading the file in bytes

Where do you run your code? Vision or Gateway?

Ignition designer

I still do not get satisfactory results, I even added oauth2 and google-api-python libraries, as I am also looking at the google console (GCP) in case something works correctly

this is my latest code

import json
import net
import system
import os
import system.net as net

token_acceso = event.source.parent.getComponent('txt_token').text
carpeta = event.source.parent.getComponent('txt_carpeta').text

#url = "https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart"
url = "https://www.googleapis.com/upload/drive/v3/files?uploadType=media"
#url = "https://www.googleapis.com/upload/drive/v3/files"

headers = {"Authorization": "Bearer "+token_acceso}

selected_file = system.file.openFile("pdf")
#selected_file = system.file.openFile("")
if selected_file != None:
    # Obtenemos el nombre del archivo seleccionado
    file_name = os.path.basename(selected_file)
    
    print "nombre archivo: "+file_name

    # Leemos el contenido del archivo seleccionado
    file_content = system.file.readFileAsBytes(selected_file)

    params = {"name": file_name, "parents": [carpeta]}
    metadata = json.dumps(params)

    files = {
    "data": ("metadata", metadata, "application/json;charset=UTF-8"),
    "file": (file_name, file_content, "application/pdf")
    }

    client = net.httpClient()
    response = client.post(url, headers=headers, data=files)

    if response.good:
        print(response.json)
    else:
      #  print("Error: " + response.json)
      print ("error: " + response)

I already have about 10 buttons with different codes in the designer, ups

and sadly none work (yet)

the code is executed on the gateway, so the file must be on the gateway

2 Likes

In mi g. drive root folder ive multiple files called "Untiled"

when i open any, surprise..:

Almost...