Access images from other drive with flask - python

My flask application is in my C: drive. The images I want to display on my flask server are on my D: drive because there are 160 GB of them, which my C: drive does not like to store. I was wondering how to access these files outside of the root of the flask application. Any help is appreciated!
SOLVED [Thanks to Shivendra Pratap Kushwaha]
I was able to access the other drive with the following test code:
HTML with Jinja2:
<img id="myimage9" src="{{ url_for('main.sendfiletest') }}" width="400" height="300" alt="TestLabel">
Python 3.7:
from flask import send_file
#main.route('/uploads/')
def sendfiletest():
test_url = "D:\myimage.png"
return send_file(test_url, mimetype='image/jpg')
Thanks for everyone for trying to help me out!

Add below code in your routes.py :
from flask import send_file
file = "D:\your\file\name"
return send_file(file, mimetype='image/jpg')

Do you want to expose images stored on your computer? Does that mean your computer is supposed to be the server of your flask app?
You could store your images on a AWS S3 bucket or Google Drive and store the links to these images in your flask app.

Related

Allow only authenicated users access to HTML video URL using Flask

I'm working on a web app that hosts videos/photos so I can easily share with friends and family, running on an Ubuntu Server (20.04) with Python 3.8 Flask and Apache2. I've got everything working however there's one issue, to access the site and the media you must be logged in (authentication is done using JSON Web Tokens) which works fine however due to the media files being stored in the 'static' flask directory (actually a symlink that is in this directory), anyone that finds the URL (while long and difficult to brute force) can directory access these files.
To combat this I tried using a GET request as follows in the HTML:
<img src="/webapp/goes/here/image?title={{file_name}}" alt="{{ file_name }}" onerror="if (this.src != '/static/loading.gif') this.src = '/static/loading.gif';" >
linking back to the flask py file:
#app.route('/webapp/goes/here/image')
def sendimage():
if jwtVerify(request.cookies):
file = request.args.get('title')
filename = 'dir/to/image/not/in/static/dir' + str(file)
return send_file(filename, mimetype='image/jpg')
else:
return redirect(url_for("login"))
Which checks for the JWT authentication and this works perfectly, stopping direct unauthenticated URL access to the files, however, when using this method for videos (changing the MIME of course) it is very very slow and results in lots of buffering.
I've resorted to just hard coding the static directory into the HTML file and with Jinja changing the file name, authentication is still required to access the HTML page but anyone with the URL can get to the video files which I don't want. The video is much much faster to load now though with this method.
<source src="/static/dir/to/video/{{filename}}" type="video/mp4">
Is there a better way to do this that ensures authentication to access the videos or reduce the buffering in the first (successful authenication) method?
Maybe using something along the lines of?
<source src="/webapp/not/real/dir/to/video/{{filename}}" type="video/mp4">
#app.route('/not/real/dir/to/video/*')
def send_video():
if jwtVerify(request.cookies):
return (real_URl_to_video)
else:
return redirect(url_for("login"))
Thanks for the help!

Display image from google cloud storage in flask website hosted on google cloud using python 3

I'm am trying to make a website that takes input of text, generates an image, and then shows that image back in the html.
This works fine by writing the image to the static directory when I have the local test implementation, but when I push to google cloud I'm not allowed to write to the directory. I figured out how to save the image to my google cloud storage bucket instead, but now I can't get the image back to show in the html template.
I'm using Flask and python 3.7
Here is what I'm doing:
from flask import Flask, render_template, request, send_file
import time
#import cloudstorage
import io, os
from google.cloud import storage
import tempfile
import functions
app = Flask(__name__)
app.config['SEND_FILE_MAX_AGE_DEFAULT'] = 0
#app.route("/")
def home():
return render_template("home_css.html")
#app.route('/', methods=['POST'])
def my_form_post():
text = request.form['text']
URL = functions.main(text)
print(URL)
return render_template("return_img_css.html", picture_path = URL, screen_name = text)
Where the functions part contains a block that DOES SUCCESSFULLY SAVE the image to return the url of the image:
def make_plot():
....
# NEED to SAVE THE IMAGE TO GOOGLE CLOUD
client = storage.Client(project='meytweets')
bucket = client.bucket('meytweets.appspot.com')
savename = 'static/'+ screen_name+ '_network.png'
blob = bucket.blob(savename)
# temporarily save image to buffer
buf = io.BytesIO()
plt.savefig(buf, format='png')
# upload buffer contents to gcs
blob.upload_from_string(
buf.getvalue(),
content_type='image/png')
buf.close()
return blob.public_url
Where that URL usually looks like:
https://storage.googleapis.com/meytweets.appspot.com/static/twitter_network.png
And the HTML template looks like:
{% extends 'base.html' %}
{% block content %}
<h1>{% block title %} Network for Twitter User: {{ screen_name }} {% endblock %}</h1>
<img src="{{ picture_path }}" >
{% endblock %}
Here is the app.yaml:
runtime: python37
env_variables:
CLOUD_STORAGE_BUCKET: meytweets.appspot.com
handlers:
- url: /static
static_dir: public
- url: /.*
script: auto
As I wrote above, it does save the image to my google cloud bucket but then I can't get it back to show in the html:
screenshot
I'm open to other strategies that do not write to google cloud, whatever works to display the image I produce in matplotlib is fine with me.
When you run your app on serverless environment, only the /tmp directory is writable. You can't change the content of other directory, such as /static. In addition, the /tmp directory is an in memory file system, and thus, when the instance is killed, all the /tmp disappear.
Now, you can try to set the /tmp in the handlers. I never tested, not sure of the result and its consistency.
The other solution, is to save the image into Google Cloud Storage, and finally to generate your HTML with the image in the Google Cloud Storage, publicly accessible of course.
It's been a while since this question was asked, but I needed to do the same thing and got it working. I'm storing images in google object storage and inserting them into jinja2 templates as base64 encoded data in img tags.
Route:
#app.route("/view/<string:blob_name>")
def view(blob_name):
bucket = get_bucket()
blob = bucket.get_blob(blob_name)
content = blob.download_as_bytes()
image = base64.b64encode(content).decode("utf-8")
return render_template('view.html', content_type=blob.content_type, image=image)
Template:
<body>
<h1>Image:</h1>
<img src="data:{{ content_type }};base64,{{ image }}" />
</body>
This solution works if flask is running on a serverless environment where you can't create temporary files and you don't want to make the data public.

Flask in cPanel showing 404 for images under public folder

I have setup a Flask app in a cPanel server with CloudLinux. I used the Setup Python App feature.
The app is at a folder /home/user/app . The app URL is https://www.example.com/app
cPanel uses Phusion Passenger to make the app work with Apache.
When I created the app, a folder /home/user/app/public was created and supposedly all images should go there.
The app is working well, but all URLs to images in the public folder are giving 404 error. I've tried different urls like https://www.example.com/app/image.jpg, and https://www.example.com/app/public/image.jpg . Always 404.
This is the first time I am using this Setup Python App feature.
Does anyone know which is the right URL to use, or what needs to be configured in order for images to be served?
Thanks!
EDIT:
The image url is created using url_for:
return url_for('general.send_data_file', filename=key)
The generated url looks correct
I added a route to serve the files:
#general_blueprint.route('/public/data_store/data/<filename>', methods=['GET'])
def send_data_file(filename):
return send_from_directory(app.config.get('DATA_FOLDER'), filename)
I get 404 instead of the file.
The generated file url is /app/public/data_store/data/test.jpg for example.
The app runs under /app, and all created routes work and don't use the /app when defining the route. I added an app.logger.info call inside the send_data_file, and it is being called.
app.config.get['DATA_FOLDER'] equals ./public/data_store/data
No error in log from send_from_directory .
For serving static files outside your main static folder within your app you need to change that in Flask config like this:
app = Flask(__name__, static_folder='/home/user/app/public')
Then, use url_for as relative path with static as first parameter in your HTML file:
<img src="{{ url_for('static', filename='images/image.svg') }}" alt="svg image">

How to read a Google Cloud Storage file from Google App Engine

How do you open a file (from App Engine) that's stored in Google Cloud Storage?
I am using Python, Flask and App Engine (Flexible environment). The file is not public, the bucket belongs to the App Engine project, so has the correct permissions set.
app.yaml
runtime: python
env: flex
entrypoint: gunicorn -b :$PORT view:app
runtime_config:
python_version: 3.5
env_variables:
CLOUD_STORAGE_BUCKET: <project-xxxx>
view.py
...
from google.cloud import storage
gcs = storage.Client()
#app.route('/start_serving/<file_name>')
def start(file_name):
WHAT TO DO HERE?
#Rest of the app
Thank you in advance.
I couldn't find anything related in documentation. It provides information on how to create a bucket, how to upload, how to download, how to give permission, but nothing about how to read it.
Also, how can I open it from my computer (before running the 'gcloud app deploy' command)?
I have a python2.7 flex app, where I upload to GCS using blob.upload_from_string() but it looks like there is a blob.download_as_string() so maybe something like this would work
from google.cloud import storage
project_id = os.environ['GCLOUD_PROJECT']
CLOUD_STORAGE_BUCKET = "%s.appspot.com" % project_id
#app.route('/start_serving/<file_name>')
def start(file_name):
gcs = storage.Client()
bucket = gcs.get_bucket(CLOUD_STORAGE_BUCKET)
blob = bucket.blob(file_name)
return blob.download_as_string()

Displaying an image with Google Cloud Storage client library on dev server

I'm trying to figure out how to display an image with the Google Cloud Storage client library on the dev server. I figured out how to upload a photo. But not sure how to get it to display while using Flask.
If I deploy to App Engine, I can get the images to display if I link directly to them. Like if I put the following in the template:
<img src="http://storage.googleapis.com/foo/{{ userid }}.jpg">
But that doesn't work on the dev server, because the uploads aren't actually going up to App Engine. So I was wondering how I can read the objects using the client library and display them in Flask.
The following code works for the POST (upload) part. But on the GET, I'm not sure where to go. To get the image to put on the template. I was hoping to just be able to use a URL.
BUCKET = 'foo'
def account():
if request.method == "GET":
#not sure how to get the image to then display on the template
filename = "/".join(['', BUCKET, g.user.key.id()])
gcs_file = gcs.open(filename)
return render_template('users/account.html')
else:
image = request.files.get('file', None)
filename = "/".join(['', BUCKET, g.user.key.id()])
write_retry_params = gcs.RetryParams(backoff_factor=1.1)
with gcs.open(filename, 'w', content_type=image.mimetype,
retry_params=write_retry_params) as imageFile:
image.save(imageFile)
return redirect(url_for("users.account"))
I think what you're looking for is get_serving_url, which now works with Google Cloud Storage. It should also work when using the dev server.
See this question for more information.

Categories