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): def __str__(self):
return self.file.name return self.file.name
def name(self):
return self.file.name
class File(BaseFile): class File(BaseFile):
pass pass

View File

@ -65,10 +65,25 @@ class MultipleFilesWidget {
} }
rebuildListFromField() { rebuildListFromField() {
let idList = this.element.field.value.split(",") const fieldContents = this.element.field.value
for (let id of idList) {
this.addFile(id, `Saved upload (id ${id})`, this.status.DONE) // 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() this.viewFileList()
} }
@ -145,9 +160,13 @@ class MultipleFilesWidget {
updateFormField() { updateFormField() {
let oldVal = this.element.field.value let oldVal = this.element.field.value
this.element.field.value = this.fileList.filter(f => f.id != null) let fileList = this.fileList.filter(f => f.id != null)
.map(f => f.id) .map(f => ({
.toString() id: f.id,
name: f.name
}))
this.element.field.value = JSON.stringify(fileList)
// Mark form as dirty // Mark form as dirty
if (this.element.field.value !== oldVal) { 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 apps.files.models import File, ImageFile
from .models import CaseStudy, SpatialRefSys from .models import CaseStudy, SpatialRefSys
from .widgets import CommaSeparatedTextInput from .widgets import JSONFileListWidget
class MinimumZoomWidget(LeafletWidget): class MinimumZoomWidget(LeafletWidget):
@ -94,7 +94,7 @@ class LongCaseStudyForm(BaseCaseStudyForm):
images_files = forms.ModelMultipleChoiceField( images_files = forms.ModelMultipleChoiceField(
queryset=ImageFile.objects.all(), queryset=ImageFile.objects.all(),
widget=CommaSeparatedTextInput(), widget=JSONFileListWidget(),
required=False required=False
) )
@ -107,7 +107,7 @@ class LongCaseStudyForm(BaseCaseStudyForm):
official_project_documents_files = forms.ModelMultipleChoiceField( official_project_documents_files = forms.ModelMultipleChoiceField(
queryset=File.objects.all(), queryset=File.objects.all(),
widget=CommaSeparatedTextInput(), widget=JSONFileListWidget(),
required=False required=False
) )
@ -120,7 +120,7 @@ class LongCaseStudyForm(BaseCaseStudyForm):
other_documents_files = forms.ModelMultipleChoiceField( other_documents_files = forms.ModelMultipleChoiceField(
queryset=File.objects.all(), queryset=File.objects.all(),
widget=CommaSeparatedTextInput(), widget=JSONFileListWidget(),
required=False required=False
) )
@ -133,7 +133,7 @@ class LongCaseStudyForm(BaseCaseStudyForm):
shapefiles_files = forms.ModelMultipleChoiceField( shapefiles_files = forms.ModelMultipleChoiceField(
queryset=File.objects.all(), queryset=File.objects.all(),
widget=CommaSeparatedTextInput(), widget=JSONFileListWidget(),
required=False required=False
) )

View File

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

View File

@ -1,4 +1,7 @@
import json
from django.forms import widgets from django.forms import widgets
from apps.files.models import File
class CommaSeparatedTextInput(widgets.HiddenInput): class CommaSeparatedTextInput(widgets.HiddenInput):
@ -19,3 +22,34 @@ class CommaSeparatedTextInput(widgets.HiddenInput):
return value.split(',') return value.split(',')
except AttributeError: except AttributeError:
return None 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