Compare commits
4 Commits
master
...
features/f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
757cf3d869 | ||
|
|
5ea0b02964 | ||
|
|
3346a88f81 | ||
|
|
56c8e2741b |
@@ -271,6 +271,8 @@
|
|||||||
* Add the checkdependencies command.
|
* Add the checkdependencies command.
|
||||||
* Add comment and make file target to generate all requirement
|
* Add comment and make file target to generate all requirement
|
||||||
files.
|
files.
|
||||||
|
* Place deletion policies units before periods for clarity.
|
||||||
|
|
||||||
|
|
||||||
3.1.11 (2019-04-XX)
|
3.1.11 (2019-04-XX)
|
||||||
===================
|
===================
|
||||||
|
|||||||
@@ -1445,7 +1445,7 @@ sudo -u mayan \
|
|||||||
dialog --infobox "Preparing static files" 3 70
|
dialog --infobox "Preparing static files" 3 70
|
||||||
sudo -u mayan \
|
sudo -u mayan \
|
||||||
MAYAN_MEDIA_ROOT=$MAYAN_MEDIA_ROOT \
|
MAYAN_MEDIA_ROOT=$MAYAN_MEDIA_ROOT \
|
||||||
$MAYAN_BIN collectstatic --noinput > /dev/null
|
$MAYAN_BIN preparestatic --noinput > /dev/null
|
||||||
|
|
||||||
# Create supervisor file for gunicorn (frontend), 3 background workers, and the scheduler for periodic tasks
|
# Create supervisor file for gunicorn (frontend), 3 background workers, and the scheduler for periodic tasks
|
||||||
cat > /etc/supervisor/conf.d/mayan.conf <<EOF
|
cat > /etc/supervisor/conf.d/mayan.conf <<EOF
|
||||||
|
|||||||
@@ -161,7 +161,7 @@ priority = 998
|
|||||||
EOF
|
EOF
|
||||||
|
|
||||||
echo -e "\n -> Collecting the static files \n"
|
echo -e "\n -> Collecting the static files \n"
|
||||||
mayan-edms.py collectstatic --noinput
|
mayan-edms.py preparestatic --noinput
|
||||||
|
|
||||||
echo -e "\n -> Making the installation directory readable and writable by the webserver user \n"
|
echo -e "\n -> Making the installation directory readable and writable by the webserver user \n"
|
||||||
chown www-data:www-data ${INSTALLATION_DIRECTORY} -R
|
chown www-data:www-data ${INSTALLATION_DIRECTORY} -R
|
||||||
|
|||||||
@@ -705,6 +705,7 @@ Other changes
|
|||||||
Change color scheme to match rest of project. Increase size of data points.
|
Change color scheme to match rest of project. Increase size of data points.
|
||||||
Improve responsive settings. Redirect to the current view after queueing.
|
Improve responsive settings. Redirect to the current view after queueing.
|
||||||
- Split document type retention policies into it own view.
|
- Split document type retention policies into it own view.
|
||||||
|
- Place deletion policies units before periods for clarity.
|
||||||
|
|
||||||
|
|
||||||
Removals
|
Removals
|
||||||
@@ -829,6 +830,10 @@ Backward incompatible changes
|
|||||||
|
|
||||||
ImportError: No module named ocr.backends.pyocr
|
ImportError: No module named ocr.backends.pyocr
|
||||||
|
|
||||||
|
- To collect and compress the static media files, use the new ``preparestatic``
|
||||||
|
command instead of the traditional ``collectstatic``. Both work the same
|
||||||
|
way, but ``preparestatic`` has a default backlist to avoid collecting
|
||||||
|
test files.
|
||||||
|
|
||||||
Bugs fixed or issues closed
|
Bugs fixed or issues closed
|
||||||
---------------------------
|
---------------------------
|
||||||
|
|||||||
@@ -148,7 +148,7 @@ Django's development server doesn't serve static files unless the DEBUG option
|
|||||||
is set to True, this mode of operation should only be used for development or
|
is set to True, this mode of operation should only be used for development or
|
||||||
testing. For production deployments the management command::
|
testing. For production deployments the management command::
|
||||||
|
|
||||||
$ mayan-edms.py collectstatic
|
$ mayan-edms.py preparestatic
|
||||||
|
|
||||||
should be used and the resulting static folder served from a webserver.
|
should be used and the resulting static folder served from a webserver.
|
||||||
For more information check the
|
For more information check the
|
||||||
|
|||||||
@@ -172,6 +172,22 @@ class DynamicFormMixin(object):
|
|||||||
kwargs.update(field_data.get('kwargs', {}))
|
kwargs.update(field_data.get('kwargs', {}))
|
||||||
self.fields[field_name] = field_class(**kwargs)
|
self.fields[field_name] = field_class(**kwargs)
|
||||||
|
|
||||||
|
def get_dynamic_values(self):
|
||||||
|
# Consolidate the dynamic fields into a single dictionary.
|
||||||
|
cleaned_data = super(DynamicFormMixin, self).clean()
|
||||||
|
result = {}
|
||||||
|
|
||||||
|
for field_name, field_data in self.schema['fields'].items():
|
||||||
|
result[field_name] = cleaned_data.pop(
|
||||||
|
field_name, field_data.get('default', None)
|
||||||
|
)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
def set_dynamic_values(self, values):
|
||||||
|
for key in self.schema['fields']:
|
||||||
|
self.fields[key].initial = values.get(key, self.fields[key].initial)
|
||||||
|
|
||||||
|
|
||||||
class DynamicForm(DynamicFormMixin, forms.Form):
|
class DynamicForm(DynamicFormMixin, forms.Form):
|
||||||
pass
|
pass
|
||||||
|
|||||||
@@ -111,8 +111,8 @@ class DocumentTypeDeleteView(SingleObjectDeleteView):
|
|||||||
|
|
||||||
class DocumentTypeDeletionPoliciesEditView(SingleObjectEditView):
|
class DocumentTypeDeletionPoliciesEditView(SingleObjectEditView):
|
||||||
fields = (
|
fields = (
|
||||||
'trash_time_period', 'trash_time_unit', 'delete_time_period',
|
'trash_time_unit', 'trash_time_period', 'delete_time_unit',
|
||||||
'delete_time_unit'
|
'delete_time_period'
|
||||||
)
|
)
|
||||||
model = DocumentType
|
model = DocumentType
|
||||||
object_permission = permission_document_type_edit
|
object_permission = permission_document_type_edit
|
||||||
|
|||||||
3
mayan/apps/forms/__init__.py
Normal file
3
mayan/apps/forms/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
default_app_config = 'mayan.apps.forms.apps.FormsApp'
|
||||||
28
mayan/apps/forms/admin.py
Normal file
28
mayan/apps/forms/admin.py
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.contrib import admin
|
||||||
|
|
||||||
|
from .models import FieldChoice, FormInstance, FormTemplate, FormTemplateField
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(FieldChoice)
|
||||||
|
class FieldChoiceAdmin(admin.ModelAdmin):
|
||||||
|
list_display = ('label', 'dotted_path')
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(FormInstance)
|
||||||
|
class FormInstanceAdmin(admin.ModelAdmin):
|
||||||
|
list_display = ('form_template', 'data')
|
||||||
|
|
||||||
|
|
||||||
|
class FormTemplateFieldInline(admin.StackedInline):
|
||||||
|
model = FormTemplateField
|
||||||
|
extra = 1
|
||||||
|
classes = ('collapse-open',)
|
||||||
|
allow_add = True
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(FormTemplate)
|
||||||
|
class FormTemplateAdmin(admin.ModelAdmin):
|
||||||
|
inlines = (FormTemplateFieldInline,)
|
||||||
|
list_display = ('name', 'label', 'enabled')
|
||||||
33
mayan/apps/forms/apps.py
Normal file
33
mayan/apps/forms/apps.py
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.apps import apps
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
from mayan.apps.acls.classes import ModelPermission
|
||||||
|
from mayan.apps.acls.links import link_acl_list
|
||||||
|
from mayan.apps.acls.permissions import permission_acl_edit, permission_acl_view
|
||||||
|
from mayan.apps.common.apps import MayanAppConfig
|
||||||
|
from mayan.apps.common.html_widgets import TwoStateWidget
|
||||||
|
from mayan.apps.common.menus import (
|
||||||
|
menu_list_facet, menu_multi_item, menu_object, menu_secondary, menu_setup,
|
||||||
|
menu_tools
|
||||||
|
)
|
||||||
|
from mayan.apps.events.classes import ModelEventType
|
||||||
|
from mayan.apps.events.links import (
|
||||||
|
link_events_for_object, link_object_event_types_user_subcriptions_list
|
||||||
|
)
|
||||||
|
from mayan.apps.navigation.classes import SourceColumn
|
||||||
|
|
||||||
|
from .classes import FieldClass
|
||||||
|
|
||||||
|
|
||||||
|
class FormsApp(MayanAppConfig):
|
||||||
|
app_namespace = 'forms'
|
||||||
|
app_url = 'forms'
|
||||||
|
#has_tests = True
|
||||||
|
name = 'mayan.apps.forms'
|
||||||
|
verbose_name = _('Forms')
|
||||||
|
|
||||||
|
def ready(self):
|
||||||
|
super(FormsApp, self).ready()
|
||||||
|
FieldClass.initialize()
|
||||||
64
mayan/apps/forms/classes.py
Normal file
64
mayan/apps/forms/classes.py
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from importlib import import_module
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from django.apps import apps
|
||||||
|
from django.utils import six
|
||||||
|
from django.utils.encoding import force_text
|
||||||
|
from django.utils.module_loading import import_string
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class FieldClass(object):
|
||||||
|
_registry = {}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def initialize():
|
||||||
|
for app in apps.get_app_configs():
|
||||||
|
try:
|
||||||
|
import_module('{}.form_fields'.format(app.name))
|
||||||
|
except ImportError as exception:
|
||||||
|
if force_text(exception) not in ('No module named form_fields', 'No module named \'{}.form_fields\''.format(app.name)):
|
||||||
|
logger.error(
|
||||||
|
'Error importing %s queues.py file; %s', app.name,
|
||||||
|
exception
|
||||||
|
)
|
||||||
|
raise
|
||||||
|
|
||||||
|
FieldClass.update()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def all(cls):
|
||||||
|
return cls._registry.values()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def update(cls):
|
||||||
|
FieldChoice = apps.get_model(
|
||||||
|
app_label='forms', model_name='FieldChoice'
|
||||||
|
)
|
||||||
|
|
||||||
|
for field in cls.all():
|
||||||
|
FieldChoice.objects.update_or_create(
|
||||||
|
dotted_path=field.dotted_path, defaults={
|
||||||
|
'label': field.label
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
def __init__(self, dotted_path, label):
|
||||||
|
self.dotted_path = dotted_path
|
||||||
|
self.label = label
|
||||||
|
|
||||||
|
self.__class__._registry[self.dotted_path] = self
|
||||||
|
|
||||||
|
def validate(self):
|
||||||
|
try:
|
||||||
|
import_string(dotted_path=self.dotted_path)
|
||||||
|
except Exception as exception:
|
||||||
|
logger.critical(
|
||||||
|
'Exception validating field entry %s; %s', self.label, exception,
|
||||||
|
exc_info=True
|
||||||
|
)
|
||||||
|
raise
|
||||||
8
mayan/apps/forms/form_fields.py
Normal file
8
mayan/apps/forms/form_fields.py
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
from .classes import FieldClass
|
||||||
|
|
||||||
|
|
||||||
|
FieldClass(dotted_path='django.forms.CharField', label=_('Character field'))
|
||||||
82
mayan/apps/forms/forms.py
Normal file
82
mayan/apps/forms/forms.py
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import json
|
||||||
|
|
||||||
|
from django import forms
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
from mayan.apps.acls.models import AccessControlList
|
||||||
|
from mayan.apps.common.forms import DynamicModelForm
|
||||||
|
#from mayan.apps.common.settings import setting_project_title, setting_project_url
|
||||||
|
|
||||||
|
#from .classes import MailerBackend
|
||||||
|
#from .models import UserMailer
|
||||||
|
#from .permissions import permission_user_mailer_use
|
||||||
|
#from .settings import (
|
||||||
|
# setting_document_body_template, setting_document_subject_template,
|
||||||
|
# setting_link_body_template, setting_link_subject_template
|
||||||
|
#)
|
||||||
|
#from .validators import validate_email_multiple
|
||||||
|
|
||||||
|
from .models import FormInstance
|
||||||
|
|
||||||
|
|
||||||
|
class FormInstanceDynamicForm(DynamicModelForm):
|
||||||
|
class Meta:
|
||||||
|
#fields = ('label', 'default', 'enabled', 'backend_data')
|
||||||
|
fields = ('data',)
|
||||||
|
model = FormInstance
|
||||||
|
widgets = {'data': forms.widgets.HiddenInput}
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
result = super(FormInstanceDynamicForm, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
if self.instance:
|
||||||
|
#print("!!!!!!!!!!! instace data", self.instance.get_data())
|
||||||
|
##print("!!!!!!!!!!! instace data", type(self.instance.get_data()))
|
||||||
|
print("!!!!!!!!!!! instace data", self.instance.data)
|
||||||
|
print("!!!!!!!!!!! instace data", type(self.instance.data))
|
||||||
|
self.set_dynamic_values(values=self.instance.data)
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
instance_data = self.instance.get_data()
|
||||||
|
|
||||||
|
if instance_data:
|
||||||
|
#print("@@@@@@@@@!!!!!!!!!!!! self.instance.data", self.instance.data)
|
||||||
|
#print("@@@@@@@@@!!!!!!!!!!!! data", data)
|
||||||
|
#print("@@@@@@@@@!!!!!!!!!!!! type: data", type(data))
|
||||||
|
#print("@@@@@@@@@!!!!!!!!!!!! self.fields", self.fields)
|
||||||
|
#print("@@@@@@@@@!!!!!!!!!!!! self.fields", self.fields.keys())
|
||||||
|
for key in self.instance.form_template.get_fields_dictionary():
|
||||||
|
#print("@@@@@@@@@@@key", key)
|
||||||
|
#print("@@@@@@@@@@@key", type(data))
|
||||||
|
#print("@@@@@@@@@@@key", data[key])
|
||||||
|
self.fields[key].initial = instance_data[key]
|
||||||
|
|
||||||
|
return result
|
||||||
|
"""
|
||||||
|
|
||||||
|
def clean(self):
|
||||||
|
cleaned_data = super(FormInstanceDynamicForm, self).clean()
|
||||||
|
cleaned_data['data'] = json.dumps(self.get_dynamic_values())
|
||||||
|
return cleaned_data
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
cleaned_data = super(FormInstanceDynamicForm, self).clean()
|
||||||
|
|
||||||
|
# Consolidate the dynamic fields into a single JSON field called
|
||||||
|
# 'backend_data'.
|
||||||
|
form_instance_data = {}
|
||||||
|
|
||||||
|
for field_name, field_data in self.schema['fields'].items():
|
||||||
|
form_instance_data[field_name] = cleaned_data.pop(
|
||||||
|
field_name, field_data.get('default', None)
|
||||||
|
)
|
||||||
|
|
||||||
|
print("!!!!!!!!!!!!!!!!!! form_instance_data", form_instance_data)
|
||||||
|
#cleaned_data['data'] = json.dumps(form_instance_data)
|
||||||
|
cleaned_data['data'] = form_instance_data
|
||||||
|
return cleaned_data
|
||||||
|
"""
|
||||||
61
mayan/apps/forms/migrations/0001_initial.py
Normal file
61
mayan/apps/forms/migrations/0001_initial.py
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.11.20 on 2019-05-22 07:27
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='FieldChoice',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('label', models.CharField(max_length=128, verbose_name='Label')),
|
||||||
|
('dotted_path', models.CharField(max_length=128, verbose_name='Dotted path')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Field choice',
|
||||||
|
'verbose_name_plural': 'Field choices',
|
||||||
|
'ordering': ('label',),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='FormTemplate',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.CharField(max_length=32, verbose_name='Name')),
|
||||||
|
('label', models.CharField(max_length=128, verbose_name='Label')),
|
||||||
|
('enabled', models.BooleanField(default=True, verbose_name='Enabled')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Form template',
|
||||||
|
'verbose_name_plural': 'Form templates',
|
||||||
|
'ordering': ('label',),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='FormTemplateField',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.CharField(max_length=128, verbose_name='Name')),
|
||||||
|
('arguments', models.TextField(blank=True, verbose_name='Arguments')),
|
||||||
|
('widget', models.CharField(blank=True, max_length=128, verbose_name='Widget')),
|
||||||
|
('widget_arguments', models.CharField(blank=True, max_length=128, verbose_name='Widget arguments')),
|
||||||
|
('enabled', models.BooleanField(default=True, verbose_name='Enabled')),
|
||||||
|
('choice', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='forms', to='forms.FieldChoice', verbose_name='Choice')),
|
||||||
|
('form_template', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='fields', to='forms.FormTemplate', verbose_name='Form template field')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Form template field',
|
||||||
|
'verbose_name_plural': 'Form template fields',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
23
mayan/apps/forms/migrations/0002_forminstance.py
Normal file
23
mayan/apps/forms/migrations/0002_forminstance.py
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.11.20 on 2019-05-22 07:32
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('forms', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='FormInstance',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('form_template', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='instances', to='forms.FormTemplate', verbose_name='Form template field')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
||||||
0
mayan/apps/forms/migrations/__init__.py
Normal file
0
mayan/apps/forms/migrations/__init__.py
Normal file
121
mayan/apps/forms/models.py
Normal file
121
mayan/apps/forms/models.py
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import json
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from django.core import mail
|
||||||
|
from django.db import models, transaction
|
||||||
|
from django.template import Context, Template
|
||||||
|
from django.utils.encoding import force_text, python_2_unicode_compatible
|
||||||
|
from django.utils.html import strip_tags
|
||||||
|
from django.utils.module_loading import import_string
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
|
class FieldChoice(models.Model):
|
||||||
|
label = models.CharField(max_length=128, verbose_name=_('Label'))
|
||||||
|
dotted_path = models.CharField(
|
||||||
|
max_length=128, verbose_name=_('Dotted path')
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
ordering = ('label',)
|
||||||
|
verbose_name = _('Field choice')
|
||||||
|
verbose_name_plural = _('Field choices')
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.label
|
||||||
|
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
|
class FormTemplate(models.Model):
|
||||||
|
name = models.CharField(max_length=32, verbose_name=_('Name'))
|
||||||
|
label = models.CharField(max_length=128, verbose_name=_('Label'))
|
||||||
|
enabled = models.BooleanField(default=True, verbose_name=_('Enabled'))
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
ordering = ('label',)
|
||||||
|
verbose_name = _('Form template')
|
||||||
|
verbose_name_plural = _('Form templates')
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.label
|
||||||
|
|
||||||
|
def get_fields_dictionary(self):
|
||||||
|
result = {}
|
||||||
|
|
||||||
|
for field in self.fields.all():
|
||||||
|
result[field.name] = {
|
||||||
|
'label': field.get_arguments().get('label', self.name),
|
||||||
|
'class': field.choice.dotted_path,
|
||||||
|
'kwargs': field.get_arguments(),
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
class FormTemplateField(models.Model):
|
||||||
|
form_template = models.ForeignKey(
|
||||||
|
on_delete=models.CASCADE, related_name='fields', to=FormTemplate,
|
||||||
|
verbose_name=_('Form template field')
|
||||||
|
)
|
||||||
|
name = models.CharField(
|
||||||
|
max_length=128, verbose_name=_('Name')
|
||||||
|
)
|
||||||
|
choice = models.ForeignKey(
|
||||||
|
on_delete=models.CASCADE, related_name='forms', to=FieldChoice,
|
||||||
|
verbose_name=_('Choice')
|
||||||
|
)
|
||||||
|
arguments = models.TextField(
|
||||||
|
blank=True, verbose_name=_('Arguments')
|
||||||
|
)
|
||||||
|
widget = models.CharField(
|
||||||
|
blank=True, max_length=128, verbose_name=_('Widget')
|
||||||
|
)
|
||||||
|
widget_arguments = models.CharField(
|
||||||
|
blank=True, max_length=128, verbose_name=_('Widget arguments')
|
||||||
|
)
|
||||||
|
enabled = models.BooleanField(default=True, verbose_name=_('Enabled'))
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = _('Form template field')
|
||||||
|
verbose_name_plural = _('Form template fields')
|
||||||
|
|
||||||
|
def get_arguments(self):
|
||||||
|
return json.loads(self.arguments or '{}')
|
||||||
|
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
|
class FormInstance(models.Model):
|
||||||
|
form_template = models.ForeignKey(
|
||||||
|
on_delete=models.CASCADE, related_name='instances', to=FormTemplate,
|
||||||
|
verbose_name=_('Form template field')
|
||||||
|
)
|
||||||
|
data = models.TextField(
|
||||||
|
blank=True, verbose_name=_('Data')
|
||||||
|
)
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(FormInstance, self).__init__(*args, **kwargs)
|
||||||
|
self.deserialize_data()
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return force_text(self.form_template)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = _('Form instance')
|
||||||
|
verbose_name_plural = _('Form instances')
|
||||||
|
|
||||||
|
def deserialize_data(self):
|
||||||
|
self.data = json.loads(self.data or '{}')
|
||||||
|
|
||||||
|
def serialize_data(self):
|
||||||
|
self.data = json.dumps(self.data or {})
|
||||||
|
|
||||||
|
def save(self, *args, **kwargs):
|
||||||
|
#if not self.pk:
|
||||||
|
self.serialize_data()
|
||||||
|
return super(FormInstance, self).save(*args, **kwargs)
|
||||||
16
mayan/apps/forms/urls.py
Normal file
16
mayan/apps/forms/urls.py
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.conf.urls import url
|
||||||
|
|
||||||
|
from .views import FormInstanceCreateView, FormInstanceEditView
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
url(
|
||||||
|
regex=r'^templates/(?P<pk>\d+)/instances/create/$',
|
||||||
|
view=FormInstanceCreateView.as_view(), name='form_instance_create'
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
regex=r'^instances/(?P<pk>\d+)/edit/$',
|
||||||
|
view=FormInstanceEditView.as_view(), name='form_instance_edit'
|
||||||
|
),
|
||||||
|
]
|
||||||
94
mayan/apps/forms/views.py
Normal file
94
mayan/apps/forms/views.py
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
from __future__ import absolute_import, unicode_literals
|
||||||
|
|
||||||
|
from django.http import Http404, HttpResponseRedirect
|
||||||
|
from django.shortcuts import get_object_or_404
|
||||||
|
from django.template import RequestContext
|
||||||
|
from django.urls import reverse, reverse_lazy
|
||||||
|
from django.utils.translation import ungettext, ugettext_lazy as _
|
||||||
|
|
||||||
|
from mayan.apps.acls.models import AccessControlList
|
||||||
|
from mayan.apps.common.generics import (
|
||||||
|
DynamicFormView, FormView, MultipleObjectFormActionView, SingleObjectDeleteView,
|
||||||
|
SingleObjectDynamicFormCreateView, SingleObjectDynamicFormEditView,
|
||||||
|
SingleObjectListView
|
||||||
|
)
|
||||||
|
from mayan.apps.common.forms import DynamicForm, DynamicModelForm
|
||||||
|
from mayan.apps.common.mixins import ExternalObjectMixin
|
||||||
|
|
||||||
|
from .models import FormTemplate, FormInstance
|
||||||
|
|
||||||
|
"""
|
||||||
|
class FormInstanceCreateView(ExternalObjectMixin, DynamicFormView):
|
||||||
|
external_object_class = FormTemplate
|
||||||
|
external_object_pk_url_kwarg = 'pk'
|
||||||
|
form_class = DynamicForm
|
||||||
|
|
||||||
|
def get_form_schema(self):
|
||||||
|
result = {
|
||||||
|
'fields': self.external_object.get_fields_dictionary(),
|
||||||
|
'widgets': {}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
from .forms import FormInstanceDynamicForm
|
||||||
|
|
||||||
|
class FormInstanceCreateView(ExternalObjectMixin, SingleObjectDynamicFormCreateView):
|
||||||
|
external_object_class = FormTemplate
|
||||||
|
external_object_pk_url_kwarg = 'pk'
|
||||||
|
form_class = FormInstanceDynamicForm
|
||||||
|
#post_action_redirect = reverse_lazy(viewname='mailer:user_mailer_list')
|
||||||
|
#view_permission = permission_user_mailer_create
|
||||||
|
|
||||||
|
#def get_backend(self):
|
||||||
|
# try:
|
||||||
|
# return MailerBackend.get(name=self.kwargs['class_path'])
|
||||||
|
# except KeyError:
|
||||||
|
# raise Http404(
|
||||||
|
# '{} class not found'.format(self.kwargs['class_path'])
|
||||||
|
# )
|
||||||
|
|
||||||
|
#def get_extra_context(self):
|
||||||
|
# return {
|
||||||
|
# 'title': _(
|
||||||
|
# 'Create a "%s" mailing profile'
|
||||||
|
# ) % self.get_backend().label,
|
||||||
|
# }
|
||||||
|
|
||||||
|
def get_form_schema(self):
|
||||||
|
result = {
|
||||||
|
'fields': self.external_object.get_fields_dictionary(),
|
||||||
|
'widgets': {}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
#def get_form_schema(self):
|
||||||
|
# backend = self.get_backend()
|
||||||
|
# result = {
|
||||||
|
# 'fields': backend.fields,
|
||||||
|
# 'widgets': getattr(backend, 'widgets', {})
|
||||||
|
# }
|
||||||
|
# if hasattr(backend, 'field_order'):
|
||||||
|
# result['field_order'] = backend.field_order
|
||||||
|
|
||||||
|
# return result
|
||||||
|
|
||||||
|
def get_instance_extra_data(self):
|
||||||
|
return {'form_template': self.external_object}
|
||||||
|
|
||||||
|
|
||||||
|
class FormInstanceEditView(SingleObjectDynamicFormEditView):
|
||||||
|
model = FormInstance
|
||||||
|
form_class = FormInstanceDynamicForm
|
||||||
|
|
||||||
|
def get_form_schema(self):
|
||||||
|
result = {
|
||||||
|
'fields': self.object.form_template.get_fields_dictionary(),
|
||||||
|
'widgets': {}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
@@ -118,6 +118,7 @@ INSTALLED_APPS = (
|
|||||||
'mayan.apps.document_states',
|
'mayan.apps.document_states',
|
||||||
'mayan.apps.documents',
|
'mayan.apps.documents',
|
||||||
'mayan.apps.file_metadata',
|
'mayan.apps.file_metadata',
|
||||||
|
'mayan.apps.forms',
|
||||||
'mayan.apps.linking',
|
'mayan.apps.linking',
|
||||||
'mayan.apps.mailer',
|
'mayan.apps.mailer',
|
||||||
'mayan.apps.mayan_statistics',
|
'mayan.apps.mayan_statistics',
|
||||||
|
|||||||
Reference in New Issue
Block a user