How to select the download location in flask send_file? - python

I am working on a flask based UI and there I am downloading a text file using send_file function.
This is my directory setup:
/static
/design.css
/templates
/index.html
/upload.html
/engine.html
/output
/text_file.txt
/main.py
Below is the code:
#app.route('/download')
def download_file():
path = "output\\text_file.txt"
return send_file(path, as_attachment=True)
And below is related html button which is initiating the download:
<button>
<a href="{{ url_for('.download_file') }}" style="color: white; text-decoration: none;">Download Source Text
</a>
</button>
Now this function is directly downloading the file in downloads folder of my local C drive. But I want to get an option to select the location like below:
(image taken from google)
How can I achieve this?

The path to save the downloaded file is decided by a browser and server-side application cannot change this--and this is a feature, not a bug.
You think about it--say a server application can pick a location to save a file, what if my website saves an exe file to your C:\Windows folder? The consequence is disastrous...
Some modern browsers allow users to set a default download path. If you discover that your file is saved to a folder, such as Downloads, without asking you, most likely you have this browser feature enabled.

Related

http.server (SimpleHTTPServer) serve file.html instead of dir (using cmd)

Is it possible to serve not a index of a directory but rather an html file using Python SimpleHTTPServer on path '/'?
Having directory with one file login.html serves a directory index on path '/'.
python -m SimpleHTTPServer 7800
I want a content of login.html on '/'.
Is that possible?
SimpleHTTPServer (or http.server in Python3) will serve a directory unless that directory contains a file called index.html, in which case it will serve that instead.
So just rename login.html to index.html and it should do what you want.
By default http server looks for index.html file and loads it. Otherwise it will serve the directory structure.
You can extend SimpleHTTPServer and write your own class with proper routing. I would prefer this.
But alternatively you could also add a redirect in index.html.
<html>
<body>
<!-- redirect on load -->
<script>
window.onload = function () {
window.location.href = "login.html";
}
</script>
</body>
</html>

Flask rendering templates from another folder

I have a simple flask app with only an index.html page (so far), it's located in a folder with a bunch of javascript and CSS, which makes it a bit difficult to render.
I tried listing the file path for my HTML, however, it gives an internal server error, when I open the browser. Should I instead declare the path as a variable and pass that in?
I'm on Linux Ubuntu 16.04 btw.
here is my sample code:
from flask import Flask, render_template
app = Flask(__name__)
#app.route("/")
#app.route("/home")
def home():
return render_template('/frontend/index.html')
here is how my directory is listed
--flaskwebsite
----routes.py
----routes.pyc
----templates
------frontend(other folders, javascript files etc)
------index.html
If Im seeing your folder structure correctly.
'templates/frontend/index.html'
Also you should have a separate template folder and a separate folder for static files such as css, js, pictures, and fonts.

Folder picker in HTML with Flask for Uploads

I am running a Flask app where the user uploads a file and must select the root folder path of where to upload the file on a network drive. This path is an IIS available network path and is also a network drive on all user's computers.
I want to dynamically show the available folders in HTML, even if new folders are created after the app starts.
I know this can't be done with pure HTML due to security but wanted to know if there was a way around this with Flask. The goal is to use Python to move the upload file to the choosen folder path.
I have tried:
<form><input type="file" name=dir webkitdirectory directory multiple/></form>
But this only works in Chrome. With the path choosen by the user I can pass this onto Python to copy the upload file to there.
Due to modern browser limitations I decided to use JSTree as a solution. And it is working very well. It features a tree structure browser. The structure is the result of outputting the folders as JSON. You can add a search bar as well so the user can just type in a folder name to search.
Please see JSTree https://www.jstree.com/
How to implement this with Flask
HTML/JS:
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.2.1/themes/default/style.min.css">
<div>
<input class="search-input form-control" placeholder="Search for folder"></input>
</div>
<script id="jstree1" name="jstree1">
/*Search and JS Folder Tree*/
$(function () {
$(".search-input").keyup(function () {
var searchString = $(this).val();
console.log(searchString);
$('#container').jstree('search', searchString);
});
$('#container').jstree({
'core': {
"themes": {
"name": "default"
, "dots": true
, "icons": true
}
, 'data': {
'url': "static/JSONData.json"
, 'type': 'GET'
, 'dataType': 'JSON'
}
}
, "search": {
"case_insensitive": true
, "show_only_matches": true
}
, "plugins": ["search"]
});
});
{ /* --- THIS IS FOLDER SELECTOR FOR ID "folderout" --- */
$("#container").on("select_node.jstree", function (evt, data) {
var number = data.node.text
document.getElementById("folderout").value = number;
});
In Flask/WTForms call on the id "folderout". This will return the path to WTForms when the user clicks the folder.
folderout = TextField('Folder:', validators=[validators.required()])
To Create the JSON JStree File using Python:
import os
# path : string to relative or absolute path to be queried
# subdirs: tuple or list containing all names of subfolders that need to be
# present in the directory
def all_dirs_with_subdirs(path, subdirs):
# make sure no relative paths are returned, can be omitted
path = os.path.abspath(path)
result = []
for root, dirs, files in os.walk(path):
if all(subdir in dirs for subdir in subdirs):
result.append(root)
return result
def get_directory_listing(path):
output = {}
output["text"] = path.decode('latin1')
output["type"] = "directory"
output["children"] = all_dirs_with_subdirs(path, ('Maps', 'Reports'))
return output
with open('test.json', 'w+') as f:
listing = get_directory_listing(".")
json.dump(listing, f)
Python runs on your server, therefoere it will not be possible to use that to move the files on the client side. If you think about it, let's assume you manage to somehow (magically) send python commands to the clients to move files, do you know if they even have python installed to be able to interpret your commands?
Javascript on the other hand is running on client side and was used to achieve this. However, like you said, due to security reasons modern browswers won't allow that. If they would allow it then any website could potentially see your whole File System.
Here is an article that explains a bit why. Look up the File Upload Control section of it. Hope this makes things a bit clearer.
EDIT: after seeing your comment you could achieve that using os.walk. Beware it could be slow.
for root, dirs, files in os.walk(rootPath): # for example "C:/Users/"
for file in files:
if file == (wantedFile):
print(os.path.join(root,file))
break

Show files uploaded of a particular format on ftp server using python

I am working on a ftp webapp. I have created everything till uploading part, i.e, File is successfully uploaded into ftpuser's directory. Now I am providing users option to see files they uploaded by format. Example: if users clicks on icon of browse images then they should be shown all the images they have uploaded.
Commands like "Retr" starts downloading files other than texts and pdf but I want to enlist all the files and not download. I have no idea about how to do this.
I am using Flask for webapp and ftplib for uploading.
By suggestions made by #tdelaney. I formed the solution by uploading different file formats to a different directory in ftp user's directory. So when the user clicks on display images he is displayed names of files in the images folder. Code for the following is given below:
if c=='images':
ftp=FTP('127.0.0.1',userid,passwd)
if not 'images' in ftp.nlst():
ftp.mkd('images')
ftp.cwd('images')
elif c=='documents':
ftp=FTP('127.0.0.1',userid,passwd)
if not 'documents' in ftp.nlst():
ftp.mkd('documents')
ftp.cwd('documents')
elif c=='audios':
ftp=FTP('127.0.0.1',userid,passwd)
if not 'audios' in ftp.nlst():
ftp.mkd('audios')
ftp.cwd('audios')
elif c=='videos':
ftp=FTP('127.0.0.1',userid,passwd)
if not 'videos' in ftp.nlst():
ftp.mkd('videos')
ftp.cwd('videos')
else:
ftp=FTP('127.0.0.1',userid,passwd)
if not 'others' in ftp.nlst():
ftp.mkd('others')
ftp.cwd('others')
files=ftp.nlst()
and further ftp.nlst() is used to get the list of files in that directory which is then passed to template and printed by following code:
<table>
<tr>
{% for file in files %}
<td>{{file}}</td>
{% endfor %}
</tr>
</table>

Google App Engine No such file or directory:

I'm trying to deploy a project to Google App Engine. The main HTML page I render is stored in the /documents/form.html directory of the project. If I run on my local host it finds the file no problem. When I deploy to GAE it gives the below error:
File "/base/data/home/apps/s~andesonchase/1.372703354720880550/main.py", line 4, in <module>
fileHandle = open("documents/form.html", "r")
IOError: [Errno 2] No such file or directory: 'documents/form.html'
I think I need to include it on my app.yaml but I'm not sure on the correct syntax.
I can list three options for you
A) as suggested by the previous poster is to add to app.yaml as either a static_files entry or by making documents a static_dir which would allow access to the files using raw http requests but completely bypassing your handlers in main.py
B) [probably the most kosha] is to access the file with the jinja2 template library as explained here which doesn't require you to add the files explicitly to app.yaml
C) or you could stick with whatever your doing inside main.py at the moment but modify your open statement as follows
import os.path
f = open(os.path.dirname(__file__) + '/documents/form.html')
as explained in this stackoverlflow answer since open works a little differently with appengine
If you want to serve it as a static file add it like this:
Add it to your app.yaml and replace /form with the url you please
- url: /form
static_files: documents/form.html
upload: documents/form.html
If you need to run a script then it's different.

Categories

Resources