Using PhoneGap + Google App Engine to Upload and Save Images - python

Goal: Take/attach pictures in a PhoneGap application and send a public URL for each picture to a Google Cloud SQL database.
Question 1: Is there a way to create a Google Cloud Storage object from a base64 encoded image (in Python), then upload that object to a bucket and return a public link?
I'm looking to use PhoneGap to send images to a Python Google App Engine application, then have that application send the images to a Google Cloud Storage bucket I have set up, then return a public link back to the PhoneGap app. These images can either be taken directly from the app, or attached from existing photo's on the user's device.
I use PhoneGap's FileTransfer plugin to upload the images to GAE, which are sent as base64 encoded images (this isn't something I can control).
Based on what I've found in Google Docs, I can upload the images to Blobstore; however, it requires <input type='file'> elements in a form. I don't have 'file' input elements; I just take the image URI returned from PhoneGap's camera object and display a thumbnail of the picture that was taken (or attached).
Question 2: Is it possible to have an <input type='file'> element and control it's value? As in, is it possible to set it's value based on whether the user chooses a file, or takes a picture?
Thanks in advance!

Here's a solution for others who might face this problem. Turns out it's incredibly simple!
Once you have a bucket setup for your GAE project, you can use this Python code to send an image to the bucket:
import cloudstorage as gcs
import webapp2
import cgi
import MySQLdb
import os
import logging
import time
from google.appengine.api import mail
from google.appengine.api import images
from google.appengine.ext import blobstore
class UploadImageHandler(webapp2.RequestHandler):
def post(self):
self.response.headers.add_header(ACCESS_CONTROL, '*')
f = self.request.POST['image']
fname = '/your-bucket-name/%s' % f.filename;
gcs_file = gcs.open(fname, 'w', content_type="image/jpeg")
gcs_file.write(self.request.get('image'))
gcs_file.close()
And the code used to upload the file from a PhoneGap application:
// Uploads images in "imageURIs" to the web service specified in "server".
function uploadImages(imageURIs, server) {
var success = function(data) {
alert("Successfully uploaded image!");
};
var fail = function(error) {
alert("Failed to upload image: "+error);
};
var options = new FileUploadOptions();
options.fileKey = "image";
options.mimeType = "image/jpeg";
var ft = new FileTransfer();
for (var i = 0; i < imageURIs.length; i++) {
alert("Uploading"+i);
options.fileName = imageURIs[i].substr(imageURIs[i].lastIndexOf('/') + 1);
ft.upload(imageURIs[i], encodeURI(server), success, fail, options);
}
}
I hope it helps someone else. :)

Yes, that is a fine use for GAE and GCS. You do not need an <input type=file>, per se. You can just set up POST parameters in your call to your GAE url. Make sure you send a hidden key as well, and work from SSL-secured urls, to prevent spammers from posting to your app.

Related

Upload images from Flutter

I want to upload images from the mobile application to my Firestore using a Flask API.
The app is uploading a list of int that represents the image. The length of the list is really long, over a thousand I believe.
I'm sending this list of ints in the request json.
How can I upload this list of ints to Firebase storage using the Firebase module for Flask.
Is using a list of ints to upload the image even the correct way?
If not, how can I upload the image using the Flask API?
This the code I have so far, and it's a mess :) :
def post(self):
request_data = request.get_json()
baqala_id = request_data["userID"]
imageBytes = request_data["imageBytes"]
# imageFile = request_data["imageFile"]
bucket = storage.bucket("bucket_name.appspot.com")
blob = bucket.blob(f"{baqala_id}/{imageBytes}")
# blob = bucket.blob(f"{baqala_id}/{imageFile}")
upload = blob.upload_from_string(imageBytes)
# upload = blob.upload_from_file(imageFile)
return {"message": "upload succesfull"}, 200
Note: I can't using the Firebase plugin for Flutter because it's too slow and cannot be used in a separate Isolate.

Is there a temporary directory or direct way to upload a file in azure storage?

so I try to make a python API so the user can upload a pdf file then the API directly sends it to Azure storage. what I found is I must have a directory i.e.
container_client = ContainerClient.from_connection_string(conn_str=conn_str,container_name='mycontainer')
with open('mylocalpath/myfile.pdf',"rb") as data:
container_client.upload_blob(name='myblockblob.pdf', data=data)
another solution is I have to store it on VM and then replace the local path to it, but I don't want to make my VM full.
If you want to upload it directly from the client-side to azure storage blob instead of receiving that file to your API you can use azure shared access signature inside your storage account and from your API you can make a function to generate Pre-Signed URL using that shared access signature service and return that URL to your client it will allow the client to upload file to your blob via that URL.
To generate URL can you follow the below code:
from datetime import datetime, timedelta
from azure.storage.blob import generate_blob_sas, BlobSasPermissions
blobname= "<blobname>"
accountkey="<accountkey>" #get this from access key section in azure storage.
containername = "<containername>"
def getpushurl(filename):
token = generate_blob_sas(
account_name=blobname,
container_name=containername,
account_key=accountkey,
permission=BlobSasPermissions(write=True),
expiry=datetime.utcnow() + timedelta(seconds=100),
blob_name=filename,
)
url = f"https://{blobname}.blob.core.windows.net/{containername}/{filename}?{token}"
return url
pdfpushurl = getpushurl("demo.text")
print(pdfpushurl)
So after generating this URL give it to the client so client could directly send the file to the URL received with PUT request and it will get uploaded directly to azure storage.
You can generate a SAS token with write permission for your users so that your users could upload .pdf files directly on their side without storing them on the server. For details, pls see my previous post here.
Try the code below to generate a SAS token with container write permission:
from azure.storage.blob import BlobServiceClient,ContainerSasPermissions,generate_container_sas
from datetime import datetime, timedelta
storage_connection_string=''
container_name = ''
block_blob_service = BlobServiceClient.from_connection_string(storage_connection_string)
container_client = block_blob_service.get_container_client(container_name)
sasToken = generate_container_sas(account_name=container_client.account_name,
container_name=container_client.container_name,
account_key= container_client.credential.account_key,
#grant write permission only
permission=ContainerSasPermissions(write=True),
start=datetime.utcnow() - timedelta(minutes=1),
#1 hour vaild time
expiry=datetime.utcnow() + timedelta(hours=1)
)
print(sasToken)
After you have replied to this SAS token to your user, just see this official guide to upload files from a HTML page, I think it would be helpful if you are developing a web app.

Python: Is it possible to upload images to Firebase Storage using an image URL and not the image file?

I am trying to use Python, the Reddit API, and Firebase to store images from reddit in Firebase Storage and then put the URL from firebase storage in a doc.
Right now I am just storing the URL that the reddit api provides in my project's Firebase Database. BUT this is a problem since sometimes these URLs "go bad and expire" meaning that when I grab a doc and display the URL I have stored I get an error.
This is how I am getting the information before creating the doc in firebase
function getJSON(sub){
var ret;
var yourUrl="https://www.reddit.com/r/"+sub+".json";
fetch(yourUrl).then(response => {
return response.json();
}).then(function(data){
var i = 5;
list= data.data.children
curlist = list[i].data
if(curlist.domain==='i.redd.it'){
if(curlist.post_hint==='image'){
var url =curlist.url;
var author=curlist.author;
var time=curlist.created_utc;
var score = curlist.score;
sendToFirebase(url,author,sub,time,score);
}
}
}).catch(err => {
});
}
What I would like to do instead of putting the reddit URL in the doc is take this reddit URL and store the image that is at the end of this URL in my Firebase Storage, so that way I can take the image URL that is stored in Firebase Storage and put it in the doc.
The Firebase SDKs require that the image data is available on the local client to be able to upload it to Cloud Storage. There are no methods that take an external image URL of the data to upload to Cloud Storage.
If the image is not local to the client, you will first need to download it to the client, before uploading it to Cloud Storage with the Firebase SDK.

Python App Engine serving files with Google Cloud Storage

I currently use the following code for allowing my users to upload files;
uploadurl = blobstore.create_upload_url('/process?session=' + session, gs_bucket_name='mybucketname')
and I can serve images like this;
imgurl = get_serving_url(blob_key, size=1600, crop=False, secure_url=True)
After content is uploaded using the method in the first code snipped, the blob key contains encoded_gs_file: and that's how it knows to serve it from Google Cloud Service and not the blobstore as standard.
However, I'm unsure how I'd serve any other kind of file (for example .pdf, or .rtf). I do not want the content to be displayed in the browser, but rather sent to the client as a download (so they get the save file dialog and choose a location on their computer to save it).
How would I go about doing this? Thanks.
Using a google serving_url works only for images.
To serve a pdf from the blobstore you can use:
class DynServe(blobstore_handlers.BlobstoreDownloadHandler):
def get(self, resource):
(blob_key, extension) = resource.rpartition('.')[::2]
blob_info = blobstore.BlobInfo.get(blob_key)
if not blob_info:
logging.error('Blob NOT FOUND %s' % resource)
self.abort(404)
self.response.headers[b'Content-Type'] = mimetypes.guess_type(blob_info.filename)
self.send_blob(blob_key, save_as=blob_info.filename)
The webapp2 route for this handler looks like:
webapp2.Route(r'/dynserve/<resource:(.*)>', handler=DynServe)
To serve:
PDF download
I'm going to answer my own question based on the answer from #voscausa
This is what my handler looks like (inside a file named view.py);
class DynServe(blobstore_handlers.BlobstoreDownloadHandler):
def get(self, resource):
blob_key = resource
if not blobstore.get(blob_key):
logging.warning('Blob NOT FOUND %s' % resource)
self.abort(404)
return
else:
blob_info = blobstore.BlobInfo.get(blob_key)
self.send_blob(blob_key, save_as=blob_info.filename)
We need this in app.yaml;
- url: /download/.*
script: view.app
secure: always
secure: always is optional, but I always use it while handling user data.
Put this at the bottom of view.py;
app = webapp.WSGIApplication([('/download/([^/]+)?', DynServe),
], debug=False)
Now visit /download/BLOB_KEY_HERE. (you can check the datastore for your blob key)
That's a fully working example which works with both the standard blob store AND Google Cloud Service.
NOTE: All blob keys which are part of the GCS will start with encoded_gs_file: and the ones which don't are in the standard blobstore; app engine automatically uses this to determine where to locate the file

Youtube Upload to own account

I'm trying to upload a video to my Youtube to my account using the API but I can't find a way to do it easily. All the methods I saw require me to authenticate with oAuth in a browser.
I simply want to upload a video from a script to one account using a username and password or dev key or similar without going through the crazy, overly complex authentication methods. The script will run in a private in environment so security is not a concern.
try:
youtube-upload
django-youtube (if you use django)
Uploading videos
OAuth2 authorization let's you get a refresh token once the user authorize the upload.
So you can get that token form OAuth2 playground manually for "https://www.googleapis.com/auth/youtube.upload" scope, save it and have a script to get access token periodically. Then you can plug in that access token to upload.
To sum up, browser interaction is required once, and you can do that through playground and save the token manually.
Try YouTube Upload Direct Lite. It is really easy to set up. https://code.google.com/p/youtube-direct-lite/
"Adding YouTube Direct Lite is as simple as adding an iframe HTML tag to your existing web pages. There is no server-side code that needs to be configured or deployed, though we do recommend that you check out your own copy of the YouTube Direct Lite HTML/CSS/JavaScript and host it on your existing web server. "
youtube-upload is a really nice tool which you can make heavy usage out of it. This video shows you how to upload videos on your Youtube channel using youtube-upload.
Using ZEND, theres is a method, but it's deprecated by google: the client login.
Even you tag your question with pyton, I think this PHP example can helps you to give and idea
<?php
/*First time, first: start the session and calls Zend Library.
Remember that ZEND path must be in your include_path directory*/
session_start();
require_once 'Zend/Loader.php';
Zend_Loader::loadClass('Zend_Gdata_YouTube');
Zend_Loader::loadClass('Zend_Gdata_ClientLogin');
$authenticationURL= 'https://accounts.google.com/ClientLogin';
$httpClient =
Zend_Gdata_ClientLogin::getHttpClient(
$username = 'myuser#gmail.com',
$password = 'mypassword',
$service = 'youtube',
$client = null,
$source = 'My super duper application',
$loginToken = null,
$loginCaptcha = null,
$authenticationURL);
//Now, create an Zend Youtube Objetc
$yt = new Zend_Gdata_YouTube($httpClient, $applicationId, $clientId, $developerKey);
// create a new video object
$video = new Zend_Gdata_YouTube_VideoEntry();
$video ->setVideoTitle('Test video');
$video ->setVideoDescription('This is a test video');
$video ->setVideoCategory('News'); // The category must be a valid YouTube category
//Will get an one-time upload URL and a one-time token
$tokenHandlerUrl = 'http://gdata.youtube.com/action/GetUploadToken';
$tokenArray = $yt->getFormUploadToken($myVideoEntry, $tokenHandlerUrl);
$tokenValue = $tokenArray['token']; //Very important token, it will send on an hidden input in your form
$postUrl = $tokenArray['url']; //This is a very importan URL
// place to redirect user after upload
$nextUrl = 'http://your-site.com/after-upload-page'; //this address must be registered on your google dev
// build the form using the $posturl and the $tokenValue
echo '<form action="'. $postUrl .'?nexturl='. $nextUrl .
'" method="post" enctype="multipart/form-data">'.
'<input name="file" type="file"/>'.
'<input name="token" type="hidden" value="'. $tokenValue .'"/>'.
'<input value="Upload Video File" type="submit" />'.
'</form>';
?>
I really hope this will be helpful.
¡Have a great day!

Categories

Resources