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:
parent
b5ccbf631d
commit
79dffadd14
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
)
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user