Skip to content

Commit

Permalink
Fix merge conflict
Browse files Browse the repository at this point in the history
  • Loading branch information
hedleyroos committed Mar 13, 2017
2 parents 80095cd + 1ec65be commit 12ddd4e
Show file tree
Hide file tree
Showing 23 changed files with 534 additions and 88 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ pep8.txt
.coverage
*.db
.idea/
*media/
2 changes: 2 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,8 @@ FormFactory come with some predefined actions:
- login: logs a user in. Requires the following ``ActionParam``
- username_field: mapping to the form field where the username will be completed.
- password_field: mapping to the form field where the username will be completed.
- file_upload: handles uploading files to a predefined path. Requires the following ``ActionParam``
- upload_path_field: mapping to the form field where the upload path has been set.

Custom actions can be added by creating a function in <yourapp or project>/formfactoryapp/actions.py. For example::

Expand Down
22 changes: 15 additions & 7 deletions formfactory/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,23 @@
SETTINGS = getattr(settings, "FORMFACTORY", {
"field-types": [
"BooleanField", "CharField", "ChoiceField", "DateField",
"DateTimeField", "DecimalField", "EmailField", "FloatField",
"GenericIPAddressField", "IntegerField", "MultipleChoiceField",
"SlugField", "SplitDateTimeField", "TimeField", "URLField", "UUIDField"
"DateTimeField", "DecimalField", "EmailField", "FileField",
"FloatField", "GenericIPAddressField", "IntegerField",
"MultipleChoiceField", "SlugField", "SplitDateTimeField", "TimeField",
"URLField", "UUIDField"
],
"widget-types": [
"TextInput", "NumberInput", "EmailInput", "URLInput", "PasswordInput",
"HiddenInput", "DateInput", "DateTimeInput", "TimeInput",
"Textarea", "CheckboxInput", "Select", "NullBooleanSelect",
"SelectMultiple", "RadioSelect", "CheckboxSelectMultiple"
"CheckboxInput", "CheckboxSelectMultiple", "DateInput",
"DateTimeInput", "EmailInput", "FileInput", "HiddenInput",
"NullBooleanSelect", "NumberInput", "PasswordInput", "RadioSelect",
"Select", "SelectMultiple", "Textarea", "TextInput", "TimeInput",
"URLInput"
],
"error-types": [
"empty", "incomplete", "invalid", "invalid_choice", "invalid_image",
"invalid_list", "invalid_date", "invalid_time", "invalid_pk_value",
"list", "max_decimal_places", "max_digits", "max_length", "max_value",
"max_whole_digits", "min_length", "min_value", "missing", "required",
],
"redirect-url-param-name": "next"
})
Expand Down
38 changes: 37 additions & 1 deletion formfactory/actions.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
import os

from django.conf import settings
from django.core.files.uploadedfile import InMemoryUploadedFile
from django.core.mail import send_mail
from django.contrib import auth

from formfactory import _registry, exceptions
from formfactory.utils import auto_registration, clean_key, get_label
from formfactory.utils import (
auto_registration, clean_key, get_label, increment_file_name
)


def register(func):
Expand Down Expand Up @@ -104,3 +110,33 @@ def login(form_instance, **kwargs):
)
if user is not None:
auth.login(request, user)


@register
def file_upload(form_instance, **kwargs):
"""An action which uploads all files to a specific location.
"""
cleaned_data = form_instance.cleaned_data

file_objects = [
f for f in cleaned_data.values() if isinstance(f, InMemoryUploadedFile)
]

try:
upload_path = cleaned_data.pop(kwargs["upload_path_field"])
except KeyError:
raise exceptions.MissingActionParam("file_upload", "upload_path_field")

full_upload_path = os.path.join(settings.MEDIA_ROOT, upload_path)

# Creates the dir path if it does not already exist
if not os.path.exists(full_upload_path):
os.makedirs(full_upload_path)

for file_object in file_objects:
file_path = increment_file_name(
os.path.join(full_upload_path, file_object.name)
)
with open(file_path, "wb+") as destination:
for chunk in file_object.chunks():
destination.write(chunk)
27 changes: 27 additions & 0 deletions formfactory/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,29 @@ class ActionModelAdmin(admin.ModelAdmin):
inlines = [FormActionParamInline]


class ValidatorModelAdmin(admin.ModelAdmin):
form = forms.ValidatorAdminForm
model = models.Validator


class FieldCustomErrorInline(admin.StackedInline):
model = models.FormFieldErrorMessageProxy
verbose_name = "Error message"
verbose_name_plural = "Error messages"
form = forms.CustomErrorInlineAdminForm


class FieldValidatorInline(admin.StackedInline):
model = models.FormFieldValidatorProxy
verbose_name = "Additional validator"
verbose_name_plural = "Additional validators"


class CustomErrorModelAdmin(admin.ModelAdmin):
form = forms.CustomErrorAdminForm
model = models.CustomErrorMessage


class FormActionThroughInline(admin.StackedInline):
form = forms.FormActionThroughAdminForm
model = models.FormActionThrough
Expand Down Expand Up @@ -80,9 +103,13 @@ class FormFieldGroupAdmin(admin.ModelAdmin):
class FormFieldAdmin(admin.ModelAdmin):
form = forms.FormFieldAdminForm
model = models.FormField
inlines = [FieldCustomErrorInline, FieldValidatorInline]
exclude = ("error_messages", "additional_validators")


admin.site.register(models.Action, ActionModelAdmin)
admin.site.register(models.Validator, ValidatorModelAdmin)
admin.site.register(models.CustomErrorMessage, CustomErrorModelAdmin)
admin.site.register(models.FieldChoice, FieldChoiceModelAdmin)
admin.site.register(models.Form, FormAdmin)
admin.site.register(models.FormData, FormDataAdmin)
Expand Down
42 changes: 13 additions & 29 deletions formfactory/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,16 +41,21 @@ def __init__(self, *args, **kwargs):
field_type = getattr(forms, field.field_type)

additional_validators = []
if field.additional_validators:
additional_validators = [field.additional_validators]
for validator in field.additional_validators.all():
additional_validators.append(
validator.as_function
)

self.fields[field.slug] = field_type(
label=field.label,
initial=field.initial,
initial=field.initial or self.initial.get(field.slug),
required=field.required,
disabled=field.disabled,
help_text=field.help_text,
validators=additional_validators
validators=additional_validators,
error_messages=dict(
(m.key, m.value) for m in field.error_messages.all()
)
)

# Saves the field model pk to the form field to prevent the
Expand Down Expand Up @@ -109,18 +114,17 @@ def _html_output(self, normal_row, error_row, row_ender, help_text_html,
"""
# Errors that should be displayed above all fields.
top_errors = self.non_field_errors()

output, hidden_fields = [], []

for name, field in self.fields.items():
html_class_attr = ''
html_class_attr = ""
bf = self[name]
# Escape and cache in local variable.
bf_errors = self.error_class([conditional_escape(error) for error in bf.errors])
if bf.is_hidden:
if bf_errors:
top_errors.extend(
[_('(Hidden field %(name)s) %(error)s') % {'name': name, 'error': force_text(e)}
[_("(Hidden field %(name)s) %(error)s") % {"name": name, "error": force_text(e)}
for e in bf_errors])
hidden_fields.append(six.text_type(bf))

Expand Down Expand Up @@ -181,29 +185,9 @@ def _html_output(self, normal_row, error_row, row_ender, help_text_html,

# Insert any hidden fields in the last row.
if hidden_fields:
# Add the hidden fields outside of the fieldset grouping.
str_hidden = "".join(hidden_fields)
if output:
last_row = output[-1]
# Chop off the trailing row_ender (e.g. '</td></tr>') and
# insert the hidden fields.
if not last_row.endswith(row_ender):
# This can happen in the as_p() case (and possibly others
# that users write): if there are only top errors, we may
# not be able to conscript the last row for our purposes,
# so insert a new, empty row.
last_row = (normal_row % {
"errors": "", "label": "",
"field": "", "help_text": "",
"html_class_attr": html_class_attr,
"field_id": ""
})
output.append(last_row)
output[-1] = last_row[:-len(row_ender)] + str_hidden + \
row_ender
else:
# If there aren't any rows in the output, just append the
# hidden fields.
output.append(str_hidden)
output.append(str_hidden)
return mark_safe("\n".join(output))

def save(self, *args, **kwargs):
Expand Down
25 changes: 24 additions & 1 deletion formfactory/forms.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from django import forms
from django.utils.translation import ugettext_lazy as _

from formfactory import models

Expand Down Expand Up @@ -30,6 +31,27 @@ class Meta(object):
fields = ["action", "form", "order"]


class ValidatorAdminForm(forms.ModelForm):
class Meta(object):
model = models.Validator
fields = ["validator"]


class CustomErrorAdminForm(forms.ModelForm):
class Meta(object):
model = models.CustomErrorMessage
fields = ["key", "value"]


class CustomErrorInlineAdminForm(forms.ModelForm):
class Meta(object):
model = models.FormFieldErrorMessageProxy
fields = ["formfield", "customerrormessage"]
labels = {
"customerrormessage": _("Error message"),
}


class FormDataAdminForm(forms.ModelForm):
class Meta(object):
model = models.FormData
Expand Down Expand Up @@ -97,7 +119,8 @@ class Meta(object):
"title", "slug", "field_groups", "field_type", "widget", "label",
"initial", "max_length", "help_text", "placeholder", "required",
"disabled", "choices", "model_choices_content_type",
"model_choices_object_id", "additional_validators"
"model_choices_object_id", "additional_validators",
"error_messages"
]


Expand Down
31 changes: 31 additions & 0 deletions formfactory/migrations/0006_additional_validator_many_to_many.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.12 on 2017-03-03 09:13
from __future__ import unicode_literals

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('formfactory', '0005_added_enum_generic_relation'),
]

operations = [
migrations.CreateModel(
name='Validator',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('validator', models.CharField(max_length=128)),
],
),
migrations.RemoveField(
model_name='formfield',
name='additional_validators',
),
migrations.AddField(
model_name='formfield',
name='additional_validators',
field=models.ManyToManyField(to='formfactory.Validator'),
),
]
20 changes: 20 additions & 0 deletions formfactory/migrations/0007_additional_validators_can_be_blank.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.12 on 2017-03-07 12:33
from __future__ import unicode_literals

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('formfactory', '0006_additional_validator_many_to_many'),
]

operations = [
migrations.AlterField(
model_name='formfield',
name='additional_validators',
field=models.ManyToManyField(blank=True, to='formfactory.Validator'),
),
]
28 changes: 28 additions & 0 deletions formfactory/migrations/0008_custom_field_error_messages.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.12 on 2017-03-09 08:59
from __future__ import unicode_literals

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('formfactory', '0007_additional_validators_can_be_blank'),
]

operations = [
migrations.CreateModel(
name='CustomErrorMessage',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('key', models.CharField(choices=[], max_length=128)),
('value', models.CharField(max_length=256)),
],
),
migrations.AddField(
model_name='formfield',
name='error_messages',
field=models.ManyToManyField(blank=True, to='formfactory.CustomErrorMessage'),
),
]
Loading

0 comments on commit 12ddd4e

Please sign in to comment.