Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cleanup export temp attachment files #1326

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
2 changes: 1 addition & 1 deletion main/tests/test_form_exports.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ def test_zip_raw_export_name(self):
'id_string': self.xform.id_string})
response = self.client.get(url + '?raw=1')
self.assertEqual(response.status_code, 200)
self.assertEqual(response['Content-Disposition'], 'attachment;')
self.assertEqual(response['Content-Disposition'], 'attachment; filename=%s.zip' % self.xform.id_string)

def test_restrict_zip_export_if_not_shared(self):
url = reverse(zip_export, kwargs={'username': self.user.username,
Expand Down
19 changes: 11 additions & 8 deletions odk_viewer/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
from odk_viewer.pandas_mongo_bridge import NoRecordsFoundError
from utils.image_tools import image_url
from xls_writer import XlsWriter
from django.core.servers.basehttp import FileWrapper
# response_with_mimetype_and_name() needs to be put down, and taken out of its misery
from utils.logger_tools import response_with_mimetype_and_name,\
disposition_ext_and_date
from utils.viewer_tools import image_urls
Expand Down Expand Up @@ -558,10 +560,8 @@ def zip_export(request, username, id_string):
helper_auth_helper(request)
if not has_permission(xform, owner, request):
return HttpResponseForbidden(_(u'Not shared.'))
if request.GET.get('raw'):
id_string = None

attachments = Attachment.objects.filter(instance__xform=xform)
zip_file = create_attachments_zipfile(attachments)
audit = {
"xform": xform.id_string,
"export_type": Export.ZIP_EXPORT
Expand All @@ -579,11 +579,14 @@ def zip_export(request, username, id_string):
{
'id_string': xform.id_string,
}, audit, request)
if request.GET.get('raw'):
id_string = None
response = response_with_mimetype_and_name('zip', id_string,
file_path=zip_file,
use_local_filesystem=True)

# return the HTTP response: the zip file as a raw stream
zip_data = create_attachments_zipfile(attachments)
response = HttpResponse(FileWrapper(zip_data),
content_type='application/zip')
response['Content-Disposition'] = 'attachment; filename=%s.zip' % xform.id_string
response['Content-Length'] = zip_data.tell()
zip_data.seek(0)
return response


Expand Down
37 changes: 18 additions & 19 deletions utils/export_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -676,37 +676,36 @@ def generate_attachments_zip_export(

xform = XForm.objects.get(user__username=username, id_string=id_string)
attachments = Attachment.objects.filter(instance__xform=xform)
zip_file = create_attachments_zipfile(attachments)
basename = "%s_%s" % (id_string,
datetime.now().strftime("%Y_%m_%d_%H_%M_%S"))
filename = basename + "." + extension

filename = "%s_%s.%s" % (id_string,
datetime.now().strftime("%Y_%m_%d_%H_%M_%S"),
extension)

file_path = os.path.join(
username,
'exports',
id_string,
export_type,
filename)

storage = get_storage_class()()
temp_file = open(zip_file)
export_filename = storage.save(
file_path,
File(temp_file, file_path))
temp_file.close()

dir_name, basename = os.path.split(export_filename)
export_type)

# get or create export object
# get or create the Export object
if(export_id):
export = Export.objects.get(id=export_id)
else:
export = Export.objects.create(xform=xform,
export_type=export_type)

export.filedir = dir_name
export.filename = basename
export.internal_status = Export.SUCCESSFUL
export.filedir = file_path
export.filename = filename
try:
zip_data = create_attachments_zipfile(attachments)
zip_data.seek(0)
with open(os.path.join(file_path, filename), 'wb') as f:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is this file being saved? Notice this is during an aync export, my worry was that this is in the local file system and would count towards using the storage space for the root file system. Is this file deleted at some point?

f.write( zip_data.read() )
export.internal_status = Export.SUCCESSFUL
except IOError:
export.internal_status = Export.FAILED
export.save()

return export


Expand Down
12 changes: 8 additions & 4 deletions utils/viewer_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import zipfile

from xml.dom import minidom
from tempfile import NamedTemporaryFile
from tempfile import TemporaryFile
from urlparse import urljoin

from django.conf import settings
Expand Down Expand Up @@ -197,8 +197,12 @@ def enketo_url(form_url, id_string, instance_xml=None,


def create_attachments_zipfile(attachments):
# create zip_file
tmp = NamedTemporaryFile(delete=False)
"""Create a zip file using the list of Attachment objects as the
contents, and return the file-like object which represents the zipped
file, WITHOUT actually writing a file in the system temp folder that
never gets cleaned up"""

tmp = TemporaryFile()
z = zipfile.ZipFile(tmp, 'w', zipfile.ZIP_DEFLATED, allowZip64=True)
for attachment in attachments:
default_storage = get_storage_class()()
Expand All @@ -208,4 +212,4 @@ def create_attachments_zipfile(attachments):
except Exception, e:
report_exception("Create attachment zip exception", e)
z.close()
return tmp.name
return tmp