From 1084f388829b560079274b78214a6fda41f8ef23 Mon Sep 17 00:00:00 2001 From: Jan Szejko Date: Tue, 4 Dec 2018 17:40:35 +0100 Subject: [PATCH] fix after merge --- contact/forms.py | 48 +++++++++++++++++-- .../0003_auto__add_field_contact_key.py | 42 ++++++++++++++++ contact/models.py | 32 +++++++++++-- contact/urls.py | 2 + contact/views.py | 16 +++++-- 5 files changed, 127 insertions(+), 13 deletions(-) create mode 100644 contact/migrations/0003_auto__add_field_contact_key.py diff --git a/contact/forms.py b/contact/forms.py index 73be1db..a9e3366 100644 --- a/contact/forms.py +++ b/contact/forms.py @@ -5,6 +5,7 @@ from django.core.files.uploadedfile import UploadedFile from django.core.mail import send_mail, mail_managers from django.core.validators import validate_email from django import forms +from django.db.models.fields.files import FieldFile from django.template.loader import render_to_string from django.template import RequestContext from django.utils.translation import ugettext_lazy as _ @@ -39,6 +40,7 @@ class ContactForm(forms.Form): form_tag = None form_type = 'create' + updatable = False old_form_tags = [] form_title = _('Contact form') submit_label = _('Submit') @@ -47,20 +49,29 @@ class ContactForm(forms.Form): mailing_field = None mailing = False data_processing = None + form_formsets = {} + + disabled = False + disabled_template = None required_css_class = 'required' contact = NotImplemented - def __init__(self, *args, **kwargs): + def __init__(self, data=None, files=None, *args, **kwargs): self.instance = kwargs.pop('instance', None) - super(ContactForm, self).__init__(*args, **kwargs) + if self.instance and (data is not None or files is not None): + for attachment in self.instance.attachment_set.all(): + if attachment.tag not in files: + files[attachment.tag] = attachment.file + super(ContactForm, self).__init__(data, files, *args, **kwargs) if not self.is_bound and self.instance: - # files are omitted (not necessary for now) self.fields['contact'].initial = self.instance.contact body = self.instance.body for field, value in body.iteritems(): if field in self.fields: self.fields[field].initial = value + for attachment in self.instance.attachment_set.all(): + self.fields[attachment.tag].initial = attachment def get_dictionary(self, contact): site = Site.objects.get_current() @@ -71,11 +82,36 @@ class ContactForm(forms.Form): 'contact': contact, } + @classmethod + def is_disabled(cls): + # end_time = localtime_to_utc(datetime(*cls.ends_on)) if cls.ends_on else None + # expired = end_time and end_time < timezone.now() + return cls.disabled # or expired + + def formset_initial(self, prefix): + if not self.instance: + return None + return self.instance.body.get(prefix) + + def get_formsets(self, request=None): + request_data = {'data': request.POST, 'files': request.FILES} if request else {} + kwargs_instance = dict(request_data) + kwargs_instance['instance'] = self.instance + formsets = {} + for prefix, formset_class in self.form_formsets.iteritems(): + if getattr(formset_class, 'takes_instance', False): + kwargs = kwargs_instance + else: + kwargs = request_data + formsets[prefix] = formset_class( + prefix=prefix, initial=self.formset_initial(prefix), **kwargs) + return formsets + def save(self, request, formsets=None): from .models import Attachment, Contact body = {} for name, value in self.cleaned_data.items(): - if not isinstance(value, UploadedFile) and name != 'contact': + if not isinstance(value, UploadedFile) and not isinstance(value, FieldFile) and name != 'contact': body[name] = value for formset in formsets or []: @@ -100,10 +136,12 @@ class ContactForm(forms.Form): ip=request.META['REMOTE_ADDR'], contact=self.cleaned_data['contact'], form_tag=self.form_tag) + contact.generate_key() + contact.save() email_changed = True - # not intended to be used with update forms for name, value in self.cleaned_data.items(): if isinstance(value, UploadedFile): + Attachment.objects.filter(contact=contact, tag=name).delete() # delete files? attachment = Attachment(contact=contact, tag=name) attachment.file.save(value.name, value) attachment.save() diff --git a/contact/migrations/0003_auto__add_field_contact_key.py b/contact/migrations/0003_auto__add_field_contact_key.py new file mode 100644 index 0000000..d9347a4 --- /dev/null +++ b/contact/migrations/0003_auto__add_field_contact_key.py @@ -0,0 +1,42 @@ +# -*- coding: utf-8 -*- +from south.utils import datetime_utils as datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Adding field 'Contact.key' + db.add_column(u'contact_contact', 'key', + self.gf('django.db.models.fields.CharField')(default='#', max_length=30), + keep_default=False) + + + def backwards(self, orm): + # Deleting field 'Contact.key' + db.delete_column(u'contact_contact', 'key') + + + models = { + u'contact.attachment': { + 'Meta': {'object_name': 'Attachment'}, + 'contact': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contact.Contact']"}), + 'file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'tag': ('django.db.models.fields.CharField', [], {'max_length': '64'}) + }, + u'contact.contact': { + 'Meta': {'ordering': "('-created_at',)", 'object_name': 'Contact'}, + 'body': ('jsonfield.fields.JSONField', [], {}), + 'contact': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'form_tag': ('django.db.models.fields.CharField', [], {'max_length': '32', 'db_index': 'True'}), + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'ip': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}), + 'key': ('django.db.models.fields.CharField', [], {'max_length': '30'}) + } + } + + complete_apps = ['contact'] \ No newline at end of file diff --git a/contact/models.py b/contact/models.py index f07b33a..fb8c8ac 100644 --- a/contact/models.py +++ b/contact/models.py @@ -1,6 +1,8 @@ # -*- coding: utf-8 -*- import yaml from hashlib import sha1 +import random +import string from django.db import models from django.utils.encoding import smart_unicode, force_str from django.db.models import permalink @@ -9,12 +11,29 @@ from jsonfield import JSONField from . import app_settings +KEY_SIZE = 30 + + +def make_key(length): + return ''.join( + random.choice(string.ascii_uppercase + string.ascii_lowercase + string.digits) + for i in range(length)) + + class Contact(models.Model): created_at = models.DateTimeField(_('submission date'), auto_now_add=True) ip = models.IPAddressField(_('IP address')) contact = models.CharField(_('contact'), max_length=128) form_tag = models.CharField(_('form'), max_length=32, db_index=True) body = JSONField(_('body')) + key = models.CharField(max_length=KEY_SIZE) + + @classmethod + def generate_key(cls): + key = '' + while not key or cls.objects.filter(key=key).exists(): + key = make_key(KEY_SIZE) + return key @staticmethod def pretty_print(value, for_html=False): @@ -40,10 +59,7 @@ class Contact(models.Model): @permalink def update_url(self): - from contact.forms import update_forms, contact_forms - form_class = update_forms.get(self.form_tag, contact_forms.get(self.form_tag)) - confirmation = form_class.confirmation_class.objects.get(contact=self) - return 'edit_form', [], {'form_tag': self.form_tag, 'contact_id': self.id, 'key': confirmation.key} + return 'edit_form', [], {'form_tag': self.form_tag, 'contact_id': self.id, 'key': self.key} class Attachment(models.Model): @@ -55,5 +71,13 @@ class Attachment(models.Model): def get_absolute_url(self): return 'contact_attachment', [self.contact_id, self.tag] + @property + @models.permalink + def url(self): + return 'contact_attachment_key', [self.contact_id, self.tag, self.contact.key] + + def __unicode__(self): + return self.file.name.rsplit('/', 1)[-1] + __import__(app_settings.FORMS_MODULE) diff --git a/contact/urls.py b/contact/urls.py index b0866ed..ed6f49c 100644 --- a/contact/urls.py +++ b/contact/urls.py @@ -8,5 +8,7 @@ urlpatterns = patterns( url(r'^(?P[^/]+)/edit/(?P[0-9]+)/(?P[0-9a-zA-Z]+)/$', views.form, name='edit_form'), url(r'^(?P[^/]+)/thanks/$', views.thanks, name='contact_thanks'), url(r'^attachment/(?P\d+)/(?P[^/]+)/$', views.attachment, name='contact_attachment'), + url(r'^attachment/(?P\d+)/(?P[^/]+)/(?P[0-9a-zA-Z]+)/$', views.attachment_key, + name='contact_attachment_key'), url(r'^results/(?P\d+)/(?P[0-9a-f]+)/', views.results, name='contact_results'), ) diff --git a/contact/views.py b/contact/views.py index 0316b20..580a65d 100644 --- a/contact/views.py +++ b/contact/views.py @@ -24,15 +24,14 @@ def form(request, form_tag, force_enabled=False, contact_id=None, key=None): except KeyError: raise Http404 if not (force_enabled and request.user.is_superuser): - disabled = getattr(form_class, 'disabled', False) - if disabled: - template = getattr(form_class, 'disabled_template', None) + if form_class.is_disabled(): + template = form_class.disabled_template if template: return render(request, template, {'title': form_class.form_title}) raise Http404 if contact_id: contact = get_object_or_404(Contact, id=contact_id, form_tag=form_tag) - if form_tag != 'olimpiada': + if not form_class.updatable: raise Http404 if key != contact.key: raise Http404 @@ -93,3 +92,12 @@ def attachment(request, contact_id, tag): attachment = get_object_or_404(Attachment, contact_id=contact_id, tag=tag) attachment_url = unquote(attachment.file.url) return serve_file(attachment_url) + + +def attachment_key(request, contact_id, tag, key): + contact = Contact.objects.get(id=contact_id) + if key != contact.key: + raise Http404 + attachment = get_object_or_404(Attachment, contact_id=contact_id, tag=tag) + attachment_url = unquote(attachment.file.url) + return serve_file(attachment_url) -- 2.20.1