Send mail per request in django - python

This is really killing me. I've been dealing with this for days.
When a user download a file from my django web app, I want to notify the uploader that his file has been downloaded by sending a mail. The problem is, If I should download a low file size (489kb), it will send a mail once to the uploader. But if I should download a file size of 3mb or above it will send more than one mail to the uploader.
I just want it to send one mail notification to the uploader per download.
views:
#login_required
def document_view(request,emov_id):
fileload = Emov.objects.get(id=emov_id)
filename = fileload.mov_file.name.split('/')[-1]
filesize=fileload.mov_file.size
response = HttpResponse(fileload.mov_file, content_type='')
response['Content-Disposition'] = 'attachment; filename=%s' % filename
response['Content-Length'] = filesize
send_mail('Your file has just been downloaded',loader.get_template('download.txt').render(Context({'fileload':fileload})),'test#example.com',[fileload.email,])
return response
download.txt
'Your file {{ fileload.name}} have been downloaded!'
How can I send mail per download request?

I would suggest a different approach...
When someone download the file, log the event to a table on your database.
Write the Session ID, the file name, the user name.
Make sure that session_id+file_name+user_name are unique key
This way, you can get much more information that can help you later.
Later on (as a crontab batch, or save listener) send the emails.
You can even send a daily/weekly report and so on...

I think you would solve this problem just with following best practises which say "Do not serve files with Django".
Instead, use X-Sendfile HTTP header in your response and configure your webserver to catch it and serve the file. See this if you're using Apache.
Then, create the response as follows:
response = HttpResponse()
response['X-Sendfile'] = unicode(filename).encode('utf-8')
response['Content-Type'] = 'application/octet-stream'
response['Content-Disposition'] = 'attachment; filename="%s"' % filename
response['Content-length'] = filesize # Optional
return response

Related

Flask redirect to external file and provide filename instead of original

I use Flask to serve application. Until recently, Flask was serving files for download using response stream.
Because of increased number of worker errors, I now need to redirect request to external location, where files are stores in 7249ed01-9c3d-45fe-895c-5a27db785d2d.tar.gz filename format. Redirect itself works, but filename displayed in save dialog in browser is still 7249ed01-9c3d-45fe-895c-5a27db785d2d.
Code example is below.
#app.route("/download/<filename>")
def view_file_download(filename):
# filename can be ignored, used to retrieve info from db
url = "https://example.com/7249ed01-9c3d-45fe-895c-5a27db785d2d.tar.gz"
filename_orig = "example.tar.gz"
filesize = 123456
res = flask.redirect(url, code=303)
res.headers.set("Location", url)
res.headers.set("Content-Disposition", "attachment", filename=filename_orig)
res.headers.set("Content-Length", filesize)
return res
It is not possible to provide content-disposition header for redirect response.
Major browsers do not support this feature any longer. It is required that server serving files contain content-disposition in own response and it will tell browser to use that instead of hashed filename.

How to set file name in response

I know about content-disposition but I read what it uses for email messages. And I want to know how I can set file name with content-type.
ps I use Pyramid framework
edit:
Web site has button 'download' how to perform Response object for file name too, like
return Response(body=f.read(), content_type='application/octet-stream')
and what I need to do for showing correct file name in browser.
You need to set the filename parameter of the Content-Disposition header like so:
response.content_disposition = 'attachment; filename="my_filename.txt"'
Use f string in python like below:
response = HttpResponse(file_data, content_type='application/pdf')
response['Content-Disposition'] = f'attachment; filename="{filename}"'
return response

Django: how to give mp3 file correctly

The problem is I can't change playing position by clicking on a timeline in google Chrome (it always plays from start to end)
If Nginx gives mp3 file to the client everything is OK and I can change playing position.
In my script I give mp3 this way:
from django.core.servers.basehttp import FileWrapper
wrapper = FileWrapper(file( 'mp3file.mp3' ))
response = HttpResponse(wrapper, content_type='audio/mpeg')
response['Content-Length'] = os.path.getsize( 'mp3file.mp3' )
return response
The url is: http://server/mp3/###.mp3
So the whole file is given to the client, but still playing pos can't be changed. What is wrong?
PS:
Do not use any proprietary sh*t like mp3 - use ".ogg" format
This is because the headers should handle additiona headers (like Accept-Ranges), and it should handle partial file requests
Doing this kind of things inside Django itself is a mess (I tried it some time ago), but then I ended up using Apache for serving files (this way you just don't waste resources)
You can consider using mod_xsendfile for being able to serve files from your django view using apache, in this way for example:
response = HttpResponse(mimetype='audio/mpeg')
response['Content-Disposition'] = 'attachment; filename=%s' % smart_str(file_name)
response['Accept-Ranges'] = 'bytes'
response['X-Sendfile'] = smart_str(path_to_file)
return response

Get selected path from response

I am using
response.headers['Content-Type'] = gluon.contenttype.contenttype('.xls')
response.headers['Content-disposition'] = 'attachment; filename=projects.xls'
to generate save as dialog box.
Is there a way to get the selected path by the user?
The browser displays the Save As dialog box to the user, then writes your content into that file. It doesn't inform the server what path the content was saved to. I'm afraid you can't get that information.
If your question is about how to send the file contents to the user, you simply write the content to your response object. The browser takes care of actually writing the file to the path selected by the user.
In Django, you would do something like:
def view(request):
# get the file content from somewhere
response = HttpResponse(file_content, mimetype='application/vnd.ms-excel')
response['Content-Disposition'] = 'attachment; filename=projects.xls'
return response
The browser will then prompt the user for a path and save the file "projects.xls" to that path.

File Sharing Site in Python

I wanted to design a simple site where one person can upload a file, and pass off the random webaddress to someone, who can then download it.
At this point, I have a webpage where someone can successfully upload a file which gets stored under /files/ on my webserver.
The python script also generates a unique, random 5 letter code that gets stored in a database identifying the file
I have another page called retrieve, where a person should go, put in the 5 letter code, and it should pop up a filebox asking where to save the file.
My Problem is that: 1) How do I retrieve the file for download? At this point my retrieve script, takes the code, gets the location of the file on my server, but how do I get the brower to start downloading?
2)How do I stop people from directly going to the file? Should I change permissions on the file?
How do you serve the file-upload page, and how do you let your users upload files?
If you are using Python's built-in HTTP server modules you shouldn't have any problems.
Anyway, here's how the file serving part is done using Python's built-in modules (just the basic idea).
Regarding your second question, if you were using these modules in the first place you probably wouldn't have asked it because you'd have to explicitly serve specific files.
import SocketServer
import BaseHTTPServer
class RequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
def do_GET(self):
# The URL the client requested
print self.path
# analyze self.path, map the local file location...
# open the file, load the data
with open('test.py') as f: data = f.read()
# send the headers
self.send_response(200)
self.send_header('Content-type', 'application/octet-stream') # you may change the content type
self.end_headers()
# If the file is not found, send error code 404 instead of 200 and display a message accordingly, as you wish.
# wfile is a file-like object. writing data to it will send it to the client
self.wfile.write(data)
# XXX: Obviously, you might want to send the file in segments instead of loading it as a whole
if __name__ == '__main__':
PORT = 8080 # XXX
try:
server = SocketServer.ThreadingTCPServer(('', 8080), RequestHandler)
server.serve_forever()
except KeyboardInterrupt:
server.socket.close()
You should send the right HTTP Response, containing the binary data and making the browser react on it.
Try this (I haven't) if you're using Django:
response = HttpResponse()
response['X-Sendfile'] = os.path.join(settings.MEDIA_ROOT, file.file.path)
content_type, encoding = mimetypes.guess_type(file.file.read())
if not content_type:
content_type = 'application/octet-stream'
response['Content-Type'] = content_type
response['Content-Length'] = file.file.size
response['Content-Disposition'] = 'attachment; filename="%s"' % file.file.name
return response
Source: http://www.chicagodjango.com/blog/permission-based-file-serving/

Categories

Resources