Restore names of uploaded files on submit/draft restore (#65)

This involved turning the list of file IDs stored in the hidden
text field into JSON.
This commit is contained in:
Anna Sidwell 2018-10-12 18:30:47 -04:00
parent b5ccbf631d
commit 79dffadd14
5 changed files with 93 additions and 38 deletions

View File

@ -19,6 +19,9 @@ class BaseFile(models.Model):
def __str__(self):
return self.file.name
def name(self):
return self.file.name
class File(BaseFile):
pass

View File

@ -65,10 +65,25 @@ class MultipleFilesWidget {
}
rebuildListFromField() {
let idList = this.element.field.value.split(",")
for (let id of idList) {
this.addFile(id, `Saved upload (id ${id})`, this.status.DONE)
const fieldContents = this.element.field.value
// Nothing to do
if (fieldContents === '') {
return;
}
try {
let list = JSON.parse(fieldContents)
for (let file of list) {
this.addFile(file.id, file.name, this.status.DONE)
}
} catch (e) {
// Not JSON, let's parse as CSV
for (let id of fieldContents.split(",")) {
this.addFile(id, `Saved upload (id ${id})`, this.status.DONE)
}
}
this.viewFileList()
}
@ -145,9 +160,13 @@ class MultipleFilesWidget {
updateFormField() {
let oldVal = this.element.field.value
this.element.field.value = this.fileList.filter(f => f.id != null)
.map(f => f.id)
.toString()
let fileList = this.fileList.filter(f => f.id != null)
.map(f => ({
id: f.id,
name: f.name
}))
this.element.field.value = JSON.stringify(fileList)
// Mark form as dirty
if (this.element.field.value !== oldVal) {

View File

@ -12,7 +12,7 @@ from leaflet.forms.widgets import LeafletWidget
from apps.files.models import File, ImageFile
from .models import CaseStudy, SpatialRefSys
from .widgets import CommaSeparatedTextInput
from .widgets import JSONFileListWidget
class MinimumZoomWidget(LeafletWidget):
@ -94,7 +94,7 @@ class LongCaseStudyForm(BaseCaseStudyForm):
images_files = forms.ModelMultipleChoiceField(
queryset=ImageFile.objects.all(),
widget=CommaSeparatedTextInput(),
widget=JSONFileListWidget(),
required=False
)
@ -107,7 +107,7 @@ class LongCaseStudyForm(BaseCaseStudyForm):
official_project_documents_files = forms.ModelMultipleChoiceField(
queryset=File.objects.all(),
widget=CommaSeparatedTextInput(),
widget=JSONFileListWidget(),
required=False
)
@ -120,7 +120,7 @@ class LongCaseStudyForm(BaseCaseStudyForm):
other_documents_files = forms.ModelMultipleChoiceField(
queryset=File.objects.all(),
widget=CommaSeparatedTextInput(),
widget=JSONFileListWidget(),
required=False
)
@ -133,7 +133,7 @@ class LongCaseStudyForm(BaseCaseStudyForm):
shapefiles_files = forms.ModelMultipleChoiceField(
queryset=File.objects.all(),
widget=CommaSeparatedTextInput(),
widget=JSONFileListWidget(),
required=False
)

View File

@ -68,7 +68,7 @@ class BaseForm(LoginRequiredMixin, CreateView):
self.object = form.save()
self.object.official_project_documents = form.cleaned_data.get(
'official_project_document_files', []
'official_project_documents_files', []
)
self.object.other_documents = form.cleaned_data.get(
'other_documents_files', []
@ -76,6 +76,9 @@ class BaseForm(LoginRequiredMixin, CreateView):
self.object.shapefiles = form.cleaned_data.get(
'shapefiles_files', []
)
self.object.images = form.cleaned_data.get(
'images_files', []
)
self.object.author = self.request.user
self.object.save()
@ -160,37 +163,33 @@ class Drafts(LoginRequiredMixin, View):
if draft != None:
data = json.loads(draft.data)
for k in ['official_project_documents', 'other_documents',
'shapefiles', 'images' ]:
for k in [ 'official_project_documents', 'other_documents',
'shapefiles', 'images' ]:
try:
# Filter the dictionary of form fields in the draft
# down to just the ones right the right name `k`
items = list(filter(
lambda x: (
x['name'] == '{0}_files'.format(k)
and x['value'] != ''
), data['data']['form']
))
except KeyError:
continue
keyname = k + '_files'
field = data['data']['form'][keyname]
# Split the comma-separated list of IDs into a list
try:
items = items[0]['value'].split(',')
except IndexError:
continue
# Delete those items
for item in items:
try:
f = File.objects.get(id=item)
if f.user != self.request.user:
continue
f.delete()
except File.DoesNotExist:
# Ignore empty fields
if field['value'] == '':
continue
file_list = json.loads(field['value'])
# Delete those items
for item in file_list:
try:
f = File.objects.get(id=item['id'])
if f.user != self.request.user:
continue
f.delete()
except File.DoesNotExist:
continue
except:
continue
draft.delete()
return HttpResponse(status=204)

View File

@ -1,4 +1,7 @@
import json
from django.forms import widgets
from apps.files.models import File
class CommaSeparatedTextInput(widgets.HiddenInput):
@ -19,3 +22,34 @@ class CommaSeparatedTextInput(widgets.HiddenInput):
return value.split(',')
except AttributeError:
return None
def idToDict(id):
file = File.objects.get(pk=id)
return dict(id=id, name=file.name())
# For clarity:
# the canonical format is a list of integers (IDs of files)
# the input/display format is a string containing a JSON list of {id=x, name=y} objects
class JSONFileListWidget(widgets.HiddenInput):
def format_value(self, value):
try:
value = [ idToDict(id) for id in value ]
value = json.dumps(value)
except TypeError:
value = ''
return super().format_value(value)
def value_from_datadict(self, data, files, name):
value = super().value_from_datadict(data, files, name)
if value == '':
return None
try:
filelist = json.loads(value)
return [ file['id'] for file in filelist ]
except JSONDecodeError:
return None